我的编程空间,编程开发者的网络收藏夹
学习永远不晚

OpenTelemetry Java SDK 高级用法解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

OpenTelemetry Java SDK 高级用法解析

引言

通过引入 OpenTelemetry SDK,可以观测业务核心逻辑,比如给核心的业务设置一个 span 以统计、跟踪、分析其实际行为、设置业务属性指标等。此方法具有一定的侵入性。

启动命令

java -javaagent:../opentelemetry-javaagent/opentelemetry-javaagent.jar \
-Dotel.traces.exporter=otlp \
-Dotel.exporter.otlp.endpoint=http://192.168.91.11:4317 \
-Dotel.resource.attributes=service.name=demo,version=dev \
-Dotel.metrics.exporter=otlp \
-jar springboot-opentelemetry-otlp-server.jar --client=true

根据启动参数 exporter 的不同,sdk 方式也需要引入对应的 exporter ,否则启动失败。如启动参数使用了 otlplogging 两个 exporter,则需要在 pom 添加对应的两个 exporter 依赖。

如果没有使用 sdk 相关依赖,则不需要做对应的调整。

引入依赖

	<dependencies>
		...
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-exporter-otlp</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-extension-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-semconv</artifactId>
            <version>1.21.0-alpha</version>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
            <version>1.21.0-alpha</version>
        </dependency>
		...
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.opentelemetry</groupId>
				<artifactId>opentelemetry-bom</artifactId>
				<version>1.21.0</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

创建 sdk


@Bean
public OpenTelemetry openTelemetry() {
    return AutoConfiguredOpenTelemetrySdk.builder()
            .setResultAsGlobal(false) // 这里填写false,否则会与全局javaagent 冲突
            .build()
            .getOpenTelemetrySdk();
}

链路(Trace)

创建 Tracer

Tracer 主要是用来获取、创建 span 对象。注意: Tracer 通常不负责进行配置,这是TracerProvider 的职责。 OpenTelemetry interface 提供了默认的TracerProvider实现。

TracerProvider getTracerProvider();

通过openTelemetry() 来获取 Tracer 对象

    @Bean
    public Tracer tracer() {
        return openTelemetry().getTracer(appName);
    }

创建 Span

除了 Tracer 外,不准许任何其他 API 创建 Span 。

Span span = tracer.spanBuilder(spanName).startSpan();

获取当前 Span 对象

获取当前 span 对象,可以为当前 span 设置 attribute、event 等。

Span span = Span.current();

创建 Attribute

attribute 为 span 的属性,为当前 span 的标签。

span.setAttribute(key, value);

创建 Link Span

一个 Span 可以连接一个或多个因果相关的其他 Span 。链接可用于表示批处理操作,其中一个 Span 的初始化由多个 Span 初始化构成,其中每个 Span 表示批处理中处理的单个输入项。

Span child = tracer.spanBuilder(spanName)
		.addLink(span(1))
		.addLink(span(2))
		.addLink(span(3))
		.startSpan();

创建 Event

Span 可以携带零个或多个 Span 属性的命名事件进行注释,每一个事件都是一个 key:value 键值对并自动携带相应的时间戳。

span.addEvent(eventName);
span.addEvent(eventName,Attributes);

recordException 是 addEvent 的特殊变体,用于记录异常事件。

创建一个嵌套的 Span

通过 setParent(parentSpan) 设置 parentSpan

void parent() {
	Span parentSpan = tracer.spanBuilder("parent")
		.startSpan();
	childSpan(parentSpan);
	parentSpan.end();
}
void childSpan(Span parentSpan) {
	Span childSpan = tracer.spanBuilder("childSpan")
		.setParent(parentSpan)
		.startSpan();
	// do stuff
	childSpan.end();
}

Baggage 用法

Baggage 可以在整个链路传播,适用于全局埋点,比如用户id埋点、用户名埋点,以便追踪业务数据。

gateway方法 set Baggage

// Baggage 用法,此处set
	Baggage.current().toBuilder().put("app.username", "gateway").build().makeCurrent();
	logger.info("gateway set baggage[app.username] value: gateway");

resource 方法 get Baggage

 // Baggage 用法,此get
	String baggage = Baggage.current().getEntryValue("app.username");
	logger.info("resource get baggage[app.username] value: {}", baggage);

通过已知的traceId和spanId,来构造一个新span。

Tracer 构造 span 提供了setParent(context)方法,便于为自定义的 span 构造一个父 span。

tracer.spanBuilder(spanName).setParent(context)

其中 setParent 需要传入 Context 参数,所以需要构造一个上下文。

而 OpenTelemetry sdk 只提供了一个 create 方法用于创建 SpanContext,其中可以自定义 traceId 和 spanId。

