This module provides an instance of OpenTelemetry as a capability. The instance is obtained from GlobalOpenTelemetry. The capability factory takes care of installing a logback appender to bridge OpenTelemetry with logging frameworks.
If you are new to OpenTelemetry, check out Open Telemetry Quick Reference (Java) for general information.
This page focuses on Nasdanika-specific functionality.
By default auto-configuration is disabled. Set otel.java.global-autoconfigure.enabled
to true to enable auto-configuration. Then use Environment variables and system properties to configure the global instance.
This is an example of Java command line properties to configure telemetry repoting to a collector over OTLP protocol: -Dotel.java.global-autoconfigure.enabled=true -Dotel.metrics.exporter=otlp -Dotel.logs.exporter=otlp -Dotel.traces.exporter=otlp -Dotel.exporter.otlp.endpoint=http://<VM external IP>:4317 -Dotel.service.name=<service name>
.
Below is a sample logback.xml
file/resource:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="file" class="ch.qos.logback.core.FileAppender">
<file>nsd.log</file>
<append>true</append>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %kvp{DOUBLE}%n</pattern>
</encoder>
</appender>
<appender name="OpenTelemetry"
class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
<captureExperimentalAttributes>true</captureExperimentalAttributes>
<captureKeyValuePairAttributes>true</captureKeyValuePairAttributes>
</appender>
<root level="INFO">
<appender-ref ref="file"/>
<appender-ref ref="OpenTelemetry"/>
</root>
</configuration>
ProgressMonitor progressMonitor = new PrintStreamProgressMonitor();
CapabilityLoader capabilityLoader = new CapabilityLoader();
try {
Requirement<Object, OpenTelemetry> requirement = ServiceCapabilityFactory.createRequirement(OpenTelemetry.class);
OpenTelemetry openTelemetry = capabilityLoader.loadOne(requirement, progressMonitor);
...
} finally {
parentSpan.end();
}
} finally {
capabilityLoader.close(progressMonitor);
}
See Capability for more details.
If an instance of OpenTelemetry is required by another capability provider, use CapabilityFactory.Loader instead of CapabilityLoader and chain capability completion stages with thenApply
and thenCombine()
.
If your capability depends just on the OpenTelemetry capability then use thenApply()
as shown below:
public class MyCapabilityFactory extends ServiceCapabilityFactory<MyRequirement, MyCapability> {
@Override
public boolean isFor(Class<?> type, Object requirement) {
return MyCapability.class == type && (requirement == null || requirement instanceof MyRequirement);
}
@Override
protected CompletionStage<Iterable<CapabilityProvider<MyCapability>>> createService(
Class<MyCapability> serviceType,
MyRequirement requirement,
Loader loader,
ProgressMonitor progressMonitor) {
Requirement<Object, OpenTelemetry> openTelemetryRequirement = ServiceCapabilityFactory.createRequirement(OpenTelemetry.class);
CompletionStage<OpenTelemetry> openTelemetryCS = loader.loadOne(openTelemetryRequirement, progressMonitor);
return wrapCompletionStage(openTelemetryCS.thenApply(openTelemetry -> createMyCapability(openTelemetry, requirement)));
}
protected MyCapability createMyCapability(OpenTelemetry openTelemetry, MyRequirement requirement) {
return new MyCapabilityImpl(openTelemetry, requirement);
}
}
If your capability depends on the OpenTelemetry capability and other capabilities, then use thenCombine()
as shown below:
public class MyCapabilityFactory extends ServiceCapabilityFactory<Void, MyCapability> {
@Override
public boolean isFor(Class<?> type, Object requirement) {
return MyCapability.class == type && requirement == null;
}
@Override
protected CompletionStage<Iterable<CapabilityProvider<MyCapability>>> createService(
Class<MyCapability> serviceType,
Void serviceRequirement,
Loader loader,
ProgressMonitor progressMonitor) {
Requirement<Object, OpenTelemetry> openTelemetryRequirement = ServiceCapabilityFactory.createRequirement(OpenTelemetry.class);
CompletionStage<OpenTelemetry> openTelemetryCS = loader.loadOne(openTelemetryRequirement, progressMonitor);
Requirement<String, OpenAIClientBuilder> openAIClientBuilderRequirement = ServiceCapabilityFactory.createRequirement(
OpenAIClientBuilder.class,
null,
"https://api.openai.com/v1/");
CompletionStage<OpenAIClientBuilder> openAIClientBuilderCS = loader.loadOne(openAIClientBuilderRequirement, progressMonitor);
return wrapCompletionStage(openAIClientBuilderCS.thenCombine(openTelemetryCS, this::createEmbeddings));
}
protected MyCapability createMyCapability(OpenAIClientBuilder openAIClientBuilder, OpenTelemetry openTelemetry) {
return new MyCapabilityImpl(openAIClientBuilder, openTelemetry);
}
}