Керування телеметрією за допомогою SDK

SDK є вбудованою референсною реалізацією API, яка обробляє та експортує телеметрію, створену викликами API інструментування. Ця сторінка є концептуальним оглядом SDK, включаючи описи, посилання на відповідні Javadocs, координати артефактів, приклади програмної конфігурації та інше. Дивіться Конфігурація SDK для деталей щодо конфігурації SDK, включаючи автоконфігурацію SDK без коду.

SDK складається з наступних основних компонентів:

  • SdkTracerProvider: Реалізація SDK для TracerProvider, включаючи інструменти для семплінгу, обробки та експортування відрізків.
  • SdkMeterProvider: Реалізація SDK для MeterProvider, включаючи інструменти для конфігурації потоків метрик та читання/експорту метрик.
  • SdkLoggerProvider: Реалізація SDK для LoggerProvider, включаючи інструменти для обробки та експортування логів.
  • TextMapPropagator: Пропагує контекст через межі процесів.

Ці компоненти обʼєднані в OpenTelemetrySdk, обʼєкт-носій, який робить зручним передавати повністю налаштовані компоненти SDK для інструментування.

SDK постачається з різноманітними вбудованими компонентами, які достатні для багатьох випадків використання, і підтримує інтерфейси плагінів для розширюваності.

Інтерфейси розширення втулків SDK

Коли вбудовані компоненти недостатні, SDK можна розширити, реалізуючи різні інтерфейси розширення втулків:

  • Sampler: Налаштовує, які відрізки записуються та семплюються.
  • SpanProcessor: Обробляє відрізки, коли вони починаються та закінчуються.
  • SpanExporter: Експортує відрізки за межі процесу.
  • MetricReader: Читає агреговані метрики.
  • MetricExporter: Експортує метрики за межі процесу.
  • LogRecordProcessor: Обробляє записи логів, коли вони створюються.
  • LogRecordExporter: Експортує записи логів за межі процесу.
  • TextMapPropagator: Пропагує контекст через межі процесів.

Компоненти SDK

Артефакт io.opentelemetry:opentelemetry-sdk:1.51.0 містить SDK OpenTelemetry.

Наступні розділи описують основні компоненти SDK, з якими працює користувач. Кожен розділ компонентів включає:

OpenTelemetrySdk

OpenTelemetrySdk є реалізацією SDK для OpenTelemetry. Це контейнер для основних компонентів SDK, який робить зручним передавання повністю налаштованих компонентів SDK для інструментування.

OpenTelemetrySdk налаштовується власником додатку і складається з:

Наступний фрагмент коду демонструє програмну конфігурацію OpenTelemetrySdk:

package otel; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; public class OpenTelemetrySdkConfig { public static OpenTelemetrySdk create() { Resource resource = ResourceConfig.create(); return OpenTelemetrySdk.builder() .setTracerProvider(SdkTracerProviderConfig.create(resource)) .setMeterProvider(SdkMeterProviderConfig.create(resource)) .setLoggerProvider(SdkLoggerProviderConfig.create(resource)) .setPropagators(ContextPropagatorsConfig.create()) .build(); } }

Resource

Resource є набором атрибутів, що визначають джерело телеметрії. Застосунок повинен асоціювати той самий ресурс з SdkTracerProvider, SdkMeterProvider, SdkLoggerProvider.

Наступний фрагмент коду демонструє програмну конфігурацію Resource:

package otel; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.semconv.ServiceAttributes; public class ResourceConfig { public static Resource create() { return Resource.getDefault().toBuilder() .put(ServiceAttributes.SERVICE_NAME, "my-service") .build(); } }

SdkTracerProvider

SdkTracerProvider є реалізацією SDK для TracerProvider і відповідає за обробку трасувальної телеметрії, створеної API.

SdkTracerProvider налаштовується власником застосунку і складається з:

  • Resource: Ресурс, з яким асоціюються відрізки.
  • Sampler: Налаштовує, які відрізки записуються та семплюються.
  • SpanProcessors: Обробляє відрізки, коли вони починаються та закінчуються.
  • SpanExporters: Експортує відрізки за межі процесу (у поєднанні з відповідними SpanProcessor).
  • SpanLimits: Контролює обмеження даних, повʼязаних з відрізками.

Наступний фрагмент коду демонструє програмну конфігурацію SdkTracerProvider:

package otel; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; public class SdkTracerProviderConfig { public static SdkTracerProvider create(Resource resource) { return SdkTracerProvider.builder() .setResource(resource) .addSpanProcessor( SpanProcessorConfig.batchSpanProcessor( SpanExporterConfig.otlpHttpSpanExporter("http://localhost:4318/v1/spans"))) .setSampler(SamplerConfig.parentBasedSampler(SamplerConfig.traceIdRatioBased(.25))) .setSpanLimits(SpanLimitsConfig::spanLimits) .build(); } }

Sampler

Sampler є інтерфейсом розширення плагінів, відповідальним за визначення, які відрізки записуються та семплюються.

Семплери, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
ParentBasedio.opentelemetry:opentelemetry-sdk:1.51.0Семплює відрізки на основі статусу семплінгу батьківського відрізка.
AlwaysOnio.opentelemetry:opentelemetry-sdk:1.51.0Семплює всі відрізки.
AlwaysOffio.opentelemetry:opentelemetry-sdk:1.51.0Відкидає всі відрізки.
TraceIdRatioBasedio.opentelemetry:opentelemetry-sdk:1.51.0Семплює відрізки на основі конфігурованого співвідношення.
JaegerRemoteSamplerio.opentelemetry:opentelemetry-sdk-extension-jaeger-remote-sampler:1.51.0Семплює відрізки на основі конфігурації з віддаленого сервера.
LinksBasedSamplerio.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alphaСемплює відрізки на основі статусу семплінгу посилань відрізка.
RuleBasedRoutingSamplerio.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alphaСемплює відрізки на основі конфігурованих правил.
ConsistentSamplersio.opentelemetry.contrib:opentelemetry-consistent-sampling:1.46.0-alphaРізні реалізації консистентного семплінгу, як визначено в ймовірнісному семплінгу.