SpanContext create(String traceIdHex, String spanIdHex, TraceFlags traceFlags, TraceState traceState)

SpanContext 作为表示 Span 的一部分,他必须可以进行序列化,并沿着分布式上下文进行传播。SpanContext 是不可变的。

OpenTelemetry SpanContext 符合 W3C TraceContext 规范。这包含两个标识符 - TraceId 和 SpanId - 一套通用 TraceFlags 和 系统特定 TraceState。

TraceId 一个有效的 TraceId 是一个 16 字节的数组,且至少有一个非零字节。

SpanId 一个有效的 SpanId 是一个 8 字节的数组,且至少有一个非零字节。

TraceFlags 包含该 trace 的详情。不像 TraceFlagsTraceFlags 影响所有的 traces。当前版本和定义的 Flags 只有 sampled 。

TraceState 携带特定 trace 标识数据,通过一个 KV 对数组进行标识。TraceState允许多个跟踪系统参与同一个 Trace。完整定义请参考 W3C Trace Context specification 。

本 API 必须实现创建 SpanContext 的方法。这些方法应当是唯一的方法用于创建 SpanContext。这个功能必须在 API 中完全实现,并且不应当可以被覆盖。

但 SpanContext 并不是 Context,因而还需要做一层转换。

private Context withSpanContext(SpanContext spanContext, Context context) {
	return context.with(Span.wrap(spanContext));
}

完整代码如下:

    
    @GetMapping("/customSpanByTraceIdAndSpanId")
    @ResponseBody
    public String customSpanByTraceIdAndSpanId(String spanName,String traceId,String spanId){
        assert StringUtils.isEmpty(spanName):"spanName 不能为空";
        assert StringUtils.isEmpty(traceId):"traceId 不能为空";
        assert StringUtils.isEmpty(spanId):"spanId 不能为空";
        Context context =
                withSpanContext(
                        SpanContext.create(
                                traceId, spanId, TraceFlags.getSampled(), TraceState.getDefault()),
                        Context.current());
        Span span = tracer.spanBuilder(spanName)
                .setParent(context)
                .startSpan();
        span.setAttribute("attribute.a2", "some value");
        span.setAttribute("func","attr");
        span.setAttribute("app","otel3");
        span.end();
        return buildTraceUrl(span.getSpanContext().getTraceId());
    }
    private Context withSpanContext(SpanContext spanContext, Context context) {
        return context.with(Span.wrap(spanContext));
    }

需要特别注意,依据当前测试写法的请求自身会产生一个新的 trace 信息。新构造的 span 是依据传入的参数进行构造。

我们可以通过访问链接来观察结果

http://localhost:8080/customSpanByTraceIdAndSpanId?spanName=tSpan&traceId=24baeeddfbb35fceaf4c18e7cae58fe1&spanId=ff1955b4f0eacc4f

指标(Metrics)

OpenTelemetry 还提供了 metric 相关操作的 API。

span 提供关于应用程序的详细信息,但生成的数据与系统上的负载成正比。相比之下,度量将单个度量组合成聚合,并生成作为系统负载函数的常量数据。聚合缺乏诊断低级问题所需的细节,但是通过帮助识别趋势和提供应用程序运行时遥测来补充跨度。

度量 API 定义了各种工具。仪器记录测量值,这些测量值由度量 SDK 聚合,并最终导出到进程外。仪器有同步和异步两种。同步仪器记录测量结果。异步仪器注册回调,每次采集调用一次,并记录该时间点的测量值。下列仪器可供选择:

LongCounter/DoubleCounter: 只记录正数值,有同步和异步选项。用于计算事物,例如通过网络发送的字节数。默认情况下,计数器测量被聚合为始终递增的单调和。

LongUpDownCounter/DoubleUpDownCounter: 记录正负值,有同步和异步选项。对于计算上升和下降的东西很有用,比如队列的大小。默认情况下,向上向下计数器测量被聚合为非单调和。

LongGauge/DoubleGauge: 用异步回调测量瞬时值。用于记录不能跨属性合并的值,如 CPU 使用率百分比。默认情况下,量规测量被聚合为量规。

LongHistogram/DoubleHistogram(长直方图/双直方图): 记录对直方图分布分析最有用的测量值。没有异步选项可用。用于记录 HTTP 服务器处理请求所花费的时间等。默认情况下,直方图测量被聚合为显式的桶直方图。

获取 Meter 对象

