Skip to content

如何实现手工埋点和日志监控

HaojunRen edited this page May 31, 2024 · 12 revisions

自定义埋点调用链监控

① 自定义注入Header,实现StrategyHeadersInjector,允许同时注入多个,每个类里允许多个Header

public class MyStrategyHeadersInjector implements StrategyHeadersInjector {
    @Override
    public List<HeadersInjectorEntity> getHeadersInjectorEntityList() {
        return Arrays.asList(
                new HeadersInjectorEntity(HeadersInjectorType.TRANSMISSION, Arrays.asList("test1")),
                new HeadersInjectorEntity(HeadersInjectorType.TRACER, Arrays.asList("test2")),
                new HeadersInjectorEntity(HeadersInjectorType.ALL, Arrays.asList("test3")));
    }
}

参数含义

  • HeadersInjectorType.TRANSMISSION表示作用于传递,上面的代码表示对名称为“test1”的Header将自动传递到下游服务
  • HeadersInjectorType.TRACER表示作用于调用链,上面的代码表示对名称为“test2”的Header将自动输出埋点到调用链和告警
  • HeadersInjectorType.ALL表示同时作用于上述量项,不需要一一设定

在配置类里@Bean方式进行Header注入类创建

@Bean
public StrategyHeadersInjector strategyHeadersInjector() {
    return new MyStrategyHeadersInjector();
}

② 自定义调用链上下文参数输出到调用链,继承DefaultStrategyTracerAdapter

// 自定义调用链上下文参数的创建
// 对于getTraceId和getSpanId方法,在OpenTracing等调用链中间件引入的情况下,由调用链中间件决定,在这里定义不会起作用;在OpenTracing等调用链中间件未引入的情况下,在这里定义才有效,下面代码中表示从Http Header中获取,并全链路传递
// 对于getCustomizationMap方法,表示输出到调用链中的定制化业务参数,可以同时输出到日志和OpenTracing等调用链中间件,下面代码中表示从Http Header中获取,并全链路传递
public class MyStrategyTracerAdapter extends DefaultStrategyTracerAdapter {
    @Override
    public String getTraceId() {
        return StringUtils.isNotEmpty(strategyContextHolder.getHeader(DiscoveryConstant.TRACE_ID)) ? strategyContextHolder.getHeader(DiscoveryConstant.TRACE_ID) : StringUtils.EMPTY;
    }

    @Override
    public String getSpanId() {
        return StringUtils.isNotEmpty(strategyContextHolder.getHeader(DiscoveryConstant.SPAN_ID)) ? strategyContextHolder.getHeader(DiscoveryConstant.SPAN_ID) : StringUtils.EMPTY;
    }

    @Override
    public Map<String, String> getCustomizationMap() {
        Map<String, String> customizationMap = new LinkedHashMap<String, String>();
        customizationMap.put("mobile", StringUtils.isNotEmpty(strategyContextHolder.getHeader("mobile")) ? strategyContextHolder.getHeader("mobile") : StringUtils.EMPTY);
        customizationMap.put("user", StringUtils.isNotEmpty(strategyContextHolder.getHeader("user")) ? strategyContextHolder.getHeader("user") : StringUtils.EMPTY);

        return customizationMap;
    }
}

在配置类里@Bean方式进行调用链类创建,覆盖框架内置的调用链适配器

@Bean
public StrategyTracerAdapter strategyTracerAdapter() {
    return new MyStrategyTracerAdapter();
}

注意事项

“自定义注入Header输出到调用链”和“自定义调用链上下文参数输出到调用链”的区别

  • 前者只适用于Header埋点,后者不仅适用于Header埋点,也适用于其它参数埋点
  • 前者一般适用于中间件再次封装的使用场景,允许多个,后者一般适用于最终业务的使用场景,只允许一个

③ 自定义类方法上入参和出参输出到调用链,实现ServiceStrategyMonitorAdapter,允许多个

// 自定义类方法上入参和出参输出到调用链
// parameterMap格式:
// key为入参名
// value为入参值
public class MyServiceStrategyMonitorAdapter implements ServiceStrategyMonitorAdapter {
    @Override
    public Map<String, String> getCustomizationMap(ServiceStrategyMonitorInterceptor interceptor, MethodInvocation invocation, Map<String, Object> parameterMap, Object returnValue) {
        Map<String, String> customizationMap = new LinkedHashMap<String, String>();
        customizationMap.put(DiscoveryConstant.PARAMETER, parameterMap.toString());
        customizationMap.put(DiscoveryConstant.RETURN, returnValue != null ? returnValue.toString() : null);

        return customizationMap;
    }
}

在配置类里@Bean方式进行监控适配类创建

@Bean
public ServiceStrategyMonitorAdapter serviceStrategyMonitorAdapter() {
    return new MyServiceStrategyMonitorAdapter();
}

④ 自定义方法输出到调用链,通过在带有@RestController或者@ServiceStrategy注解的类的方法头部上增加如下注解,即忽略该方法埋点输出、日志输出、告警输出

@ServiceMonitorIgnore

⑤ 业务方法上获取TraceId和SpanId

public class MyClass {
    @Autowired
    private StrategyMonitorContext strategyMonitorContext;

    public void doXXX() {
        String traceId = strategyMonitorContext.getTraceId();
        String spanId = strategyMonitorContext.getSpanId();
        ...
    }
}

对于全链路监控功能的开启和关闭,需要通过如下开关做控制