Наступний фрагмент коду демонструє програмну конфігурацію Sampler:

package otel; import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.time.Duration; public class SamplerConfig { public static Sampler parentBasedSampler(Sampler root) { return Sampler.parentBasedBuilder(root) .setLocalParentNotSampled(Sampler.alwaysOff()) .setLocalParentSampled(Sampler.alwaysOn()) .setRemoteParentNotSampled(Sampler.alwaysOff()) .setRemoteParentSampled(Sampler.alwaysOn()) .build(); } public static Sampler alwaysOn() { return Sampler.alwaysOn(); } public static Sampler alwaysOff() { return Sampler.alwaysOff(); } public static Sampler traceIdRatioBased(double ratio) { return Sampler.traceIdRatioBased(ratio); } public static Sampler jaegerRemoteSampler() { return JaegerRemoteSampler.builder() .setInitialSampler(Sampler.alwaysOn()) .setEndpoint("http://endpoint") .setPollingInterval(Duration.ofSeconds(60)) .setServiceName("my-service-name") .build(); } }

Реалізуйте інтерфейс Sampler, щоб надати власну логіку семплінгу. Наприклад:

package otel; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.trace.data.LinkData; import io.opentelemetry.sdk.trace.samplers.Sampler; import io.opentelemetry.sdk.trace.samplers.SamplingResult; import java.util.List; public class CustomSampler implements Sampler { @Override public SamplingResult shouldSample( Context parentContext, String traceId, String name, SpanKind spanKind, Attributes attributes, List<LinkData> parentLinks) { // Викликається, коли відрізко починається, перед тим як будь-який SpanProcessor буде викликаний. // Якщо SamplingDecision є: // - DROP: відрізок відкидається. Створюється дійсний контекст відрізка, і SpanProcessor#onStart все ще викликається, але дані не записуються, і SpanProcessor#onEnd не викликається. // - RECORD_ONLY: відрізок записується, але не семплюється. Дані записуються у відрізок, викликаються SpanProcessor#onStart і SpanProcessor#onEnd, але статус семплінгу відрізка вказує, що він не повинен експортуватися за межі процесу. // - RECORD_AND_SAMPLE: відрізок записується і семплюється. Дані записуються у відрізок, викликаються SpanProcessor#onStart і SpanProcessor#onEnd, і статус семплінгу відрізка вказує, що він повинен експортуватися за межі процесу. return SpanKind.SERVER == spanKind ? SamplingResult.recordAndSample() : SamplingResult.drop(); } @Override public String getDescription() { // Повертає опис семплера. return this.getClass().getSimpleName(); } }

SpanProcessor

SpanProcessor є інтерфейсом розширення втулків зі зворотними викликами, які викликаються, коли відрізок починається і закінчується. Вони часто поєднуються з SpanExporters для експорту відрізків за межі процесу, але мають інші застосування, такі як збагачення даних.

Процесори відрізків, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
BatchSpanProcessorio.opentelemetry:opentelemetry-sdk:1.51.0Пакує семпльовані відрізки та експортує їх через конфігурований SpanExporter.
SimpleSpanProcessorio.opentelemetry:opentelemetry-sdk:1.51.0Експортує кожен семпльований відрізок через конфігурований SpanExporter.
BaggageSpanProcessorio.opentelemetry.contrib:opentelemetry-baggage-processor:1.46.0-alphaЗбагачує відрізки багажем.
JfrSpanProcessorio.opentelemetry.contrib:opentelemetry-jfr-events:1.46.0-alphaСтворює події JFR зі відрізків.
StackTraceSpanProcessorio.opentelemetry.contrib:opentelemetry-span-stacktrace:1.46.0-alphaЗбагачує вибрані відрізки даними стеку викликів.
InferredSpansProcessorio.opentelemetry.contrib:opentelemetry-inferred-spans:1.46.0-alphaГенерує відрізки з async profiler замість інструментування.

Наступний фрагмент коду демонструє програмну конфігурацію SpanProcessor:

package otel; import io.opentelemetry.sdk.trace.SpanProcessor; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.time.Duration; public class SpanProcessorConfig { public static SpanProcessor batchSpanProcessor(SpanExporter spanExporter) { return BatchSpanProcessor.builder(spanExporter) .setMaxQueueSize(2048) .setExporterTimeout(Duration.ofSeconds(30)) .setScheduleDelay(Duration.ofSeconds(5)) .build(); } public static SpanProcessor simpleSpanProcessor(SpanExporter spanExporter) { return SimpleSpanProcessor.builder(spanExporter).build(); } }

Реалізуйте інтерфейс SpanProcessor, щоб надати власну логіку обробки відрізків. Наприклад:

package otel; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.trace.ReadWriteSpan; import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.SpanProcessor; public class CustomSpanProcessor implements SpanProcessor { @Override public void onStart(Context parentContext, ReadWriteSpan span) { // Викликається, коли відрізок починається. // Збагачує запис користувацьким атрибутом. span.setAttribute("my.custom.attribute", "hello world"); } @Override public boolean isStartRequired() { // Вказує, чи слід викликати onStart. return true; } @Override public void onEnd(ReadableSpan span) { // Викликається, коли спан закінчується. } @Override public boolean isEndRequired() { // Вказує, чи слід викликати onEnd. return false; } @Override public CompletableResultCode shutdown() { // Опціонально завершує роботу процесора та очищає будь-які ресурси. return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode forceFlush() { // Опціонально обробляє будь-які записи, які були поставлені в чергу, але ще не оброблені. return CompletableResultCode.ofSuccess(); } }

SpanExporter

SpanExporter є інтерфейсом розширення втуліків, відповідальним за експорт відрізків за межі процесу. Замість безпосередньої реєстрації з SdkTracerProvider, вони поєднуються з SpanProcessors (зазвичай BatchSpanProcessor).

Експортери відрізків, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
OtlpHttpSpanExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.51.0Експортує відрізки через OTLP http/protobuf.
OtlpGrpcSpanExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.51.0Експортує відрізки через OTLP grpc.
LoggingSpanExporterio.opentelemetry:opentelemetry-exporter-logging:1.51.0Логує відрізки до JUL у форматі налагодження.
OtlpJsonLoggingSpanExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0Логує відрізки до JUL у кодуванні OTLP JSON.
OtlpStdoutSpanExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0Логує відрізки до System.out у OTLP JSON file encoding (експериментально).
ZipkinSpanExporterio.opentelemetry:opentelemetry-exporter-zipkin:1.51.0Експортує відрізки до Zipkin.
InterceptableSpanExporterio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaПередає відрізки до гнучкого перехоплювача перед експортом.
KafkaSpanExporterio.opentelemetry.contrib:opentelemetry-kafka-exporter:1.46.0-alphaЕкспортує відрізки, записуючи їх до теми Kafka.

[1]: Дивіться OTLP exporters для деталей реалізації.

Наступний фрагмент коду демонструє програмну конфігурацію SpanExporter:

package otel; import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.time.Duration; public class SpanExporterConfig { public static SpanExporter otlpHttpSpanExporter(String endpoint) { return OtlpHttpSpanExporter.builder() .setEndpoint(endpoint) .addHeader("api-key", "value") .setTimeout(Duration.ofSeconds(10)) .build(); } public static SpanExporter otlpGrpcSpanExporter(String endpoint) { return OtlpGrpcSpanExporter.builder() .setEndpoint(endpoint) .addHeader("api-key", "value") .setTimeout(Duration.ofSeconds(10)) .build(); } public static SpanExporter logginSpanExporter() { return LoggingSpanExporter.create(); } public static SpanExporter otlpJsonLoggingSpanExporter() { return OtlpJsonLoggingSpanExporter.create(); } }

Реалізуйте інтерфейс SpanExporter, щоб надати власну логіку експорту відрізків. Наприклад:

package otel; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; public class CustomSpanExporter implements SpanExporter { private static final Logger logger = Logger.getLogger(CustomSpanExporter.class.getName()); @Override public CompletableResultCode export(Collection<SpanData> spans) { // Експортує записи. Зазвичай записи надсилаються за межі процесу через якийсь мережевий протокол, але // ми просто логуватимемо для ілюстрації. logger.log(Level.INFO, "Експортування відрізків"); spans.forEach(span -> logger.log(Level.INFO, "Відрізок: " + span)); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode flush() { // Експортує будь-які записи, які були поставлені в чергу, але ще не експортовані. logger.log(Level.INFO, "очищення"); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode shutdown() { // Завершує роботу експортера та очищає будь-які ресурси. logger.log(Level.INFO, "завершення роботи"); return CompletableResultCode.ofSuccess(); } }

SpanLimits

SpanLimits визначає обмеження для даних, захоплених відрізками, включаючи максимальну довжину атрибутів, максимальну кількість атрибутів та інше.

Наступний фрагмент коду демонструє програмну конфігурацію SpanLimits:

package otel; import io.opentelemetry.sdk.trace.SpanLimits; public class SpanLimitsConfig { public static SpanLimits spanLimits() { return SpanLimits.builder() .setMaxNumberOfAttributes(128) .setMaxAttributeValueLength(1024) .setMaxNumberOfLinks(128) .setMaxNumberOfAttributesPerLink(128) .setMaxNumberOfEvents(128) .setMaxNumberOfAttributesPerEvent(128) .build(); } }

SdkMeterProvider

SdkMeterProvider є реалізацією SDK для MeterProvider і відповідає за обробку метрик, створених API.

SdkMeterProvider налаштовується власником застосунку і складається з:

  • Resource: Ресурс, з яким асоціюються метрики.
  • MetricReader: Читає агрегований стан метрик.
    • Опціонально, з CardinalityLimitSelector для перевизначення обмеження кардинальності за типом інструменту. Якщо не встановлено, кожен інструмент обмежується 2000 унікальними комбінаціями атрибутів за цикл збору. Обмеження кардинальності також налаштовуються для окремих інструментів через views. Дивіться обмеження кардинальності для деталей.
  • MetricExporter: Експортує метрики за межі процесу (у поєднанні з відповідним MetricReader).
  • Views: Налаштовує потоки метрик, включаючи відкидання невикористаних метрик.

Наступний фрагмент коду демонструє програмну конфігурацію SdkMeterProvider:

package otel; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.resources.Resource; import java.util.List; import java.util.Set; public class SdkMeterProviderConfig { public static SdkMeterProvider create(Resource resource) { SdkMeterProviderBuilder builder = SdkMeterProvider.builder() .setResource(resource) .registerMetricReader( MetricReaderConfig.periodicMetricReader( MetricExporterConfig.otlpHttpMetricExporter( "http://localhost:4318/v1/metrics"))); // Розкоментуйте, щоб опціонально зареєструвати читач метрик з обмеженнями кардинальності // builder.registerMetricReader( // MetricReaderConfig.periodicMetricReader( // MetricExporterConfig.otlpHttpMetricExporter("http://localhost:4318/v1/metrics")), // instrumentType -> 100); ViewConfig.dropMetricView(builder, "some.custom.metric"); ViewConfig.histogramBucketBoundariesView( builder, "http.server.request.duration", List.of(1.0, 5.0, 10.0)); ViewConfig.attributeFilterView( builder, "http.client.request.duration", Set.of("http.request.method")); ViewConfig.cardinalityLimitsView(builder, "http.server.active_requests", 100); return builder.build(); } }

MetricReader

MetricReader є інтерфейсом розширення втулків, який відповідає за читання агрегованих метрик. Вони часто поєднуються з MetricExporters для експорту метрик за межі процесу, але можуть також використовуватися для обслуговування метрик зовнішнім скреперам у протоколах на основі запитів.

Читачі метрик, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
PeriodicMetricReaderio.opentelemetry:opentelemetry-sdk:1.51.0Читає метрики на періодичній основі та експортує їх через конфігурований MetricExporter.
PrometheusHttpServerio.opentelemetry:opentelemetry-exporter-prometheus:1.51.0-alphaОбслуговує метрики на HTTP-сервері у різних форматах prometheus.

Наступний фрагмент коду демонструє програмну конфігурацію MetricReader:

package otel; import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; import io.opentelemetry.sdk.metrics.export.MetricExporter; import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; import java.time.Duration; public class MetricReaderConfig { public static MetricReader periodicMetricReader(MetricExporter metricExporter) { return PeriodicMetricReader.builder(metricExporter).setInterval(Duration.ofSeconds(60)).build(); } public static MetricReader prometheusMetricReader() { return PrometheusHttpServer.builder().setHost("localhost").setPort(9464).build(); } }

Реалізуйте інтерфейс MetricReader, щоб надати власну логіку читання метрик. Наприклад:

package otel; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.CollectionRegistration; import io.opentelemetry.sdk.metrics.export.MetricReader; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; public class CustomMetricReader implements MetricReader { private static final Logger logger = Logger.getLogger(CustomMetricExporter.class.getName()); private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); private final AtomicReference<CollectionRegistration> collectionRef = new AtomicReference<>(CollectionRegistration.noop()); @Override public void register(CollectionRegistration collectionRegistration) { // Викликається, коли SdkMeterProvider ініціалізується, надаючи обробника для збору метрик. collectionRef.set(collectionRegistration); executorService.scheduleWithFixedDelay(this::collectMetrics, 0, 60, TimeUnit.SECONDS); } private void collectMetrics() { // Збирає метрики. Зазвичай записи надсилаються за межі процесу через якийсь мережевий протокол, але ми // просто логуватимемо для ілюстрації. logger.log(Level.INFO, "Збір метрик"); collectionRef .get() .collectAllMetrics() .forEach(metric -> logger.log(Level.INFO, "Метрика: " + metric)); } @Override public CompletableResultCode forceFlush() { // Експортує будь-які записи, які були поставлені в чергу, але ще не експортовані. logger.log(Level.INFO, "очищення"); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode shutdown() { // Завершує роботу експортера та очищає будь-які ресурси. logger.log(Level.INFO, "завершення роботи"); return CompletableResultCode.ofSuccess(); } @Override public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { // Вказує необхідну агрегаційну тимчасовість як функцію типу інструменту return AggregationTemporalitySelector.deltaPreferred() .getAggregationTemporality(instrumentType); } @Override public MemoryMode getMemoryMode() { // Опціонально вказує режим памʼяті, вказуючи, чи можуть записи метрик бути повторно використані або повинні // бути незмінними return MemoryMode.REUSABLE_DATA; } @Override public Aggregation getDefaultAggregation(InstrumentType instrumentType) { // Опціонально вказує стандартну агрегацію як функцію типу інструменту return Aggregation.defaultAggregation(); } }

MetricExporter

MetricExporter є інтерфейсом розширення плагінів, відповідальним за експорт метрик за межі процесу. Замість безпосередньої реєстрації з SdkMeterProvider, вони поєднуються з PeriodicMetricReader.

Експортери метрик, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
OtlpHttpMetricExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.51.0Експортує метрики через OTLP http/protobuf.
OtlpGrpcMetricExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.51.0Експортує метрики через OTLP grpc.
LoggingMetricExporterio.opentelemetry:opentelemetry-exporter-logging:1.51.0Логує метрики до JUL у форматі налагодження.
OtlpJsonLoggingMetricExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0Логує метрики до JUL у кодуванні OTLP JSON.
OtlpStdoutMetricExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0Логує метрики до System.out у OTLP JSON file encoding (експериментально).
InterceptableMetricExporterio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaПередає метрики до гнучкого перехоплювача перед експортом.

[1]: Дивіться OTLP exporters для деталей реалізації.

Наступний фрагмент коду демонструє програмну конфігурацію MetricExporter:

package otel; import io.opentelemetry.exporter.logging.LoggingMetricExporter; import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingMetricExporter; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.sdk.metrics.export.MetricExporter; import java.time.Duration; public class MetricExporterConfig { public static MetricExporter otlpHttpMetricExporter(String endpoint) { return OtlpHttpMetricExporter.builder() .setEndpoint(endpoint) .addHeader("api-key", "value") .setTimeout(Duration.ofSeconds(10)) .build(); } public static MetricExporter otlpGrpcMetricExporter(String endpoint) { return OtlpGrpcMetricExporter.builder() .setEndpoint(endpoint) .addHeader("api-key", "value") .setTimeout(Duration.ofSeconds(10)) .build(); } public static MetricExporter logginMetricExporter() { return LoggingMetricExporter.create(); } public static MetricExporter otlpJsonLoggingMetricExporter() { return OtlpJsonLoggingMetricExporter.create(); } }

Реалізуйте інтерфейс MetricExporter, щоб надати власну логіку експорту метрик. Наприклад:

package otel; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.MetricExporter; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; public class CustomMetricExporter implements MetricExporter { private static final Logger logger = Logger.getLogger(CustomMetricExporter.class.getName()); @Override public CompletableResultCode export(Collection<MetricData> metrics) { // Експортує записи. Зазвичай записи надсилаються за межі процесу через якийсь мережевий протокол, але // ми просто логуватимемо для ілюстрації. logger.log(Level.INFO, "Експортування метрик"); metrics.forEach(metric -> logger.log(Level.INFO, "Метрика: " + metric)); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode flush() { // Експортує будь-які записи, які були поставлені в чергу, але ще не експортовані. logger.log(Level.INFO, "очищення"); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode shutdown() { // Завершує роботу експортера та очищає будь-які ресурси. logger.log(Level.INFO, "завершення роботи"); return CompletableResultCode.ofSuccess(); } @Override public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { // Вказує необхідну агрегаційну тимчасовість як функцію типу інструменту return AggregationTemporalitySelector.deltaPreferred() .getAggregationTemporality(instrumentType); } @Override public MemoryMode getMemoryMode() { // Опціонально вказує режим пам'яті, вказуючи, чи можуть записи метрик бути повторно використані або повинні // бути незмінними return MemoryMode.REUSABLE_DATA; } @Override public Aggregation getDefaultAggregation(InstrumentType instrumentType) { // Опціонально вказує стандартну агрегацію як функцію типу інструменту return Aggregation.defaultAggregation(); } }

Views

Views дозволяють налаштовувати потоки метрик, включаючи зміну імен метрик, описів метрик, агрегацій метрик (тобто межі кошиків гістограми), набір ключів атрибутів для збереження, обмеження кардинальності тощо.

Наступний фрагмент коду демонструє програмну конфігурацію View:

package otel; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentSelector; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.View; import java.util.List; import java.util.Set; public class ViewConfig { public static SdkMeterProviderBuilder dropMetricView( SdkMeterProviderBuilder builder, String metricName) { return builder.registerView( InstrumentSelector.builder().setName(metricName).build(), View.builder().setAggregation(Aggregation.drop()).build()); } public static SdkMeterProviderBuilder histogramBucketBoundariesView( SdkMeterProviderBuilder builder, String metricName, List<Double> bucketBoundaries) { return builder.registerView( InstrumentSelector.builder().setName(metricName).build(), View.builder() .setAggregation(Aggregation.explicitBucketHistogram(bucketBoundaries)) .build()); } public static SdkMeterProviderBuilder attributeFilterView( SdkMeterProviderBuilder builder, String metricName, Set<String> keysToRetain) { return builder.registerView( InstrumentSelector.builder().setName(metricName).build(), View.builder().setAttributeFilter(keysToRetain).build()); } public static SdkMeterProviderBuilder cardinalityLimitsView( SdkMeterProviderBuilder builder, String metricName, int cardinalityLimit) { return builder.registerView( InstrumentSelector.builder().setName(metricName).build(), View.builder().setCardinalityLimit(cardinalityLimit).build()); } }

SdkLoggerProvider

SdkLoggerProvider є реалізацією SDK для LoggerProvider і відповідає за обробку логів, створених API логів.

SdkLoggerProvider налаштовується власником застосунку і складається з:

  • Resource: Ресурс, з яким асоціюються логи.
  • LogRecordProcessor: Обробляє логи, коли вони створюються.
  • LogRecordExporter: Експортує логи за межі процесу (у поєднанні з відповідним LogRecordProcessor).
  • LogLimits: Контролює обмеження даних, повʼязаних з логами.

Наступний фрагмент коду демонструє програмну конфігурацію SdkLoggerProvider:

package otel; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.resources.Resource; public class SdkLoggerProviderConfig { public static SdkLoggerProvider create(Resource resource) { return SdkLoggerProvider.builder() .setResource(resource) .addLogRecordProcessor( LogRecordProcessorConfig.batchLogRecordProcessor( LogRecordExporterConfig.otlpHttpLogRecordExporter("http://localhost:4318/v1/logs"))) .setLogLimits(LogLimitsConfig::logLimits) .build(); } }

LogRecordProcessor

LogRecordProcessor є інтерфейсом розширення плагінів з зворотним викликом, який викликається, коли лог створюється. Вони часто поєднуються з LogRecordExporters для експорту логів за межі процесу, але мають інші застосування, такі як збагачення даних.

Процесори логів, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
BatchLogRecordProcessorio.opentelemetry:opentelemetry-sdk:1.51.0Пакує логи та експортує їх через конфігурований LogRecordExporter.
SimpleLogRecordProcessorio.opentelemetry:opentelemetry-sdk:1.51.0Експортує кожен лог через конфігурований LogRecordExporter.
EventToSpanEventBridgeio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaЗаписує події логів як події відрізків на поточному відрізку.

Наступний фрагмент коду демонструє програмну конфігурацію LogRecordProcessor:

package otel; import io.opentelemetry.sdk.logs.LogRecordProcessor; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; import java.time.Duration; public class LogRecordProcessorConfig { public static LogRecordProcessor batchLogRecordProcessor(LogRecordExporter logRecordExporter) { return BatchLogRecordProcessor.builder(logRecordExporter) .setMaxQueueSize(2048) .setExporterTimeout(Duration.ofSeconds(30)) .setScheduleDelay(Duration.ofSeconds(1)) .build(); } public static LogRecordProcessor simpleLogRecordProcessor(LogRecordExporter logRecordExporter) { return SimpleLogRecordProcessor.create(logRecordExporter); } }

Реалізуйте інтерфейс LogRecordProcessor, щоб надати власну логіку обробки логів. Наприклад:

package otel; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.logs.LogRecordProcessor; import io.opentelemetry.sdk.logs.ReadWriteLogRecord; public class CustomLogRecordProcessor implements LogRecordProcessor { @Override public void onEmit(Context context, ReadWriteLogRecord logRecord) { // Викликається, коли лог створюється. // Збагачує запис користувацьким атрибутом. logRecord.setAttribute(AttributeKey.stringKey("my.custom.attribute"), "hello world"); } @Override public CompletableResultCode shutdown() { // Опціонально завершує роботу процесора та очищає будь-які ресурси. return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode forceFlush() { // Опціонально обробляє будь-які записи, які були поставлені в чергу, але ще не оброблені. return CompletableResultCode.ofSuccess(); } }

LogRecordExporter

LogRecordExporter є інтерфейсом розширення плагінів, відповідальним за експорт логів за межі процесу. Замість безпосередньої реєстрації з SdkLoggerProvider, вони поєднуються з LogRecordProcessors (зазвичай BatchLogRecordProcessor).

Експортери логів, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
OtlpHttpLogRecordExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.51.0Експортує логи через OTLP http/protobuf.
OtlpGrpcLogRecordExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.51.0Експортує логи через OTLP grpc.
SystemOutLogRecordExporterio.opentelemetry:opentelemetry-exporter-logging:1.51.0Логує логи до system out у форматі налагодження.
OtlpJsonLoggingLogRecordExporter [2]io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0Логує логи до JUL у кодуванні OTLP JSON.
OtlpStdoutLogRecordExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0Логує логи до System.out у OTLP JSON file encoding (експериментально).
InterceptableLogRecordExporterio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaПередає логи до гнучкого перехоплювача перед експортом.

[1]: Дивіться OTLP exporters для деталей реалізації.

[2]: OtlpJsonLoggingLogRecordExporter логує до JUL і може викликати нескінченні цикли (тобто JUL -> SLF4J -> Logback -> OpenTelemetry Appender -> OpenTelemetry Log SDK -> JUL), якщо не налаштований обережно.

Наступний фрагмент коду демонструє програмну конфігурацію LogRecordProcessor:

package otel; import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter; import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingLogRecordExporter; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import java.time.Duration; public class LogRecordExporterConfig { public static LogRecordExporter otlpHttpLogRecordExporter(String endpoint) { return OtlpHttpLogRecordExporter.builder() .setEndpoint(endpoint) .addHeader("api-key", "value") .setTimeout(Duration.ofSeconds(10)) .build(); } public static LogRecordExporter otlpGrpcLogRecordExporter(String endpoint) { return OtlpGrpcLogRecordExporter.builder() .setEndpoint(endpoint) .addHeader("api-key", "value") .setTimeout(Duration.ofSeconds(10)) .build(); } public static LogRecordExporter systemOutLogRecordExporter() { return SystemOutLogRecordExporter.create(); } public static LogRecordExporter otlpJsonLoggingLogRecordExporter() { return OtlpJsonLoggingLogRecordExporter.create(); } }

Реалізуйте інтерфейс LogRecordExporter, щоб надати власну логіку експорту логів. Наприклад:

package otel; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; public class CustomLogRecordExporter implements LogRecordExporter { private static final Logger logger = Logger.getLogger(CustomLogRecordExporter.class.getName()); @Override public CompletableResultCode export(Collection<LogRecordData> logs) { // Експортує записи. Зазвичай записи надсилаються за межі процесу через якийсь мережевий протокол, але // ми просто логуватимемо для ілюстрації. System.out.println("Експортування логів"); logs.forEach(log -> System.out.println("лог запис: " + log)); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode flush() { // Експортує будь-які записи, які були поставлені в чергу, але ще не експортовані. logger.log(Level.INFO, "очищення"); return CompletableResultCode.ofSuccess(); } @Override public CompletableResultCode shutdown() { // Завершує роботу експортера та очищає будь-які ресурси. logger.log(Level.INFO, "завершення роботи"); return CompletableResultCode.ofSuccess(); } }

LogLimits

LogLimits визначає обмеження для даних, захоплених логами, включаючи максимальну довжину атрибутів та максимальну кількість атрибутів.

Наступний фрагмент коду демонструє програмну конфігурацію LogRecordProcessor:

package otel; import io.opentelemetry.sdk.logs.LogLimits; public class LogLimitsConfig { public static LogLimits logLimits() { return LogLimits.builder() .setMaxNumberOfAttributes(128) .setMaxAttributeValueLength(1024) .build(); } }

TextMapPropagator

TextMapPropagator є інтерфейсом розширення плагінів, відповідальним за пропагування контексту через межі процесів у текстовому форматі.

TextMapPropagators, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib:

КласАртефактОпис
W3CTraceContextPropagatorio.opentelemetry:opentelemetry-api:1.51.0Поширює контекст трасування за допомогою протоколу поширення W3C trace context.
W3CBaggagePropagatorio.opentelemetry:opentelemetry-api:1.51.0Поширює багаж за допомогою протоколу поширення W3C baggage.
MultiTextMapPropagatorio.opentelemetry:opentelemetry-context:1.51.0Компонує кілька поширювачів.
JaegerPropagatorio.opentelemetry:opentelemetry-extension-trace-propagators:1.51.0Поширює контекст трасування за допомогою протоколу поширення Jaeger.
B3Propagatorio.opentelemetry:opentelemetry-extension-trace-propagators:1.51.0Поширює контекст трасування за допомогою протоколу поширення B3.
OtTracePropagatorio.opentelemetry:opentelemetry-extension-trace-propagators:1.51.0Поширює контекст трасування за допомогою протоколу поширення OpenTracing.
PassThroughPropagatorio.opentelemetry:opentelemetry-api-incubator:1.51.0-alphaПоширює конфігурований набір полів без участі в телеметрії.
AwsXrayPropagatorio.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.46.0-alphaПоширює контекст трасування за допомогою протоколу поширення AWS X-Ray.
AwsXrayLambdaPropagatorio.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.46.0-alphaПоширює контекст трасування за допомогою змінних середовища та протоколу поширення AWS X-Ray.

Наступний фрагмент коду демонструє програмну конфігурацію TextMapPropagator:

package otel; import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.context.propagation.TextMapPropagator; public class ContextPropagatorsConfig { public static ContextPropagators create() { return ContextPropagators.create( TextMapPropagator.composite( W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())); } }

Реалізуйте інтерфейс TextMapPropagator, щоб надати власну логіку пропагування. Наприклад:

package otel; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapGetter; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.context.propagation.TextMapSetter; import java.util.Collection; import java.util.Collections; public class CustomTextMapPropagator implements TextMapPropagator { @Override public Collection<String> fields() { // Повертає поля, які використовуються для пропагування. Дивіться W3CTraceContextPropagator для референсної реалізації. return Collections.emptyList(); } @Override public <C> void inject(Context context, C carrier, TextMapSetter<C> setter) { // Впроваджує контекст. Дивіться W3CTraceContextPropagator для референсної реалізації. } @Override public <C> Context extract(Context context, C carrier, TextMapGetter<C> getter) { // Витягує контекст. Дивіться W3CTraceContextPropagator для референсної реалізації. return context; } }

Додаток

Внутрішнє логування

Компоненти SDK логують різноманітну інформацію до java.util.logging, на різних рівнях логування та використовуючи імена логерів на основі повністю кваліфікованого імені класу відповідного компонента.

Стандартно, повідомлення логів обробляються кореневим обробником у вашому застосунку. Якщо ви не встановили користувацький кореневий обробник для вашого застосунку, логи рівня INFO або вище стандартно надсилаються до консолі.

Ви можете змінити поведінку логера для OpenTelemetry. Наприклад, ви можете зменшити рівень логування, щоб вивести додаткову інформацію під час налагодження, збільшити рівень для конкретного класу, щоб ігнорувати помилки, що надходять від цього класу, або встановити користувацький обробник або фільтр, щоб виконувати користувацький код щоразу, коли OpenTelemetry логує певне повідомлення. Детальний список імен логерів та інформації про логування не підтримується. Однак усі компоненти OpenTelemetry API, SDK, contrib та інструментування мають однаковий префікс пакунка io.opentelemetry.*. Може бути корисно увімкнути більш детальне логування для всіх io.opentelemetry.*, переглянути вивід та звузити до пакунків або FQCNs, що вас цікавлять.

Наприклад:

## Вимкнути все логування OpenTelemetry io.opentelemetry.level = OFF
## Вимкнути логування лише для BatchSpanProcessor io.opentelemetry.sdk.trace.export.BatchSpanProcessor.level = OFF
## Логувати повідомлення "FINE" для допомоги у налагодженні io.opentelemetry.level = FINE ## Встановлює рівень стандартного логера для ConsoleHandler ## Зверніть увагу, що це впливає на логування поза OpenTelemetry також java.util.logging.ConsoleHandler.level = FINE

Для більш детального контролю та спеціального оброблення можна вказати користувацькі обробники та фільтри за допомогою коду.

// Користувацький фільтр, який не логує помилки, що надходять від експорту public class IgnoreExportErrorsFilter implements java.util.logging.Filter { public boolean isLoggable(LogRecord record) { return !record.getMessage().contains("Exception thrown by the export"); } }
## Реєстрація користувацького фільтра на BatchSpanProcessor io.opentelemetry.sdk.trace.export.BatchSpanProcessor = io.opentelemetry.extension.logging.IgnoreExportErrorsFilter

Відправники OTLP експортерів

Розділи: експортер відрізків, експортер метрик та експортер логів описують OTLP експортери у формі:

  • OtlpHttp{Signal}Exporter експортує дані через OTLP http/protobuf.
  • OtlpGrpc{Signal}Exporter експортує дані через OTLP grpc.

Експортери для всіх сигналів доступні через io.opentelemetry:opentelemetry-exporter-otlp:1.51.0 і мають значний збіг між версіями grpc та http/protobuf протоколу OTLP протоколу OTLP, а також між сигналами. У наступних розділах детально розглянуто ці ключові поняття:

Відправники

Експортери залежать від різних клієнтських бібліотек для виконання HTTP та gRPC запитів. Немає єдиної клієнтської бібліотеки HTTP / gRPC, яка задовольняє всі випадки використання в екосистемі Java:

  • Java 11+ приносить вбудований java.net.http.HttpClient, але opentelemetry-java потрібно підтримувати користувачів Java 8+, і це не можна використовувати для експорту через gRPC, оскільки немає підтримки trailer header.
  • OkHttp надає потужний HTTP клієнт з підтримкою trailer header, але залежить від стандартної бібліотеки kotlin.
  • grpc-java надає власну абстракцію ManagedChannel з різними реалізаціями транспорту, але не підходить для http/protobuf.

Щоб задовольнити різні випадки використання, opentelemetry-exporter-otlp використовує внутрішню абстракцію “відправника” з різними реалізаціями, щоб відобразити обмеження застосунку. Щоб вибрати іншу реалізацію, виключіть стандартну залежність io.opentelemetry:opentelemetry-exporter-sender-okhttp та додайте залежність від альтернативи.

АртефактОписПротоколи OTLPСтандартно
io.opentelemetry:opentelemetry-exporter-sender-okhttp:1.51.0Реалізація на основі OkHttp.grpc, http/protobufТак
io.opentelemetry:opentelemetry-exporter-sender-jdk:1.51.0Реалізація на основі java.net.http.HttpClient Java 11+.http/protobufНі
io.opentelemetry:opentelemetry-exporter-sender-grpc-managed-channel:1.51.0 [1]Реалізація на основі ManagedChannel grpc-java.grpcНі

[1]: Щоб використовувати opentelemetry-exporter-sender-grpc-managed-channel, ви також повинні додати залежність від реалізацій транспорту gRPC.

Автентифікація

Експортери OTLP надають механізми для статичної та динамічної автентифікації на основі заголовків, а також для mTLS.

Якщо ви використовуєте zero-code SDK autoconfigure зі змінними середовища та системними властивостями, див. відповідні системні властивості:

  • otel.exporter.otlp.headers для статичної автентифікації на основі заголовків.
  • otel.exporter.otlp.client.key, otel.exporter.otlp.client.certificate для mTLS-автентифікації.

Наступний фрагмент коду демонструє програмне налаштування статичної та динамічної автентифікації на основі заголовків:

package otel; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import java.time.Duration; import java.time.Instant; import java.util.Collections; import java.util.Map; import java.util.function.Supplier; public class OtlpAuthenticationConfig { public static void staticAuthenticationHeader(String endpoint) { // Якщо адресат OTLP приймає статичний, довгоживучий заголовок автентифікації, наприклад, ключ API, // встановіть його як заголовок. // Це зчитує ключ API зі змінної env var OTLP_API_KEY, щоб уникнути жорсткого кодування секрету у // вихідному коді. String apiKeyHeaderName = "api-key"; String apiKeyHeaderValue = System.getenv("OTLP_API_KEY"); // Ініціалізуйте експортери OTLP Span, Metric та LogRecord за аналогічним шаблоном OtlpHttpSpanExporter spanExporter = OtlpHttpSpanExporter.builder() .setEndpoint(endpoint) .addHeader(apiKeyHeaderName, apiKeyHeaderValue) .build(); OtlpHttpMetricExporter metricExporter = OtlpHttpMetricExporter.builder() .setEndpoint(endpoint) .addHeader(apiKeyHeaderName, apiKeyHeaderValue) .build(); OtlpHttpLogRecordExporter logRecordExporter = OtlpHttpLogRecordExporter.builder() .setEndpoint(endpoint) .addHeader(apiKeyHeaderName, apiKeyHeaderValue) .build(); } public static void dynamicAuthenticationHeader(String endpoint) { // Якщо адресат OTLP вимагає динамічного заголовка автентифікації, наприклад, JWT, який потрібно // періодично оновлюватися, скористайтеся постачальником заголовків. // Тут ми реалізуємо простий постачальник, який додає заголовок виду "Authorization: Bearer // <token", де <token> зчитується з refreshBearerToken кожні 10 хвилин. String username = System.getenv("OTLP_USERNAME"); String password = System.getenv("OTLP_PASSWORD"); Supplier<Map<String, String>> supplier = new AuthHeaderSupplier(() -> refreshToken(username, password), Duration.ofMinutes(10)); // Ініціалізуйте експортери OTLP Span, Metric та LogRecord за аналогічним шаблоном OtlpHttpSpanExporter spanExporter = OtlpHttpSpanExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build(); OtlpHttpMetricExporter metricExporter = OtlpHttpMetricExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build(); OtlpHttpLogRecordExporter logRecordExporter = OtlpHttpLogRecordExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build(); } private static class AuthHeaderSupplier implements Supplier<Map<String, String>> { private final Supplier<String> tokenRefresher; private final Duration tokenRefreshInterval; private Instant refreshedAt = Instant.ofEpochMilli(0); private String currentTokenValue; private AuthHeaderSupplier(Supplier<String> tokenRefresher, Duration tokenRefreshInterval) { this.tokenRefresher = tokenRefresher; this.tokenRefreshInterval = tokenRefreshInterval; } @Override public Map<String, String> get() { return Collections.singletonMap("Authorization", "Bearer " + getToken()); } private synchronized String getToken() { Instant now = Instant.now(); if (currentTokenValue == null || now.isAfter(refreshedAt.plus(tokenRefreshInterval))) { currentTokenValue = tokenRefresher.get(); refreshedAt = now; } return currentTokenValue; } } private static String refreshToken(String username, String password) { // Для сценарію промислового використання це буде замінено на позасмуговий запит на обмін // імʼя користувача / пароль для токена на предʼявника. return "abc123"; } }

Тестування

TODO: документувати інструменти, доступні для тестування SDK


Востаннє змінено June 21, 2025: [uk] sync with upstream (2d6f8511)