API定义了一个 Meter 接口。该接口由一组 instrument 构造器,和一个使用原子方式批量获取测量值的工具组成。Meter 可以通过 MeterProvider 的 getMeter(name)方法来创建一个新实例。 MeterProvider 通常被期望作为单例来使用。 其实现应作为 MeterProvider 全局的唯一实现。通过 Meter 对象可以构建不同类型的 metric。

    @Bean
    public Meter meter() {
        return openTelemetry().getMeter(appName);
    }

这里跳过了 MeterProvider 的细节,主要原因在于 OpenTelemetry Interface 提供了 MeterProvider 的默认 noop 实现。

    default MeterProvider getMeterProvider() {
        return MeterProvider.noop();
    }

构建 gauge 类型的 metric

	meter().gaugeBuilder("connections")
		.setDescription("当前Socket.io连接数")
		.setUnit("1")
		.buildWithCallback(
				result -> {
					System.out.println("metrics");
					for (int i = 1; i < 4; i++) {
						result.record(
								i,
								Attributes.of(
										AttributeKey.stringKey("id"),
										"a" + i));
					}
				});

buildWithCallback 是一个回调函数,是支持异步 API 并按需收集度量数据的附加工具,按间隔收集数据,默认 1min 一次。

参考

springboot-opentelemetry-otlp-server

opentelemetry api

opentelemetry java

opentelemetry 参数配置

以上就是OpenTelemetry Java SDK 高级用法解析的详细内容,更多关于OpenTelemetry Java SDK的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

OpenTelemetry Java SDK 高级用法解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

OpenTelemetry Java SDK 高级用法解析

这篇文章主要介绍了OpenTelemetry Java SDK 的高级用法示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-15

Java中注解的高级用法

注解本身没有含义,主要作用是标记目标元素,后续拿到改标识的元数据,进行一系列的处理。注解的使用是非常广泛的,各种框架中都使用频繁,基于注解可以将很多抽象功能提取出来,通过简单 的标识来实现各种复杂的功能。

Java高级-解析Java中的多线程机制(转)

Java高级-解析Java中的多线程机制(转)[@more@]进程与应用程序的区别进程(Process)是最初定义在Unix等多用户、多任务操作系统环境下用于表示应用程序在内存环境中基本执行单元的概念。以Unix操作系统为例,进程是Unix
2023-06-03

java中RabbitMQ高级应用方法

这篇文章主要介绍了java中RabbitMQ高级应用方法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java中RabbitMQ高级应用方法文章都会有所收获,下面我们一起来看看吧。1、消息可靠性投递 
2023-06-30

Java后端高级开发面试技巧解析

  当你收到面试通知后,如下的准备可以大大提升面试成功率。今天陕西优就业小编给大家分享一篇以Java后端高级开发为例,讲述下面试的准备点。方法是通用的,其它方向的同学也可以以此类推。  一、至少定出2天的准备时间:  面试的准备时间一般别低
2023-06-02

在 Java 中,unshift 方法的高级使用技巧有哪些?(java中unshift方法的高级用法)

在Java编程中,unshift方法是数组对象的一个重要方法,它用于在数组的开头添加一个或多个元素,并返回新数组的长度。虽然unshift方法在日常的数组操作中较为常见,但它还有一些高级用法,可以帮助我们更灵活地处理数组数据。
在 Java 中,unshift 方法的高级使用技巧有哪些?(java中unshift方法的高级用法)
Java2024-12-15

java枚举高级用法有哪些

Java枚举的高级用法包括:1. 枚举的自定义方法:可以为枚举类型添加自定义方法,使其具有更多的功能。2. 枚举的构造函数和属性:可以给枚举类型添加构造函数和属性,使其具有更多的属性和行为。3. 枚举的静态方法和实例方法:可以为枚举类型添加
2023-08-21

Python多线程编程全解析:基础到高级用法

Python的Threading模块提供了多线程编程的基本工具。在下面,我将列举一些基础的多线程用法和一些高级用法,并提供相应的源代码,其中包含中文注释。

Python中的迭代器与生成器高级用法解析

迭代器 迭代器是依附于迭代协议的对象——基本意味它有一个next方法(method),当调用时,返回序列中的下一个项目。当无项目可返回时,引发(raise)StopIteration异常。 迭代对象允许一次循环。它保留单次迭代的状态(位置)
2022-06-04

深入理解 TypeScript 高级用法

本文将深入探讨 TypeScript 的高级类型系统,以更好地理解和使用这些高级类型,提高代码的可读性、可维护性和健壮性。

万字详解 TypeScript 高级用法

TypeScript 是一种类型安全的 JavaScript 超集,除了基本类型和对象类型之外,TypeScript 还提供了一些高级类型系统,使得我们可以更好地处理复杂的数据结构和业务逻辑。本文将深入探讨 TypeScript 的高级类型

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录