# 启动和关闭监控,一旦关闭,调用链和日志输出都将关闭。缺失则默认为false
spring.application.strategy.monitor.enabled=true
# 启动和关闭告警,一旦关闭,蓝绿灰度上下文输出都将关闭。缺失则默认为false
spring.application.strategy.alarm.enabled=true
# 启动和关闭日志输出。缺失则默认为false
spring.application.strategy.logger.enabled=true
# 日志输出中,是否显示MDC前面的Key。缺失则默认为true
spring.application.strategy.logger.mdc.key.shown=true
# 启动和关闭Debug日志打印,注意:每调用一次都会打印一次,会对性能有所影响,建议压测环境和生产环境关闭。缺失则默认为false
spring.application.strategy.logger.debug.enabled=true
# 启动和关闭调用链输出。缺失则默认为false
spring.application.strategy.tracer.enabled=true
# 启动和关闭调用链的蓝绿灰度信息以独立的Span节点输出,如果关闭,则蓝绿灰度信息输出到原生的Span节点中(SkyWalking不支持原生模式)。缺失则默认为true
spring.application.strategy.tracer.separate.span.enabled=true
# 启动和关闭调用链的蓝绿灰度规则策略信息输出。缺失则默认为true
spring.application.strategy.tracer.rule.output.enabled=true
# 启动和关闭调用链的异常信息是否以详细格式输出。缺失则默认为false
spring.application.strategy.tracer.exception.detail.output.enabled=true
# 启动和关闭类方法上入参和出参输出到调用链。缺失则默认为false
spring.application.strategy.tracer.method.context.output.enabled=true
# 显示在调用链界面上蓝绿灰度Span的名称,建议改成具有公司特色的框架产品名称。缺失则默认为NEPXION
spring.application.strategy.tracer.span.value=NEPXION
# 显示在调用链界面上蓝绿灰度Span Tag的插件名称,建议改成具有公司特色的框架产品的描述。缺失则默认为Nepxion Discovery
spring.application.strategy.tracer.span.tag.plugin.value=Nepxion Discovery
# 启动和关闭Sentinel调用链上规则在Span上的输出。缺失则默认为true
spring.application.strategy.tracer.sentinel.rule.output.enabled=true
# 启动和关闭Sentinel调用链上方法入参在Span上的输出。缺失则默认为false
spring.application.strategy.tracer.sentinel.args.output.enabled=true

自定义日志调用链监控

蓝绿灰度埋点日志,通过MDC的%X{n-d-service-xyz}方式输出,目前支持11个参数,使用者可以根据实际使用场景进行裁剪,具体参考如下logback.xml配置

<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<configuration scan="true" scanPeriod="10 seconds">
    <!-- Simple file output -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- Encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%15.15t] %X{trace-id} %X{span-id} %X{n-d-service-group} %X{n-d-service-type} %X{n-d-service-app-id} %X{n-d-service-id} %X{n-d-service-address} %X{n-d-service-version} %X{n-d-service-region} %X{n-d-service-env} %X{n-d-service-zone} %-40.40logger{39} : %msg%n</pattern>
            <!-- <pattern>discovery %d{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread] %X{trace-id} %X{span-id} %X{n-d-service-group} %X{n-d-service-type} %X{n-d-service-app-id} %X{n-d-service-id} %X{n-d-service-address} %X{n-d-service-version} %X{n-d-service-region} %X{n-d-service-env} %X{n-d-service-zone} %logger{10} [%file:%line] - %msg%n</pattern> -->
            <charset>UTF-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>log/discovery-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>50MB</maxFileSize>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- Safely log to the same file from multiple JVMs. Degrades performance! -->
        <prudent>true</prudent>
    </appender>

    <appender name="FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>512</queueSize>
        <appender-ref ref="FILE" />
    </appender>

    <!-- Console output -->
    <conversionRule conversionWord="levelColor" converterClass="com.nepxion.discovery.common.logback.LevelColorConverter" />
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- Encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %levelColor(%5p) %magenta(${PID:- }) --- [%15.15t] %levelColor(%X{trace-id}) %levelColor(%X{span-id}) %levelColor(%X{n-d-service-group}) %levelColor(%X{n-d-service-type}) %levelColor(%X{n-d-service-app-id}) %levelColor(%X{n-d-service-id}) %levelColor(%X{n-d-service-address}) %levelColor(%X{n-d-service-version}) %levelColor(%X{n-d-service-region}) %levelColor(%X{n-d-service-env}) %levelColor(%X{n-d-service-zone}) %cyan(%-40.40logger{39}) : %msg%n</pattern>
        </encoder>
        <!-- Only log level WARN and above -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <!-- For loggers in the these namespaces, log at all levels. -->
    <logger name="pedestal" level="ALL" />
    <logger name="hammock-cafe" level="ALL" />
    <logger name="user" level="ALL" />

    <root level="INFO">
        <appender-ref ref="FILE_ASYNC" />
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

上述格式支持输出彩色日志,帮助分辨和定位失败的测试用例

  • 彩色日志配色方案,参考:https://logback.qos.ch/manual/layouts.html#coloring
    • 编辑器需要打开相关开启ANSI颜色渲染的开关
    • Windows终端默认不能显示ANSI颜色,需要在注册表HKEY_CURRENT_USER\Console中新建一个DWORD类型的值VirtualTerminalLevel,数值为1
  • 彩色Logo显示方案
    • 编辑器通过System.setProperty("nepxion.banner.shown.ansi.mode", "true")进行开启
    • 命令行通过java -jar -Dnepxion.banner.shown.ansi.mode=true进行开启




2017-2050 ©Nepxion Studio Apache License

           

Total visits

讲义篇

集成篇

概念篇

实践篇

功能篇

配置篇

扩展篇

测试篇

升级篇

贡献篇

Clone this wiki locally