【实战教程】Spring Boot集成SkyWalking:轻松实现用户ID、URL和IP的自定义标签追踪

图片[1]-【实战教程】Spring Boot集成SkyWalking:轻松实现用户ID、URL和IP的自定义标签追踪

为什么需要自定义标签?

在微服务架构中,追踪用户请求的完整链路至关重要。SkyWalking作为一款优秀的APM工具,提供了基础的链路追踪功能,但在实际业务场景中,我们常常需要知道:

  • 是哪个用户发起的请求?
  • 请求的具体URL是什么?
  • 请求来自哪个IP地址

通过添加这些自定义标签,我们可以:

  1. 快速定位特定用户遇到的问题
  2. 分析不同接口的性能瓶颈
  3. 识别可能的异常访问来源

效果示意:


| SkyWalking追踪详情                                |
|--------------------------------------------------|
| 追踪ID: 123e4567-e89b-12d3-a456-426614174000    |
| 服务名: user-service                             |
| 操作名: /api/users/profile                       |
| 耗时: 230ms                                      |
|                                                  |
| 自定义标签:                                       |
| ✓ userid: 10086                                  |
| ✓ url: https://example.com/api/users/profile     |
| ✓ ip: 203.0.113.195                             |
|--------------------------------------------------|

实现方案一:使用过滤器(Filter)

过滤器是实现这一功能的最简单方式,它能拦截所有的HTTP请求。


package com.example.config;

import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class SkyWalkingTagFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        // 获取用户ID(根据你的认证机制实现)
        String userId = getUserIdFromRequest(request);
        if (userId != null) {
            ActiveSpan.tag("userid", userId);
        }
        
        // 添加URL标签
        String url = request.getRequestURL().toString();
        ActiveSpan.tag("url", url);
        
        // 添加IP标签
        String clientIp = getClientIp(request);
        ActiveSpan.tag("ip", clientIp);
        
        // 继续请求链
        filterChain.doFilter(request, response);
    }
    
    private String getUserIdFromRequest(HttpServletRequest request) {
        // 根据你的认证机制实现
        // 例如,如果使用Spring Security:
        // Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        // return auth != null && auth.isAuthenticated() ? auth.getName() : "anonymous";
        
        // 或者从会话属性中获取:
        return (String) request.getSession().getAttribute("userId");
    }
    
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

过滤器工作流程:

客户端请求 → [SkyWalkingTagFilter] → 添加自定义标签(userid/url/ip) → 继续请求处理 → 返回响应

实现方案二:使用拦截器(Interceptor)

如果你更喜欢Spring MVC的拦截器机制,这里提供另一种实现方式:


package com.example.config;

import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class SkyWalkingTagInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获取用户ID
        String userId = getUserIdFromRequest(request);
        if (userId != null) {
            ActiveSpan.tag("userid", userId);
        }
        
        // 添加URL标签
        String url = request.getRequestURL().toString();
        ActiveSpan.tag("url", url);
        
        // 添加IP标签
        String clientIp = getClientIp(request);
        ActiveSpan.tag("ip", clientIp);
        
        return true;
    }
    
    private String getUserIdFromRequest(HttpServletRequest request) {
        // 根据你的认证机制实现
        return (String) request.getSession().getAttribute("userId");
    }
    
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

然后,需要注册这个拦截器:


package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private SkyWalkingTagInterceptor skyWalkingTagInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(skyWalkingTagInterceptor);
    }
}

添加必要的依赖

确保在你的pom.xml中添加SkyWalking的相关依赖:


<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.8.0</version>
</dependency>

依赖配置说明:


项目依赖结构:
└── pom.xml
    └── dependencies
        ├── spring-boot-starter-web
        ├── spring-boot-starter-aop
        └── apm-toolkit-trace (SkyWalking工具包)

实现效果

成功配置后,你将在SkyWalking UI中看到每个追踪都带有自定义标签:

追踪详情示例:


+-----------------------------------------------+
|                追踪详情                        |
+-----------------------------------------------+
| 追踪ID: 7a6cc3df-8f9a-4b9c-a1b2-1a2b3c4d5e6f |
| 开始时间: 2023-05-20 14:30:45.123             |
| 持续时间: 157ms                               |
+-----------------------------------------------+
| 标签:                                         |
|  ├─ userid: user_123456                      |
|  ├─ url: http://api.example.com/users/info   |
|  └─ ip: 192.168.1.100                        |
+-----------------------------------------------+
| 组件:                                         |
|  ├─ HTTP GET                                 |
|  ├─ Controller.getUserInfo                   |
|  └─ Database Query                           |
+-----------------------------------------------+

注意事项

  1. getUserIdFromRequest方法需要根据你的认证机制进行实现
  2. 确保SkyWalking agent已正确配置并与你的应用一起启动
  3. 过滤器和拦截器两种方案选择一种即可,根据你的项目结构选择更合适的方式
  4. IP提取逻辑处理了各种代理头信息,以获取真实的客户端IP

总结

通过简单的几步配置,我们成功地为SkyWalking追踪添加了用户ID、URL和IP这三个关键标签,大大增强了应用监控的能力。这些自定义标签不仅可以帮助我们更快地定位问题,还能为业务分析提供有价值的数据支持。

你还可以根据业务需求,添加更多自定义标签,例如设备信息、操作类型等,进一步丰富你的追踪数据。

实现架构图:

希望本文对你有所帮助,让你的微服务监控更上一层楼!

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享