OpenTelemetry系列 - 第2篇 Java端接入OpenTelemetry

这篇具有很好参考价值的文章主要介绍了OpenTelemetry系列 - 第2篇 Java端接入OpenTelemetry。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、架构说明

opentelemetry-java,云原生,Java & Spring,java,opentelemetry

  • 支持集成Agent 自动 插桩(Instrumentation) - 无需改变代码

  • 手动编码进行插桩 - 侵入代码

    • API - OTel接口定义,具体实现可通过依赖SDK或者Agent注入
      • annotations - OTel通用注解(如@WithSpan, @SpanAttr等)
      • semconv - OTel通用语义约定(如常用属性名称)
    • SDK - 具体OTel实现
    • Instumentation Libraries - 被注入OTel插桩的代码库
    • Resource Detector - 识别服务自身信息
  • Exporter - 导出器,将OTel相关数据导出到OTel Collector 或者 具体的监控后端

    • OTLP Exporter - OTel官方协议OTLP导出器,可导出数据到OTel Collector 或者其他接收OTLP协议的监控后端
    • vender exporters - 不同监控后端厂商的导出器,负责将OTel数据导出到不同的监控后端
      • Jaeger, Ziplin
      • Prometheus
      • Skywalking
  • OTel Collector - OTel官方的收集器(支持OTLP gRpc/http协议)

二、方式1 - 自动化

支持的编程语言:

  • .NET
  • Java
  • JavaScript
  • PHP
  • Python

2.1 opentelemetry-javaagent.jar(Java8+ )

Java自动插桩使用的Java agent JAR可以附加到任何Java 8+应用程序。它动态注入字节码来捕获来自许多流行库和框架的遥测。它可以用于在应用程序或服务的“边缘”捕获遥测数据,例如入站请求、出站HTTP调用、数据库调用等。
支持的库、框架等包括:

  • Spring: Boot, Web, MVC, WebFlux, Cloud Gateway, Batch, Scheduling, Data, MQ(JMS, Kafka, RabbitMq), Micrometer, RestTemplate
  • HTTP客户端工具: HttpClient 2.0+, OkHttp 2.2+, HttpURLConnection, Java Http Client
  • Web容器: Servlet 2.2+, Tomcat 7~10, Jetty 9 ~ 11, Undertow 1.4+, Netty 3.8+
  • 数据库连接: Hibernate 3.3+, JDBC, HIkariCP 3.0+, c3p0 0.9.2+, DBCP 2.0+, MongoDB Driver 3.1+, R2DBC 1.0+
  • RPC: Dubbo 2.7+, gRPC 1.6+
  • 消息队列: RabbitMQ 2.7+, Kafka 0.11+, RocketMq, Pulsar 2.8+, JMS
  • 缓存: Jedis 1.4+, Lettuce 4.0+, Redisson 3.0+
  • 日志: Log4j2 2.11+, Logback 1.0+
  • 搜索引擎: ES 5.0+
  • 云原生: AWS Lambda 1.0+, AWS SDK, Azure Core 1.14+, Kubernetes Client 7.0+
  • 其他: RxJava 1.0+, Reactor 3.1+, Guava, Quartz 2.0+, GraphQL 12.0+, Hystrix, …

具体支持情况可参见:
https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md

下载:opentelemetry-javaagent.jar

2.2 使用opentelemetry-javaagent.jar完成自动注入

方式1 - 使用java启动命令指定javaagment:

java -javaagent:path/to/opentelemetry-javaagent.jar 
	 -Dotel.service.name=your-service-name 
	 -jar myapp.jar

方式2 - 通过环境变量全局配置javaagent:

export JAVA_TOOL_OPTIONS="-javaagent:path/to/opentelemetry-javaagent.jar"
export OTEL_SERVICE_NAME="your-service-name"
java -jar myapp.jar

2.3 配置opentelemetry-javaagent.jar

方式1 - 通过Java系统属性:

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.service.name=your-service-name \
     -Dotel.traces.exporter=zipkin \
     -jar myapp.jar

方式2 - 通过环境变量:

OTEL_SERVICE_NAME=your-service-name \
OTEL_TRACES_EXPORTER=zipkin \
java -javaagent:path/to/opentelemetry-javaagent.jar \
     -jar myapp.jar

方式3 - 通过属性文件:

OTEL_JAVAAGENT_CONFIGURATION_FILE=path/to/properties/file.properties \
java -javaagent:path/to/opentelemetry-javaagent.jar \
     -jar myapp.jar

开启agent debug日志:

-Dotel.javaagent.debug=true

关于opentelemetry-javaagent.jar的更多配置可参见:
https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md
https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/

2.4 使用注解(@WithSpan, @SpanAttribute)

添加maven依赖:

<dependencies>
  <dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-instrumentation-annotations</artifactId>
    <version>1.31.0</version>
  </dependency>
</dependencies>

2.5.1 代码集成@WithSpan, @SpanAttribute
import io.opentelemetry.instrumentation.annotations.WithSpan;

public class MyClass {
  @WithSpan
  public void myMethod() {
      <...>
  }

   @WithSpan
   public void myMethod(@SpanAttribute("parameter1") String parameter1,
       @SpanAttribute("parameter2") long parameter2) {
       <...>
   }
}
2.5.2 禁用已标注@WithSpan的方法的自动注入:
-Dotel.instrumentation.opentelemetry-instrumentation-annotations.exclude-methods=
my.package.MyClass1[method1,method2];my.package.MyClass2[method3]
2.5.3 不修改代码的情况下启用@WithSpan

适用于无法修改源码的情况:

-Dotel.instrumentation.methods.include=
my.package.MyClass1[method1,method2];my.package.MyClass2[method3]
设置Agent日志级别

https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/#java-agent-logging-output

The agent’s logging output can be configured by setting the following property:

System property: otel.javaagent.logging
Description: The Java agent logging mode. The following 3 modes are supported:

  • simple: The agent will print out its logs using the standard error stream. Only INFO or higher logs will be printed. This is the default Java agent logging mode.
  • none: The agent will not log anything - not even its own version.
  • application: The agent will attempt to redirect its own logs to the instrumented application’s slf4j logger. This works the best for simple one-jar applications that do not use multiple classloaders; Spring Boot apps are supported as well. The Java agent output logs can be further configured using the instrumented application’s logging configuration (e.g. logback.xml or log4j2.xml). Make sure to test that this mode works for your application before running it in a production environment

三、方式2 -【推荐】自动化 & 手动API

应用端通过Agent注入opentelemetry-javaagent.jar,
应用端代码仅需集成OTel API接口依赖(无需集成SDK实现依赖),
额外需集成Logback OTel Appender相关依赖(若不需要可移除)。

注:
最推荐此种集成方式,
保留了Agent注入,减少了代码侵入,
仅当有自定义Traces/Metrics等需求时,依赖OTel Api完成指标等埋点,
即便不注入Agent,也不影响本地应用开发与运行,
在线上环境通过Docker镜像、K8S挂载等完成Agent注入。

3.1 maven依赖

