CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-opentelemetry--opentelemetry-sdk-testing

OpenTelemetry SDK Testing utilities providing comprehensive testing support for OpenTelemetry Java SDK applications with AssertJ assertions, in-memory exporters, and JUnit integration.

Pending
Overview
Eval results
Files

exporters.mddocs/

In-Memory Exporters

In-memory exporters and readers for collecting telemetry data during tests. These components capture spans, metrics, and logs in memory for easy access and validation in test scenarios.

Capabilities

Span Exporter

In-memory span exporter that collects SpanData objects during test execution.

class InMemorySpanExporter implements SpanExporter {
    // Factory method
    static InMemorySpanExporter create();
    
    // Data access
    List<SpanData> getFinishedSpanItems();
    void reset();
    
    // SpanExporter interface methods
    CompletableResultCode export(Collection<SpanData> spans);
    CompletableResultCode flush();
    CompletableResultCode shutdown();
}

Usage examples:

// Setup in-memory span exporter
InMemorySpanExporter spanExporter = InMemorySpanExporter.create();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
    .addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
    .build();

// Use OpenTelemetry normally in your code
Tracer tracer = tracerProvider.get("test");
Span span = tracer.spanBuilder("test-operation").startSpan();
span.setAttribute("key", "value");
span.end();

// Access collected spans in tests
List<SpanData> spans = spanExporter.getFinishedSpanItems();
assertThat(spans).hasSize(1);
assertThat(spans.get(0)).hasName("test-operation");

// Clean up for next test
spanExporter.reset();

Metric Exporter

In-memory metric exporter that collects MetricData objects with configurable aggregation temporality.

class InMemoryMetricExporter implements MetricExporter {
    // Factory methods
    static InMemoryMetricExporter create();
    static InMemoryMetricExporter create(AggregationTemporality temporality);
    
    // Data access
    List<MetricData> getFinishedMetricItems();
    void reset();
    
    // MetricExporter interface methods
    AggregationTemporality getAggregationTemporality(InstrumentType instrumentType);
    CompletableResultCode export(Collection<MetricData> metrics);
    CompletableResultCode flush();
    CompletableResultCode shutdown();
}

Usage examples:

// Setup in-memory metric exporter with default temporality
InMemoryMetricExporter metricExporter = InMemoryMetricExporter.create();
SdkMeterProvider meterProvider = SdkMeterProvider.builder()
    .registerMetricReader(
        PeriodicMetricReader.builder(metricExporter)
            .setInterval(Duration.ofSeconds(1))
            .build())
    .build();

// Use OpenTelemetry normally
Meter meter = meterProvider.get("test");
LongCounter counter = meter.counterBuilder("test-counter").build();
counter.add(10, Attributes.of(AttributeKey.stringKey("key"), "value"));

// Trigger collection and access metrics
List<MetricData> metrics = metricExporter.getFinishedMetricItems();
assertThat(metrics).hasSize(1);

// Setup with specific temporality
InMemoryMetricExporter deltaExporter = InMemoryMetricExporter.create(AggregationTemporality.DELTA);

Log Record Exporter

In-memory log record exporter that collects LogRecordData objects during test execution.

class InMemoryLogRecordExporter implements LogRecordExporter {
    // Factory method
    static InMemoryLogRecordExporter create();
    
    // Data access
    List<LogRecordData> getFinishedLogRecordItems();
    void reset();
    
    // LogRecordExporter interface methods
    CompletableResultCode export(Collection<LogRecordData> logs);
    CompletableResultCode flush();
    CompletableResultCode shutdown();
}

Usage examples:

// Setup in-memory log exporter
InMemoryLogRecordExporter logExporter = InMemoryLogRecordExporter.create();
SdkLoggerProvider loggerProvider = SdkLoggerProvider.builder()
    .addLogRecordProcessor(BatchLogRecordProcessor.builder(logExporter).build())
    .build();

// Use OpenTelemetry logging
Logger logger = loggerProvider.get("test");
logger.logRecordBuilder()
    .setBody("Test log message")
    .setSeverity(Severity.INFO)
    .setAttribute(AttributeKey.stringKey("key"), "value")
    .emit();

// Access collected logs
List<LogRecordData> logs = logExporter.getFinishedLogRecordItems();
assertThat(logs).hasSize(1);
assertThat(logs.get(0)).hasBody("Test log message");

Metric Reader

In-memory metric reader that provides more control over metric collection with configurable aggregation and temporality selection.

class InMemoryMetricReader implements MetricReader {
    // Factory methods
    static InMemoryMetricReaderBuilder builder();
    static InMemoryMetricReader create();
    static InMemoryMetricReader create(
        AggregationTemporalitySelector temporalitySelector, 
        DefaultAggregationSelector aggregationSelector);
    static InMemoryMetricReader createDelta();
    
    // Data collection
    Collection<MetricData> collectAllMetrics();
    
    // MetricReader interface methods
    void register(CollectionRegistration registration);
    AggregationTemporality getAggregationTemporality(InstrumentType instrumentType);
    Aggregation getDefaultAggregation(InstrumentType instrumentType);
    CompletableResultCode forceFlush();
    CompletableResultCode shutdown();
    MemoryMode getMemoryMode();
}

Usage examples:

// Create with default configuration
InMemoryMetricReader reader = InMemoryMetricReader.create();
SdkMeterProvider meterProvider = SdkMeterProvider.builder()
    .registerMetricReader(reader)
    .build();

// Create delta reader for delta temporality
InMemoryMetricReader deltaReader = InMemoryMetricReader.createDelta();

