Керування телеметрією за допомогою 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, з якими працює користувач. Кожен розділ компонентів включає:
- Короткий опис, включаючи посилання на тип Javadoc.
- Якщо компонент є інтерфейсом розширення втулків, таблицю доступних вбудованих та
opentelemetry-java-contrib
реалізацій. - Просту демонстрацію програмної конфігурації.
- Якщо компонент є інтерфейсом розширення втулків, просту демонстрацію користувацької реалізації.
OpenTelemetrySdk
OpenTelemetrySdk є реалізацією SDK для OpenTelemetry. Це контейнер для основних компонентів SDK, який робить зручним передавання повністю налаштованих компонентів SDK для інструментування.
OpenTelemetrySdk
налаштовується власником додатку і складається з:
- SdkTracerProvider: Реалізація SDK для
TracerProvider
. - SdkMeterProvider: Реалізація SDK для
MeterProvider
. - SdkLoggerProvider: Реалізація SDK для
LoggerProvider
. - ContextPropagators: Пропагує контекст через межі процесів.
Наступний фрагмент коду демонструє програмну конфігурацію 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.
ResourceProviders додають контекстну інформацію до автоконфігурованого ресурсу на основі середовища. Дивіться документацію для списку доступних ResourceProvider
.
Наступний фрагмент коду демонструє програмну конфігурацію 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 є інтерфейсом розширення плагінів, відповідальним за визначення, які відрізки записуються та семплюються.
Стандартно SdkTracerProvider
налаштований з семплером ParentBased(root=AlwaysOn)
. Це призводить до того, що 100% відрізків семплюються, якщо застосунок, що викликає, не виконує семплінг. Якщо це занадто шумно/дорого, змініть семплер.
Семплери, вбудовані в SDK та підтримувані спільнотою в opentelemetry-java-contrib
:
Клас | Артефакт | Опис |
---|---|---|
ParentBased | io.opentelemetry:opentelemetry-sdk:1.51.0 | Семплює відрізки на основі статусу семплінгу батьківського відрізка. |
AlwaysOn | io.opentelemetry:opentelemetry-sdk:1.51.0 | Семплює всі відрізки. |
AlwaysOff | io.opentelemetry:opentelemetry-sdk:1.51.0 | Відкидає всі відрізки. |
TraceIdRatioBased | io.opentelemetry:opentelemetry-sdk:1.51.0 | Семплює відрізки на основі конфігурованого співвідношення. |
JaegerRemoteSampler | io.opentelemetry:opentelemetry-sdk-extension-jaeger-remote-sampler:1.51.0 | Семплює відрізки на основі конфігурації з віддаленого сервера. |
LinksBasedSampler | io.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alpha | Семплює відрізки на основі статусу семплінгу посилань відрізка. |
RuleBasedRoutingSampler | io.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alpha | Семплює відрізки на основі конфігурованих правил. |
ConsistentSamplers | io.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
:
Клас | Артефакт | Опис |
---|---|---|
BatchSpanProcessor | io.opentelemetry:opentelemetry-sdk:1.51.0 | Пакує семпльовані відрізки та експортує їх через конфігурований SpanExporter . |
SimpleSpanProcessor | io.opentelemetry:opentelemetry-sdk:1.51.0 | Експортує кожен семпльований відрізок через конфігурований SpanExporter . |
BaggageSpanProcessor | io.opentelemetry.contrib:opentelemetry-baggage-processor:1.46.0-alpha | Збагачує відрізки багажем. |
JfrSpanProcessor | io.opentelemetry.contrib:opentelemetry-jfr-events:1.46.0-alpha | Створює події JFR зі відрізків. |
StackTraceSpanProcessor | io.opentelemetry.contrib:opentelemetry-span-stacktrace:1.46.0-alpha | Збагачує вибрані відрізки даними стеку викликів. |
InferredSpansProcessor | io.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 . |
LoggingSpanExporter | io.opentelemetry:opentelemetry-exporter-logging:1.51.0 | Логує відрізки до JUL у форматі налагодження. |
OtlpJsonLoggingSpanExporter | io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0 | Логує відрізки до JUL у кодуванні OTLP JSON. |
OtlpStdoutSpanExporter | io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0 | Логує відрізки до System.out у OTLP JSON file encoding (експериментально). |
ZipkinSpanExporter | io.opentelemetry:opentelemetry-exporter-zipkin:1.51.0 | Експортує відрізки до Zipkin. |
InterceptableSpanExporter | io.opentelemetry.contrib:opentelemetry-processors:1.46.0-alpha | Передає відрізки до гнучкого перехоплювача перед експортом. |
KafkaSpanExporter | io.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
:
Клас | Артефакт | Опис |
---|---|---|
PeriodicMetricReader | io.opentelemetry:opentelemetry-sdk:1.51.0 | Читає метрики на періодичній основі та експортує їх через конфігурований MetricExporter . |
PrometheusHttpServer | io.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 . |
LoggingMetricExporter | io.opentelemetry:opentelemetry-exporter-logging:1.51.0 | Логує метрики до JUL у форматі налагодження. |
OtlpJsonLoggingMetricExporter | io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0 | Логує метрики до JUL у кодуванні OTLP JSON. |
OtlpStdoutMetricExporter | io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0 | Логує метрики до System.out у OTLP JSON file encoding (експериментально). |
InterceptableMetricExporter | io.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
:
Клас | Артефакт | Опис |
---|---|---|
BatchLogRecordProcessor | io.opentelemetry:opentelemetry-sdk:1.51.0 | Пакує логи та експортує їх через конфігурований LogRecordExporter . |
SimpleLogRecordProcessor | io.opentelemetry:opentelemetry-sdk:1.51.0 | Експортує кожен лог через конфігурований LogRecordExporter . |
EventToSpanEventBridge | io.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 . |
SystemOutLogRecordExporter | io.opentelemetry:opentelemetry-exporter-logging:1.51.0 | Логує логи до system out у форматі налагодження. |
OtlpJsonLoggingLogRecordExporter [2] | io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0 | Логує логи до JUL у кодуванні OTLP JSON. |
OtlpStdoutLogRecordExporter | io.opentelemetry:opentelemetry-exporter-logging-otlp:1.51.0 | Логує логи до System.out у OTLP JSON file encoding (експериментально). |
InterceptableLogRecordExporter | io.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
:
Клас | Артефакт | Опис |
---|---|---|
W3CTraceContextPropagator | io.opentelemetry:opentelemetry-api:1.51.0 | Поширює контекст трасування за допомогою протоколу поширення W3C trace context. |
W3CBaggagePropagator | io.opentelemetry:opentelemetry-api:1.51.0 | Поширює багаж за допомогою протоколу поширення W3C baggage. |
MultiTextMapPropagator | io.opentelemetry:opentelemetry-context:1.51.0 | Компонує кілька поширювачів. |
JaegerPropagator | io.opentelemetry:opentelemetry-extension-trace-propagators:1.51.0 | Поширює контекст трасування за допомогою протоколу поширення Jaeger. |
B3Propagator | io.opentelemetry:opentelemetry-extension-trace-propagators:1.51.0 | Поширює контекст трасування за допомогою протоколу поширення B3. |
OtTracePropagator | io.opentelemetry:opentelemetry-extension-trace-propagators:1.51.0 | Поширює контекст трасування за допомогою протоколу поширення OpenTracing. |
PassThroughPropagator | io.opentelemetry:opentelemetry-api-incubator:1.51.0-alpha | Поширює конфігурований набір полів без участі в телеметрії. |
AwsXrayPropagator | io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.46.0-alpha | Поширює контекст трасування за допомогою протоколу поширення AWS X-Ray. |
AwsXrayLambdaPropagator | io.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
експортує дані через OTLPhttp/protobuf
.OtlpGrpc{Signal}Exporter
експортує дані через OTLPgrpc
.
Експортери для всіх сигналів доступні через io.opentelemetry:opentelemetry-exporter-otlp:1.51.0
і мають значний збіг між версіями grpc
та http/protobuf
протоколу OTLP протоколу OTLP, а також між сигналами. У наступних розділах детально розглянуто ці ключові поняття:
- Відправники: абстракція для різних клієнтських бібліотек HTTP / gRPC.
- Автентифікація: опції для експортерів 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
Відгук
Чи це було корисним?
Дякуємо. Ми цінуємо ваші відгуки!
Будь ласка, дайте нам знати як ми можемо покращити цю сторінку. Ми цінуємо ваші відгуки!