<properties>
    <otel.version>1.32.0</otel.version>
    <otel.springboot.version>1.32.0-alpha</otel.springboot.version>
    <otel.logback.version>1.32.0-alpha</otel.logback.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!-- OTel基础依赖管理 -->
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-bom</artifactId>
            <version>${otel.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
		<!-- OTel注解 -->
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-instrumentation-annotations</artifactId>
            <version>${otel.version}</version>
        </dependency>


        <!-- OTel Logback -->
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-logback-appender-1.0</artifactId>
            <version>${otel.logback.version}</version>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-logback-mdc-1.0</artifactId>
            <version>${otel.logback.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
   <!-- OTel Api -->
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-api</artifactId>
    </dependency>

    <!-- OTel注解 -->
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-instrumentation-annotations</artifactId>
    </dependency>

    <!-- OTel Logback -->
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-logback-appender-1.0</artifactId>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-logback-mdc-1.0</artifactId>
    </dependency>
</dependencies>

3.2 Java启动命令注入OTel Agent

启动命令注入及配置opentelemetry-javaagent.jar:

java 
-javaagent:D:/programs/Java/OTel/opentelemetry-javaagent.jar
# 导出traces为控制台日志打印
-Dotel.traces.exporter=logging
# 导出metrics为控制台日志打印
-Dotel.metrics.exporter=logging
# 禁用log日志导出(若使用logging则控制台会出现日志框架如logback打印一次,OTel logging再打印一次,比较混乱,故暂且禁用)
-Dotel.logs.exporter=none
-jar myapp.jar

如下为导出traces、metrics、logs均到OTLP Collector的相关配置:

java 
-javaagent:D:/programs/Java/OTel/opentelemetry-javaagent.jar
-Dotel.traces.exporter=otlp
-Dotel.metrics.exporter=otlp
-Dotel.logs.exporter=otlp
-Dotel.exporter.otlp.endpoint=http://localhost:4317
-jar myapp.jar

如下为导出traces到Jaeger的相关配置:

注:
此种方式已被弃用,目前最新版版本的Jaeger已经内嵌OTel Collector,
可直接通过OTLP协议接收数据。

java 
-javaagent:D:/programs/Java/OTel/opentelemetry-javaagent.jar
# 导出traces到Jaeger端(Jaeger后端需根据实际环境进行调整)
-Dotel.traces.exporter=jaeger
-Dotel.exporter.jaeger.endpoint=http://10.170.xx.xxx:xxx
-Dotel.exporter.jaeger.timeout=10000
# 导出metrics为控制台日志打印
-Dotel.metrics.exporter=logging
# 禁用log日志导出
-Dotel.logs.exporter=none
-jar myapp.jar

导出到Jaeger中的traces展示:
opentelemetry-java,云原生,Java &amp; Spring,java,opentelemetry

opentelemetry-java,云原生,Java &amp; Spring,java,opentelemetry

3.3 Exporter导出器

导出方式:

  • OTLP exporter
  • Logging exporter
  • Logging OTLP JSON exporter
  • Jaeger exporter
  • Zipkin exporter
  • Prometheus exporter

关于导出器的更多配置可参见:
https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#exporters

3.4 代码端集成自定义Traces和Metrics

OTel工具类:

/**
 * OpenTelemetry工具类
 *
 * @author luohq
 * @date 2023-11-20 10:01
 */
@Component
public class OTelUtils {

    private static final Logger log = LoggerFactory.getLogger(OTelUtils.class);

    /**
     * OTel实例
     */
    private static OpenTelemetry OTEL_INSTANCE;

    /**
     * 兼容OTel SpringBoot Starter自动注入
     *
     * @param openTelemetry SpringBoot OTel实例
     */
    @Autowired(required = false)
    public void setOpenTelemetry(OpenTelemetry openTelemetry) {
        OTelUtils.OTEL_INSTANCE = openTelemetry;
    }

    /**
     * 获取OTel实例
     *
     * @return OTel实例
     */
    public static OpenTelemetry openTelemetry() {
        //获取自动注入的OTel实例
        if (Objects.nonNull(OTEL_INSTANCE)) {
            return OTEL_INSTANCE;
        }
        //获取全局配置中的OTel实例(使用Agent注入)
        return GlobalOpenTelemetry.get();
    }
}

业务代码集成OTel:

//使用@WithSpan和@SpanAttribute生成Span
@WithSpan(value = "Manual::GoodsService::findGoodsPage")
@Override
public RespResult<GoodsVo> findGoodsPage(@SpanAttribute GoodsPageQueryDto goodsPageQueryDto) {
    /** 获取当前Span */
    Span curSpan = Span.current();
    curSpan.setAttribute("attr.custom", "luohq-test-svc");

    /** 自定义指标 */
    Meter meter = OTelUtils.openTelemetry().meterBuilder("GoodsService::findGoodsPage")
            .setInstrumentationVersion("v1.0")
            .build();
    //构建计数器
    LongCounter findCounter = meter.counterBuilder("findGoodsPage.count")
            .setDescription("FindGoodsPage Sum Count")
            .setUnit("1")
            .build();
    findCounter.add(1);


    /** 自定义Span */
    Tracer tracer = OTelUtils.openTelemetry().getTracer(GoodsMapper.class.getSimpleName());
    Span daoSpan = tracer.spanBuilder("Manual::GoodsMapper::findGoodsWithCNamePage").startSpan();
    daoSpan.setAttribute("attr.custom", "luohq-test-dao");
    try (Scope scope = daoSpan.makeCurrent()) {
        //原处理逻辑
        log.info("findGoodsPage param: {}", goodsPageQueryDto);
        IPage<GoodsVo> goodsPage = this.goodsMapper.findGoodsWithCNamePage(this.toPage(goodsPageQueryDto), goodsPageQueryDto);
        log.info("findGoodsPage result: {}", goodsPage);
        return RespResult.successRows(goodsPage.getTotal(), goodsPage.getRecords());
    } catch (Throwable throwable) {
        //设置Span状态
        daoSpan.setStatus(StatusCode.ERROR, "Something bad happened!");
        //记录异常堆栈
        daoSpan.recordException(throwable);
        return RespResult.failed();
    }finally {
        daoSpan.end();
    }
}

3.5 Logback集成OTel

如下日志配置需使用spring.profiles.active来激活对应的otel或者otel-mdc配置,
如果不需要可移除springProfile段落,直接在configuration下配置相应的日志配置即可,
其中otel、otel-mdc均会自动将日志框架Logback集成OTel并导出日志到相应后端(如默认导出到OTel Collector),
相较于otel,otel-mdc通过 MDC(Mapped Diagnostic Context, 映射调试上下文机制) 将trace_id、span_id、trace_flags添加到日志中。

具体logback-spring.xml配置:

<configuration scan="true" scanPeriod=" 5 seconds">
    <!-- 默认日志配置 -->
    <springProfile name="default">
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>
                    %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                </pattern>
            </encoder>
        </appender>
        <root level="INFO">
            <appender-ref ref="console"/>
        </root>
    </springProfile>

    <!-- OTel日志配置 -->
    <springProfile name="otel">
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>
                    %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                </pattern>
            </encoder>
        </appender>
        <appender name="OpenTelemetry"
                  class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
        </appender>

        <root level="INFO">
            <appender-ref ref="console"/>
            <appender-ref ref="OpenTelemetry"/>
        </root>
    </springProfile>

    <!-- OTel MDC日志配置 -->
    <springProfile name="otel-mdc">
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <!--
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} trace_id=%X{trace_id} span_id=%X{span_id} trace_flags=%X{trace_flags} [%thread] %-5level %logger{36} - %msg%n</pattern>
                -->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{trace_id}:%X{span_id}:%X{trace_flags}] [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>

        <!-- Just wrap your logging appender, for example ConsoleAppender, with OpenTelemetryAppender -->
        <appender name="otel" class="io.opentelemetry.instrumentation.logback.mdc.v1_0.OpenTelemetryAppender">
            <appender-ref ref="console"/>
        </appender>

        <!-- Use the wrapped "otel" appender instead of the original "console" one -->
        <root level="INFO">
            <appender-ref ref="otel"/>
        </root>
    </springProfile>
</configuration>

关于trace_flags定义参见:
https://www.w3.org/TR/trace-context/#trace-flags

四、方式3 - 手动 & SpringBoot集成

SpringBoot应用需依赖opentelemetry-spring-boot-starter
此种方式下由于starter端依赖了OTel SDK,所以无需Agent注入
该starter集成了OTel API/SDK,并对OpenTelemetry进行了自动配置,

该starter引入的依赖如下:

  • opentelemetry-api
  • opentelemetry-instrumentation-api-semconv
  • opentelemetry-sdk
  • opentelemetry-exporter-otlp
  • opentelemetry-exporter-logging
  • opentelemetry-logback-appender-1.0
  • other instrumentation libs
    • web
    • webmvc
    • webflux
    • jdbc
    • kafka
    • logback / log4j appender
    • micrometer

4.1 maven依赖

<properties>
    <otel.version>1.32.0</otel.version>
    <otel.springboot.version>1.32.0-alpha</otel.springboot.version>
    <otel.logback.version>1.32.0-alpha</otel.logback.version>
</properties>

<dependencyManagement>
    <dependencies>
       <!-- OTel基础依赖管理 -->
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-bom</artifactId>
            <version>${otel.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- OTel注解 -->
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-instrumentation-annotations</artifactId>
            <version>${otel.version}</version>
        </dependency>


        <!-- OTel Logback -->
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-logback-appender-1.0</artifactId>
            <version>${otel.logback.version}</version>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-logback-mdc-1.0</artifactId>
            <version>${otel.logback.version}</version>
        </dependency>

        <!-- OTel SpringBoot -->
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-spring-boot-starter</artifactId>
            <version>${otel.springboot.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- OTel SpringBoot -->
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-spring-boot-starter</artifactId>
    </dependency>

    <!-- OTel Logback -->
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-logback-appender-1.0</artifactId>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-logback-mdc-1.0</artifactId>
    </dependency>

    <!-- Jaeger导出器 -->
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-jaeger</artifactId>
    </dependency>
</dependencies>

4.2 应用配置

application.yaml:

otel:
  # 导出器配置
  exporter:
    # OTLP导出
    otlp:
      enabled: false
      endpoint: http://localhost:4317
      timeout: 10s
    # 导出到Zipkin
    zipkin:
      enabled: false
      endpoint: http://localhost:9411/api/v2/spans
    # 导出到Jaeger
    jaeger:
      enabled: true
      endpoint: http://10.170.xx.xxx:xxxx
      timeout: 10s
    # 导出到日志
    logging:
      enabled: true
  traces:
    sampler:
      # 采样频率
      probability: 1.0

更多配置说明可参见:
https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/spring/spring-boot-autoconfigure/README.md#features

关于自定义Traces / Metrics、Logback集成OTel可参见 方式2

五、OpenTelemetry SDK手动编码

5.1 Traces

// ...
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;

public class Dice {

  private int min;
  private int max;
  private Tracer tracer;
  
  //自动注入OpenTelemetry对象
  public Dice(int min, int max, OpenTelemetry openTelemetry) {
    this.min = min;
    this.max = max;
    //获取Tracer
    this.tracer = openTelemetry.getTracer(Dice.class.getName(), "0.1.0");
  }

  public Dice(int min, int max) {
    this(min, max, OpenTelemetry.noop())
  }

  public List<Integer> rollTheDice(int rolls) {
    //通过Tracer创建Span
    Span parentSpan = tracer.spanBuilder("parent")
        //添加关联的Context
  		//.addLink(parentSpan1.getSpanContext())
        //.addLink(parentSpan2.getSpanContext())
        //.addLink(remoteSpanContext)
    	.startSpan();
    
    //为Span添加属性
	parentSpan .setAttribute(SemanticAttributes.HTTP_METHOD, "GET");
	parentSpan .setAttribute(SemanticAttributes.HTTP_URL, "/rolldice");
	
    //为Span添加事件
	Attributes eventAttributes = Attributes.of(
	    AttributeKey.stringKey("key"), "value",
	    AttributeKey.longKey("result"), 0L
	);
	parentSpan .addEvent("End Computation", eventAttributes);

	//开始Span处理
    try (Scope scope = parentSpan.makeCurrent()) {
      List<Integer> results = new ArrayList<Integer>();
      for (int i = 0; i < rolls; i++) {
        //span嵌套
        results.add(this.rollOnce());
      }
      return results;
    } catch (Throwable throwable) {
      //设置Span状态
	  span.setStatus(StatusCode.ERROR, "Something bad happened!");
	  //记录异常堆栈
	  span.recordException(throwable);
	}finally {
      //结束Span
      parentSpan.end();
    }
  }

  private int rollOnce() {
    //子Span处理
    Span childSpan = tracer.spanBuilder("child")
    // NOTE: setParent(...) is not required;
    // `Span.current()` is automatically added as the parent
    .startSpan();
    try(Scope scope = childSpan.makeCurrent()) {
      return ThreadLocalRandom.current().nextInt(this.min, this.max + 1);
    } finally {
      //结束Span
      childSpan.end();
    }
  }  
}

Context传递示例:

//Context读取(从请求头中获取context信息,如请求头traceparent)
TextMapGetter<HttpHeaders> getter =
  new TextMapGetter<HttpHeaders>() {
    @Override
    public String get(HttpHeaders headers, String s) {
      assert headers != null;
      return headers.getHeaderString(s);
    }

    @Override
    public Iterable<String> keys(HttpHeaders headers) {
      List<String> keys = new ArrayList<>();
      MultivaluedMap<String, String> requestHeaders = headers.getRequestHeaders();
      requestHeaders.forEach((k, v) ->{
        keys.add(k);
      });
      return keys.
    }
};

//Context设置(向请求中写入context信息,如请求头traceparent)
TextMapSetter<HttpURLConnection> setter =
  new TextMapSetter<HttpURLConnection>() {
    @Override
    public void set(HttpURLConnection carrier, String key, String value) {
        // Insert the context as Header
        carrier.setRequestProperty(key, value);
    }
};

//...
public void handle(<Library Specific Annotation> HttpHeaders headers){
        //从当前请求中解析上下文
        Context extractedContext = opentelemetry.getPropagators().getTextMapPropagator()
                .extract(Context.current(), headers, getter);
        //使用解析出的上下文
        try (Scope scope = extractedContext.makeCurrent()) {
            // Automatically use the extracted SpanContext as parent.
            Span serverSpan = tracer.spanBuilder("GET /resource")
                .setSpanKind(SpanKind.SERVER)
                .startSpan();

            try(Scope ignored = serverSpan.makeCurrent()) {
                // Add the attributes defined in the Semantic Conventions
                serverSpan.setAttribute(SemanticAttributes.HTTP_METHOD, "GET");
                serverSpan.setAttribute(SemanticAttributes.HTTP_SCHEME, "http");
                serverSpan.setAttribute(SemanticAttributes.HTTP_HOST, "localhost:8080");
                serverSpan.setAttribute(SemanticAttributes.HTTP_TARGET, "/resource");

                HttpURLConnection transportLayer = (HttpURLConnection) url.openConnection();
                //设置新请求的上下文
                // Inject the request with the *current*  Context, which contains our current Span.
                openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter);
                // Make outgoing call
            }finally {
                serverSpan.end();
            }
      }
}

5.2 Metrics

种类:文章来源地址https://www.toymoban.com/news/detail-810565.html

  • LongCounter / DoubleCounter - Sync/Async
  • LongUpDownCounter / DoubleUpDownCounter - Sync/Async
  • LongGauge / DoubleGauge - Async
  • LongHistogram / DoubleHistogram - Sync
OpenTelemetry openTelemetry = // obtain instance of OpenTelemetry

// Gets or creates a named meter instance
Meter meter = openTelemetry.meterBuilder("instrumentation-library-name")
        .setInstrumentationVersion("1.0.0")
        .build();

// Build counter e.g. LongCounter
LongCounter counter = meter
      .counterBuilder("processed_jobs")
      .setDescription("Processed jobs")
      .setUnit("1")
      .build();

// It is recommended that the API user keep a reference to Attributes they will record against
Attributes attributes = Attributes.of(AttributeKey.stringKey("Key"), "SomeWork");

// Record data
counter.add(123, attributes);

------------------------------

// Build an asynchronous instrument, e.g. Gauge
meter
  .gaugeBuilder("cpu_usage")
  .setDescription("CPU Usage")
  .setUnit("ms")
  .buildWithCallback(measurement -> {
    measurement.record(getCpuUsage(), Attributes.of(AttributeKey.stringKey("Key"), "SomeWork"));
  });

到了这里,关于OpenTelemetry系列 - 第2篇 Java端接入OpenTelemetry的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 当 OpenTelemetry 遇上阿里云 Prometheus

    作者:逸陵 在云原生可观测蓬勃发展的当下,想必大家对 OpenTelemetry Prometheus 并不是太陌生。OpenTelemetry 是 CNCF(Cloud Native Computing Foundation)旗下的开源项目,它的目标是在云原生时代成为应用性能监控领域的事实标准,它提供了一套统一的 API 和 SDK,用于生成、收集和处理分

    2024年01月22日
    浏览(32)
  • 锐捷RSR系列路由器_接入路由器交换模块配置_IP+MAC绑定

    目录 01  IP+MAC绑定配置案例 02  IP+MAC绑定常见问题   功能介绍 IP/MAC地址绑定是指路由器将与其直接相连的网络上的主机的MAC 地址和 IP 地址进行捆绑记录,只有指定的 MAC 地址才可以用相应的 IP 地址。这种机制可以防止被绑定的主机的IP地址不被假冒。应用这种机制有两个前

    2024年02月04日
    浏览(60)
  • 使用 OpenTelemetry 构建可观测性 03 - 导出

    上一个博文中,我提到如何使用 OpenTelemery 的特定语言 API 来收集遥测数据,包含手动和自动的埋点技术,这很重要!但是,收集遥测数据只是解决方案的第一步。 你需要把遥测数据路由转发到其他地方,同时添加额外的元数据信息。这时就轮到 SDK 发挥作用了。 链路追踪生

    2024年02月12日
    浏览(39)
  • 锐捷RSR系列路由器_接入路由器交换模块配置_802.1x认证配置

    目录 01  RSR10-02E、RSR20-14E-F802.1x认证配置 02  802.1X认证常见问题和故障 03  路由器重启802.1X认证失败的解决方案   功能介绍 RSR10-02E、RSR20-14E/F固化交换端口,没有登陆交换卡这种概念,也无法登陆交换卡。路由/交换的所有配置都在路由器的CLI界面完成。 一、组网需求:   

    2024年03月16日
    浏览(56)
  • 在 Kubernetes 中无侵入安装 OpenTelemetry 探针

    OpenTelemetry(简称 Otel,最新的版本是 1.27) 是一个用于观察性的开源项目,提供了一套工具、APIs 和 SDKs,用于收集、处理和导出遥测数据(如指标、日志和追踪信息)。应用程序遥测数据(如追踪、指标和日志)的收集是通过探针来完成的,探针通常以库的形式集成到应用程

    2024年02月05日
    浏览(33)
  • 企业主流全链路监控系统 - OpenTelemetry(一)

    在正式介绍OpenTelemetry之前,我们还需要了解什么是可观测性 管理学大师彼得德鲁克有一句话:“如果你无法衡量它,你就无法管理它”。在企业中,无论是管理人,还是管理事,抑或是管理系统,首先都需要衡量。衡量的过程其实是搜集信息的过程,有了足够的信息才能做

    2024年02月10日
    浏览(30)
  • OpenTelemetry 与 Prometheus - 架构和指标的差异

    在不断发展的软件开发世界中,可观察性使软件工程师能够实时洞察复杂的系统。OpenTelemetry 和 Prometheus 是著名的云原生计算基金会 (CNCF) 毕业项目,但用于监控和调试应用程序的可观察性工具不同。 本文探讨了 OpenTelemetry 和 Prometheus 的特性、优点、缺点和主要区别。软件开

    2024年01月25日
    浏览(29)
  • Java接入文心一言

    首先需要先申请文心千帆大模型,申请地址:文心一言 (baidu.com),点击加入体验,等通过审核之后就可以进入文心千帆大模型后台进行应用管理了。 在百度智能云首页即可看到文心千帆大模型平台 然后进入后台管理之后,点击应用接入,创建应用即可 创建完应应用之后,便

    2024年02月10日
    浏览(59)
  • 【Java接入通义千问】

    通义千问是阿里巴巴达摩院研发的预训练语言模型,提供了一系列的API和SDK可以方便地进行接入。本文将介绍如何使用SpringBoot接入通义千问,并实现搜索功能。 首先,我们需要在pom.xml文件中添加以下依赖项: 在application.properties文件中,配置以下内容,设置通义千问的API

    2024年02月13日
    浏览(82)
  • Observability:使用 OpenTelemetry 手动检测 .NET 应用程序

    作者:David Hope 在快节奏的软件开发领域,尤其是在云原生领域,DevOps 和 SRE 团队日益成为应用程序稳定性和增长的重要合作伙伴。 DevOps 工程师不断优化软件交付,而 SRE 团队则充当应用程序可靠性、可扩展性和顶级性能的管理者。 挑战? 这些团队需要一种尖端的可观察性

    2024年02月06日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包