OpenTelemetry SDK Testing utilities providing comprehensive testing support for OpenTelemetry Java SDK applications with AssertJ assertions, in-memory exporters, and JUnit integration.
—
Builder classes for creating test instances of OpenTelemetry telemetry data with full control over all properties and metadata. These builders enable creation of SpanData, MetricData, and LogRecordData objects for use in unit tests and test fixtures.
Builder for creating test SpanData instances with complete control over all span properties.
abstract class TestSpanData implements SpanData {
// Factory method
static Builder builder();
static class Builder {
// Identity and context
Builder setSpanContext(SpanContext context);
Builder setParentSpanContext(SpanContext parentContext);
Builder setResource(Resource resource);
Builder setInstrumentationScopeInfo(InstrumentationScopeInfo instrumentationScopeInfo);
// Basic properties
Builder setName(String name);
Builder setKind(SpanKind kind);
Builder setStartEpochNanos(long startEpochNanos);
Builder setEndEpochNanos(long endEpochNanos);
// Data and metadata
Builder setAttributes(Attributes attributes);
Builder setEvents(List<EventData> events);
Builder setLinks(List<LinkData> links);
Builder setStatus(StatusData status);
// State and counts
Builder setHasEnded(boolean hasEnded);
Builder setTotalRecordedEvents(int totalRecordedEvents);
Builder setTotalRecordedLinks(int totalRecordedLinks);
Builder setTotalAttributeCount(int totalAttributeCount);
// Build method
TestSpanData build();
}
}Usage examples:
// Create a basic test span
TestSpanData span = TestSpanData.builder()
.setName("test-operation")
.setKind(SpanKind.INTERNAL)
.setStartEpochNanos(TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis()))
.setEndEpochNanos(TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis() + 100))
.setAttributes(Attributes.of(
AttributeKey.stringKey("service.name"), "test-service",
AttributeKey.longKey("operation.id"), 12345L
))
.setHasEnded(true)
.build();
// Create a span with custom context
SpanContext spanContext = SpanContext.create(
"12345678901234567890123456789012",
"1234567890123456",
TraceFlags.getSampled(),
TraceState.getDefault()
);
TestSpanData spanWithContext = TestSpanData.builder()
.setSpanContext(spanContext)
.setName("custom-context-span")
.setStartEpochNanos(1000000000L)
.setEndEpochNanos(2000000000L)
.build();
// Create a span with events and links
List<EventData> events = Arrays.asList(
EventData.create(1500000000L, "request.start"),
EventData.create(1800000000L, "request.end",
Attributes.of(AttributeKey.longKey("response.size"), 1024L))
);
List<LinkData> links = Arrays.asList(
LinkData.create(SpanContext.create("other-trace-id", "other-span-id",
TraceFlags.getDefault(), TraceState.getDefault()))
);
TestSpanData complexSpan = TestSpanData.builder()
.setName("complex-operation")
.setEvents(events)
.setLinks(links)
.setStatus(StatusData.create(StatusCode.OK, "Operation completed"))
.setTotalRecordedEvents(2)
.setTotalRecordedLinks(1)
.build();Builder for creating test MetricData instances supporting all metric types (gauges, sums, histograms, exponential histograms, summaries).
abstract class TestMetricData implements MetricData {
// Factory method
static Builder builder();
static class Builder {
// Basic properties
Builder setResource(Resource resource);
Builder setInstrumentationScopeInfo(InstrumentationScopeInfo instrumentationScopeInfo);
Builder setName(String name);
Builder setDescription(String description);
Builder setUnit(String unit);
// Data type specific setters
Builder setDoubleGaugeData(GaugeData<DoublePointData> data);
Builder setLongGaugeData(GaugeData<LongPointData> data);
Builder setDoubleSumData(SumData<DoublePointData> data);
Builder setLongSumData(SumData<LongPointData> data);
Builder setHistogramData(HistogramData data);
Builder setExponentialHistogramData(ExponentialHistogramData data);
Builder setSummaryData(SummaryData data);
// Build method
TestMetricData build();
}
}Usage examples:
// Create a double gauge metric
GaugeData<DoublePointData> gaugeData = ImmutableGaugeData.create(
Arrays.asList(
ImmutableDoublePointData.create(
1000000000L, // startEpochNanos
2000000000L, // epochNanos
Attributes.of(AttributeKey.stringKey("host"), "server1"),
85.5 // value
)
)
);
TestMetricData gaugeMetric = TestMetricData.builder()
.setName("cpu.usage")
.setDescription("CPU usage percentage")
.setUnit("%")
.setDoubleGaugeData(gaugeData)
.setResource(Resource.builder()
.put(ResourceAttributes.SERVICE_NAME, "monitoring-service")
.build())
.build();
// Create a counter sum metric
SumData<LongPointData> sumData = ImmutableSumData.create(
true, // isMonotonic
AggregationTemporality.CUMULATIVE,
Arrays.asList(
ImmutableLongPointData.create(
1000000000L,
2000000000L,
Attributes.of(AttributeKey.stringKey("endpoint"), "/api/users"),
42L // value
)
)
);
TestMetricData counterMetric = TestMetricData.builder()
.setName("http.requests.total")
.setDescription("Total number of HTTP requests")
.setUnit("1")
.setLongSumData(sumData)
.build();
// Create a histogram metric
HistogramData histogramData = ImmutableHistogramData.create(
AggregationTemporality.CUMULATIVE,
Arrays.asList(
ImmutableHistogramPointData.create(
1000000000L,
2000000000L,
Attributes.of(AttributeKey.stringKey("method"), "GET"),
1250.5, // sum
false, // hasMin
0.0, // min
false, // hasMax
0.0, // max
Arrays.asList(0.0, 10.0, 50.0, 100.0, 500.0), // boundaries
Arrays.asList(5L, 15L, 25L, 10L, 3L), // counts
100L // total count
)
)
);
TestMetricData histogramMetric = TestMetricData.builder()
.setName("http.request.duration")
.setDescription("HTTP request duration")
.setUnit("ms")
.setHistogramData(histogramData)
.build();Builder for creating test LogRecordData instances with full control over log properties and metadata.
abstract class TestLogRecordData implements LogRecordData {
// Factory method
static Builder builder();
static class Builder {
// Basic properties
Builder setResource(Resource resource);
Builder setInstrumentationScopeInfo(InstrumentationScopeInfo instrumentationScopeInfo);
// Timing
Builder setTimestamp(Instant instant);
Builder setTimestamp(long timestamp, TimeUnit unit);
Builder setObservedTimestamp(Instant instant);
Builder setObservedTimestamp(long timestamp, TimeUnit unit);
// Content and severity
Builder setBody(String body);
Builder setBodyValue(Value<?> body);
Builder setSeverity(Severity severity);
Builder setSeverityText(String severityText);
// Context and metadata
Builder setSpanContext(SpanContext spanContext);
Builder setAttributes(Attributes attributes);
Builder setTotalAttributeCount(int totalAttributeCount);
Builder setEventName(String eventName);
// Build method
TestLogRecordData build();
}
}Usage examples:
// Create a basic log record
TestLogRecordData logRecord = TestLogRecordData.builder()
.setBody("User authentication successful")
.setSeverity(Severity.INFO)
.setSeverityText("INFO")
.setTimestamp(Instant.now())
.setObservedTimestamp(Instant.now().plusMillis(10))
.setAttributes(Attributes.of(
AttributeKey.stringKey("user.id"), "12345",
AttributeKey.stringKey("auth.method"), "oauth2"
))
.build();
// Create a log record with span context
SpanContext spanContext = SpanContext.create(
"12345678901234567890123456789012",
"1234567890123456",
TraceFlags.getSampled(),
TraceState.getDefault()
);
TestLogRecordData contextualLog = TestLogRecordData.builder()
.setBody("Processing user request")
.setSeverity(Severity.DEBUG)
.setSpanContext(spanContext)
.setTimestamp(1000000000L, TimeUnit.NANOSECONDS)
.setAttributes(Attributes.of(
AttributeKey.stringKey("request.id"), "req-789"
))
.setResource(Resource.builder()
.put(ResourceAttributes.SERVICE_NAME, "user-service")
.put(ResourceAttributes.SERVICE_VERSION, "1.2.3")
.build())
.build();
// Create an error log record
TestLogRecordData errorLog = TestLogRecordData.builder()
.setBody("Database connection failed")
.setSeverity(Severity.ERROR)
.setSeverityText("ERROR")
.setTimestamp(Instant.parse("2023-01-01T12:00:00Z"))
.setAttributes(Attributes.of(
AttributeKey.stringKey("db.host"), "db.example.com",
AttributeKey.longKey("db.port"), 5432L,
AttributeKey.stringKey("error.type"), "ConnectionTimeout"
))
.setTotalAttributeCount(3)
.build();
// Create a structured log with complex body
Value<?> structuredBody = Value.of(Map.of(
"event", "user.created",
"user_id", 12345,
"metadata", Map.of(
"source", "registration_form",
"campaign", "spring_2023"
)
));
TestLogRecordData structuredLog = TestLogRecordData.builder()
.setBodyValue(structuredBody)
.setSeverity(Severity.INFO)
.setEventName("user.created")
.setTimestamp(Instant.now())
.build();// Create a base builder with common configuration
TestSpanData.Builder baseSpanBuilder = TestSpanData.builder()
.setResource(Resource.builder()
.put(ResourceAttributes.SERVICE_NAME, "test-service")
.put(ResourceAttributes.SERVICE_VERSION, "1.0.0")
.build())
.setInstrumentationScopeInfo(
InstrumentationScopeInfo.create("test-instrumentation", "1.0.0"));
// Create multiple spans with shared configuration
TestSpanData span1 = baseSpanBuilder
.setName("operation-1")
.setStartEpochNanos(1000000000L)
.setEndEpochNanos(1100000000L)
.build();
TestSpanData span2 = baseSpanBuilder
.setName("operation-2")
.setStartEpochNanos(1200000000L)
.setEndEpochNanos(1300000000L)
.build();// Create a complete trace with parent-child relationships
String traceId = "12345678901234567890123456789012";
// Parent span
TestSpanData parentSpan = TestSpanData.builder()
.setSpanContext(SpanContext.create(traceId, "1111111111111111",
TraceFlags.getSampled(), TraceState.getDefault()))
.setName("parent-operation")
.setKind(SpanKind.SERVER)
.setStartEpochNanos(1000000000L)
.setEndEpochNanos(5000000000L)
.build();
// Child spans
TestSpanData child1 = TestSpanData.builder()
.setSpanContext(SpanContext.create(traceId, "2222222222222222",
TraceFlags.getSampled(), TraceState.getDefault()))
.setParentSpanContext(parentSpan.getSpanContext())
.setName("child-operation-1")
.setKind(SpanKind.INTERNAL)
.setStartEpochNanos(1500000000L)
.setEndEpochNanos(2500000000L)
.build();
TestSpanData child2 = TestSpanData.builder()
.setSpanContext(SpanContext.create(traceId, "3333333333333333",
TraceFlags.getSampled(), TraceState.getDefault()))
.setParentSpanContext(parentSpan.getSpanContext())
.setName("child-operation-2")
.setKind(SpanKind.INTERNAL)
.setStartEpochNanos(3000000000L)
.setEndEpochNanos(4000000000L)
.build();
// Use in assertions
List<SpanData> traceSpans = Arrays.asList(parentSpan, child1, child2);
assertTraces(traceSpans)
.hasTracesSatisfyingExactly(
trace -> trace.hasSpansSatisfyingExactly(
span -> assertThat(span).hasName("parent-operation"),
span -> assertThat(span).hasName("child-operation-1"),
span -> assertThat(span).hasName("child-operation-2")
)
);// Core OpenTelemetry data interfaces implemented by test builders
interface SpanData {
SpanContext getSpanContext();
SpanContext getParentSpanContext();
Resource getResource();
InstrumentationScopeInfo getInstrumentationScopeInfo();
String getName();
SpanKind getKind();
long getStartEpochNanos();
long getEndEpochNanos();
Attributes getAttributes();
List<EventData> getEvents();
List<LinkData> getLinks();
StatusData getStatus();
boolean hasEnded();
int getTotalRecordedEvents();
int getTotalRecordedLinks();
int getTotalAttributeCount();
}
interface MetricData {
Resource getResource();
InstrumentationScopeInfo getInstrumentationScopeInfo();
String getName();
String getDescription();
String getUnit();
MetricDataType getType();
Data<?> getData();
}
interface LogRecordData {
Resource getResource();
InstrumentationScopeInfo getInstrumentationScopeInfo();
long getTimestampEpochNanos();
long getObservedTimestampEpochNanos();
SpanContext getSpanContext();
Severity getSeverity();
String getSeverityText();
Value<?> getBodyValue();
Attributes getAttributes();
int getTotalAttributeCount();
}
// Supporting data types
interface Attributes {
Map<AttributeKey<?>, Object> asMap();
int size();
boolean isEmpty();
}
interface EventData {
String getName();
long getEpochNanos();
Attributes getAttributes();
int getTotalAttributeCount();
}
interface LinkData {
SpanContext getSpanContext();
Attributes getAttributes();
int getTotalAttributeCount();
}
interface StatusData {
StatusCode getStatusCode();
String getDescription();
}
// Enums and value types
enum SpanKind { INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER }
enum StatusCode { UNSET, OK, ERROR }
enum Severity { TRACE, DEBUG, INFO, WARN, ERROR, FATAL }
enum TraceFlags { /* flag values */ }
class SpanContext {
static SpanContext create(String traceId, String spanId, TraceFlags traceFlags, TraceState traceState);
String getTraceId();
String getSpanId();
TraceFlags getTraceFlags();
TraceState getTraceState();
}Install with Tessl CLI
npx tessl i tessl/maven-io-opentelemetry--opentelemetry-sdk-testing