在 OpenTelemetry 中,服务由资源描述,资源是在应用程序启动期间初始化 OpenTelemetry SDK 时设置的。详细规范可点击此链结。
Attribute | Description | Example | Required |
---|---|---|---|
service.name | 给予服务的额外名称。对於水平扩展服务的所有实例,必须相同 | oteldemo | Y |
service.version | 定义服务 API 或服务版本 | aip:1.2.3 | N |
host.hostname | 主机名或以域名表示 | oteldemo.com.tw | N |
目前只能使用环境变数方式进行设置 OTEL_RESOURCE_ATTRIBUTES
。这些的设定都是为了让後端能够进一步的识别分析。
Span
是组成 Tracer
的单位。
为了要有完整 Tracer
的过程,每个 Span
要将 SpanContext
传递至子 Span。
SpanContext
透过 span_ID
告知子 span
谁是父,以及它属於什麽 Tracer
(trace_ID)。
由 Key-value
组成,提供 Span
详细的资讯。可以查询、分组或以其他方式分析 trace
和 span
。
可将其设定为 OK
、Cancelled
或 Permission Denied
。
SpanKind
在 Tracer
中提供有用讯息,此 Span
是否为远端系统? SpanKind
值可以为 CLIENT
、SERVER
、PRODUCER
、CONSUMER
和 INTERNAL
。详细可参考官方链结
包含名称、时间戳和可选的 Attributes
集合等。其表示在 Span
工作负载内的特定时间发生所发生的事件。可能如下
events:
t:3
name:log
message: "retrieved 400 records"
...
每次调用带注释的方法时,它会在当前 Trace
中创建一个子 `Span,并记录所有引发的异常。
也可以透过 exclude
,排除一些不要的场景。
如果要与 Tracer
进行交互,需要先获取 Tracer
的实例。Tracer
以它们要检测的组件命名。通常是一个 library、一个 package或一个 class。
Tracer tracer = GlobalOpenTelemetry.getTracer(instrumentationName, instrumentationVersion);
Span
中 setAttribute
是用於细分数据的索引。可能想要新增帐户 ID 之类,以了解请求瓶颈和错误是否特定於某个帐户或是否影响每个帐户。Span
中 addEvent
可将细节做记录,就是日志的概念。这可自动查找与特定事务关联的所有日志,而不必进行大量的搜索和过滤。随着服务的扩展这将是一个很好的追踪过程Span
是在应用程序框架中被创建和管理。每个请求自动创建一个 Tracer
,且应用程序程序码已经被包装在一个 Span
,可用於新增特定於应用程序的属性(setAttribute)和事件(addEvent)。
上述的前提是框架要被支援。
Span span = Span.current()
当创建自己的 Span。这些范围将自动成为当前范围的子,同时新增至 Tracer
中。Span
管理包括三个步骤:开始 Span
、设置为当前 Span
和结束 Span
。当前如果存在 Span
,OpenTelemetry
会将其创建为当前 Span
的子。会在 Tracer
上调用 spanBuilder
方法以触发一个新的 Tracer
。创建新的 Span
後,使用 Scope
建立一个新的代码区块,当中会包含子 Span
。在该范围内对 Span.current()
的任何调用都将回传该子 Span
,而不是请求的父 Span
。都完成後,需呼叫 end()
方法来关闭 Span
,否则会有泄漏问题。
在 OpenTelemetry
中,异常记录为事件。但是,为确保异常的格式正确,应使用 span.recordException(error)
方法而非 addEvent
。
childSpan.recordException(new RuntimeException("oops"));
childSpan.setStatus(StatusCode.ERROR);
在 OpenTelemetry
中,错误表示整体操作未完成。当异常被处理并不表示着整个操作都无法完成。为了示意操作失败,需调用 span.setStatus()
并传入错误代码,该代码可让分析工具来自动触发警报、测量错误率等。
使用 Annotation
方式,此方式会建立一个 Span
,而此 Span
会是触发该 Span
的子 Span
,我们这边设置了属性(setAttribute)和事件(event)这会以 Log
方式呈现。
@WithSpan
public static void requestValueSpan(Note note) {
Span span = Span.current();
span.setAttribute("id", note.getId());
span.addEvent("Get.note.from.id", Attributes.of(AttributeKey.stringKey("content"), note.getContent(),AttributeKey.stringKey("title"), note.getTitle()));
}
下面算是实作 @WithSpan
的方式,只不过需要定义一个 Tracer
,在建立一个 Span(spanBuilder)。
private final Tracer tracer = GlobalOpenTelemetry.getTracer(NoteServiceImp.class.getSimpleName());
@Override
public void saveNote(Note note) {
// TODO Auto-generated method stub
Span span = tracer.spanBuilder("saveNote").startSpan();
try (Scope scope = span.makeCurrent()) {
this.noteRepository.save(note);
span.setAttribute("CreateTime", note.getCreatedAt().toString());
span.addEvent("Request.query", Attributes.of(AttributeKey.stringKey("content"), note.getContent(),AttributeKey.stringKey("title"), note.getTitle()));
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, "Change it to your error message");
} finally {
span.end(); // closing the scope does not end the span, this has to be done manually
}
}
建立父子关系的 Span
,在 child 方法中呼叫 setParent
。
private static void parent() {
Span parentSpan = tracer.spanBuilder("parent").startSpan();
try {
parentSpan.addEvent("parent", Attributes.of(AttributeKey.stringKey("parent"), "parent"));
child(parentSpan);
} finally {
parentSpan.end();
}
}
private static void child(Span span) {
Span childSpan = tracer.spanBuilder("child").setParent(Context.current().with(span)).startSpan();
try (Scope scope = childSpan.makeCurrent()) {
childSpan.setAttribute("name", "child");
} catch (Exception e) {
// TODO: handle exception
} finally {
childSpan.end();
}
}
架设开发环境在 VSCODE,需在 lunch.json 中设定 vmArgs
,定义与前几章 docker-compose 中几乎相同的参数,-javaagent:opentelemetry-javaagent-all.jar
导入 opentelemetry,定义 endpoint。
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch Current File",
"request": "launch",
"mainClass": "${file}",
"vmArgs": "-javaagent:opentelemetry-javaagent-all.jar -Dotel.resource.attributes=service.name=oteldemo -Dotel.exporter.otlp.endpoint=http://172.17.10.105:4317 -Dotel.exporter.otlp.traces.endpoint=http://172.17.10.105:4317 -Dotel.exporter.otlp.metrics.endpoint=http://172.17.10.105:4317"
},
{
"type": "java",
"name": "Launch OteldemoApplication",
"request": "launch",
"mainClass": "com.otel.example.oteldemo.OteldemoApplication",
"projectName": "oteldemo"
}
]
}
上述的范例可参考 github
<<: Day26:Dynamic Programming(DP) - 动态规划(下)
Thread Thread是Java的原生类别,当需要执行绪处理费时任务时,就可以新增该类别执行Ta...
基本上,JSX 单纯只是 React.createElement(component, props...
在长尾效应跟爆款理论中,实际上是边际效应的正反两面。 网路减少了边际效应的成本,让原本的长尾需求被收...
参考文章: https://medium.com/easons-murmuring/%E5%9C%A...
前面我们将了,如果通过 C# 从文本中获取内容,并进行一些简单的处理。今天我们来看看,怎么将获取的内...