// Create with custom configuration
InMemoryMetricReader customReader = InMemoryMetricReader.create(
    instrumentType -> AggregationTemporality.CUMULATIVE,
    InstrumentType.HISTOGRAM.equals(instrumentType) ? 
        Aggregation.explicitBucketHistogram() : Aggregation.defaultAggregation()
);

// Collect metrics on demand
Collection<MetricData> currentMetrics = reader.collectAllMetrics();
assertThat(currentMetrics).hasSize(expectedMetricCount);

Metric Reader Builder

Builder for creating customized InMemoryMetricReader instances with specific configuration.

class InMemoryMetricReaderBuilder {
    // Configuration methods
    InMemoryMetricReaderBuilder setAggregationTemporalitySelector(AggregationTemporalitySelector selector);
    InMemoryMetricReaderBuilder setDefaultAggregationSelector(DefaultAggregationSelector selector);
    InMemoryMetricReaderBuilder setMemoryMode(MemoryMode memoryMode);
    
    // Build method
    InMemoryMetricReader build();
}

Usage examples:

// Build custom metric reader
InMemoryMetricReader reader = InMemoryMetricReader.builder()
    .setAggregationTemporalitySelector(instrumentType -> {
        if (instrumentType == InstrumentType.COUNTER) {
            return AggregationTemporality.DELTA;
        }
        return AggregationTemporality.CUMULATIVE;
    })
    .setDefaultAggregationSelector(instrumentType -> {
        if (instrumentType == InstrumentType.HISTOGRAM) {
            return Aggregation.explicitBucketHistogram(Arrays.asList(1.0, 5.0, 10.0, 50.0));
        }
        return Aggregation.defaultAggregation();
    })
    .setMemoryMode(MemoryMode.REUSABLE_DATA)
    .build();

Types

// OpenTelemetry core exporter interfaces
interface SpanExporter {
    CompletableResultCode export(Collection<SpanData> spans);
    CompletableResultCode flush();
    CompletableResultCode shutdown();
}

interface MetricExporter {
    AggregationTemporality getAggregationTemporality(InstrumentType instrumentType);
    CompletableResultCode export(Collection<MetricData> metrics);
    CompletableResultCode flush();
    CompletableResultCode shutdown();
}

interface LogRecordExporter {
    CompletableResultCode export(Collection<LogRecordData> logs);
    CompletableResultCode flush();
    CompletableResultCode shutdown();
}

interface MetricReader {
    void register(CollectionRegistration registration);
    AggregationTemporality getAggregationTemporality(InstrumentType instrumentType);
    Aggregation getDefaultAggregation(InstrumentType instrumentType);
    CompletableResultCode forceFlush();
    CompletableResultCode shutdown();
    MemoryMode getMemoryMode();
}

// Configuration types
enum AggregationTemporality { CUMULATIVE, DELTA }
enum InstrumentType { COUNTER, UP_DOWN_COUNTER, HISTOGRAM, GAUGE, OBSERVABLE_COUNTER, OBSERVABLE_UP_DOWN_COUNTER, OBSERVABLE_GAUGE }
enum MemoryMode { REUSABLE_DATA, IMMUTABLE_DATA }

// Functional interfaces for configuration
interface AggregationTemporalitySelector {
    AggregationTemporality getAggregationTemporality(InstrumentType instrumentType);
}

interface DefaultAggregationSelector {
    Aggregation getDefaultAggregation(InstrumentType instrumentType);
}

// Result handling
class CompletableResultCode {
    static CompletableResultCode ofSuccess();
    static CompletableResultCode ofFailure();
    CompletableResultCode join(long timeout, TimeUnit unit);
    boolean isSuccess();
}

Integration Patterns

Complete Test Setup

Example showing how to set up all exporters together for comprehensive testing:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class IntegrationTest {
    
    private InMemorySpanExporter spanExporter;
    private InMemoryMetricReader metricReader;
    private InMemoryLogRecordExporter logExporter;
    private OpenTelemetry openTelemetry;
    
    @BeforeAll
    void setUp() {
        spanExporter = InMemorySpanExporter.create();
        metricReader = InMemoryMetricReader.create();
        logExporter = InMemoryLogRecordExporter.create();
        
        OpenTelemetrySdk sdk = OpenTelemetrySdk.builder()
            .setTracerProvider(
                SdkTracerProvider.builder()
                    .addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
                    .build())
            .setMeterProvider(
                SdkMeterProvider.builder()
                    .registerMetricReader(metricReader)
                    .build())
            .setLoggerProvider(
                SdkLoggerProvider.builder()
                    .addLogRecordProcessor(BatchLogRecordProcessor.builder(logExporter).build())
                    .build())
            .build();
            
        openTelemetry = sdk;
    }
    
    @BeforeEach
    void clearData() {
        spanExporter.reset();
        logExporter.reset();
        // Note: metric reader doesn't have reset, use new collection
    }
    
    @Test
    void testFullTelemetry() {
        // Use openTelemetry instance in your code
        // Then validate collected data
        assertThat(spanExporter.getFinishedSpanItems()).hasSize(expectedSpans);
        assertThat(metricReader.collectAllMetrics()).hasSize(expectedMetrics);
        assertThat(logExporter.getFinishedLogRecordItems()).hasSize(expectedLogs);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-opentelemetry--opentelemetry-sdk-testing

docs

assertions.md

exporters.md

index.md

junit-integration.md

test-builders.md

utilities.md

tile.json