OpenTelemetry: Instrumenting libraries
Instrumenting libraries
automatic instrumentation은 보통 library hook 혹은 monkey-patching library code를 통해 이뤄짐
OpenTelemetry API
API, SDK
가장 최초의 stable OpenTelemetry API (1.0.*)을 사용하고 updating issue를 굳이 하지 않아도 됨
사용하는 부분만 별도 package로 만드는 방법도 있음
OpenTelemetry Trace API는 안정화 되었으나, 이것의 후속인 Semantic Versioning 2.0인 Semantic Conventions은 아직 안정화 되지 않았음
Getting a tracer
Libraries는 tracer를 반드시 global TracerProvider를 통해 얻어야 함
private static final Tracer tracer = GlobalOpenTelemetry.getTracer("demo", "0.0.0-beta");
획득 시 lib name과 version을 제공
What to instrument
public APIs
public API 호출을 위해 성생된 span들은 user가 telemetry를 application code에 map 하게 함
이로서 lib call의 duration과 결과를 이해할 수 있게 함
ex.
private static final Tracer tracer = GlobalOpenTelemetry.getTracer("demo", "0.1.0-beta1");
private Response selectWithTracing(Query query) {
// check out conventions for guidance on span names and attributes
Span span = tracer.spanBuilder(String.format("SELECT %s.%s", dbName, collectionName))
.setSpanKind(SpanKind.CLIENT)
.setAttribute("db.name", dbName)
...
.startSpan();
// makes span active and allows correlating logs and nest spans
try (Scope unused = span.makeCurrent()) {
Response response = query.runWithRetries();
if (response.isSuccessful()) {
span.setStatus(StatusCode.OK);
}
if (span.isRecording()) {
// populate response attributes for response codes and other information
}
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName());
throw e;
} finally {
span.end();
}
}
Nested network and other spans
Events
뭔가 많이 찍어야 할 경우에는 event 즉 log를 사용
rule of thumb
- 많은 데이터에 대해서는 span 대신 log를 사용
- 항상 event를 span에 붙이기
- active span의 사용은 피하기
Context Propagation
extracting context
lib, service가 web framework 혹은 message consumer처럼 upstream call을 받는다면, 들어온 request/message에서 context를 추출해야 함
OpenTelemetry는 Propagator를 제공
특정 propagation standards를 감추고 wire로부터의 trace context를 읽음
응답이 하나라면, wire 상에 context로 하나
이는 library가 만드는 span의 부모가 됨
span을 만들고 나면, span을 active하게 만들어 새로운 trace context를 app code로 보내야 함 (callback or handler)
// extract the context
Context extractedContext = propagator.extract(Context.current(), httpExchange, getter);
Span span = tracer.spanBuilder("receive")
.setSpanKind(SpanKind.SERVER)
.setParent(extractedContext)
.startSpan();
// make span active so any nested telemetry is correlated
try (Scope unused = span.makeCurrent()) {
userCode();
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR);
throw e;
} finally {
span.end();
}
ex.
https://opentelemetry.io/docs/instrumentation/java/manual/#context-propagation
Manual Instrumentation
Libraries that want to export telemetry data using OpenTelemetry MUST only depend on the opentelemetry-api package and should never configure or depend on the OpenTelemetry SDK. The SDK configuration must be provided by Applications which should also depen
opentelemetry.io
Injecting context
context를 downstream service로 전달하고 싶을때
새로운 span을 만들어 나가는 call을 trace하고
Propagator API를 사용해서 context를 message로 inject
e.g.,
Span span = tracer.spanBuilder("send")
.setSpanKind(SpanKind.CLIENT)
.startSpan();
// make span active so any nested telemetry is correlated
// even network calls might have nested layers of spans, logs or events
try (Scope unused = span.makeCurrent()) {
// inject the context
propagator.inject(Context.current(), transportLayer, setter);
send();
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR);
throw e;
} finally {
span.end();
}
https://opentelemetry.io/docs/instrumentation/java/manual/#context-propagation
Manual Instrumentation
Libraries that want to export telemetry data using OpenTelemetry MUST only depend on the opentelemetry-api package and should never configure or depend on the OpenTelemetry SDK. The SDK configuration must be provided by Applications which should also depen
opentelemetry.io