001package io.prometheus.metrics.exporter.opentelemetry; 002 003import io.opentelemetry.sdk.metrics.export.MetricReader; 004import io.prometheus.metrics.config.PrometheusProperties; 005import io.prometheus.metrics.model.registry.PrometheusRegistry; 006import java.util.HashMap; 007import java.util.Map; 008import javax.annotation.Nullable; 009 010public class OpenTelemetryExporter implements AutoCloseable { 011 private final MetricReader reader; 012 013 public OpenTelemetryExporter(MetricReader reader) { 014 this.reader = reader; 015 } 016 017 @Override 018 public void close() { 019 reader.shutdown(); 020 } 021 022 public static Builder builder() { 023 return new Builder(PrometheusProperties.get()); 024 } 025 026 public static Builder builder(PrometheusProperties config) { 027 return new Builder(config); 028 } 029 030 public static class Builder { 031 032 private final PrometheusProperties config; 033 @Nullable private PrometheusRegistry registry = null; 034 @Nullable String protocol; 035 @Nullable String endpoint; 036 final Map<String, String> headers = new HashMap<>(); 037 @Nullable String interval; 038 @Nullable String timeout; 039 @Nullable String serviceName; 040 @Nullable String serviceNamespace; 041 @Nullable String serviceInstanceId; 042 @Nullable String serviceVersion; 043 final Map<String, String> resourceAttributes = new HashMap<>(); 044 045 private Builder(PrometheusProperties config) { 046 this.config = config; 047 } 048 049 public Builder registry(PrometheusRegistry registry) { 050 this.registry = registry; 051 return this; 052 } 053 054 /** 055 * Specifies the OTLP transport protocol to be used when exporting metrics. 056 * 057 * <p>Supported values are {@code "grpc"} and {@code "http/protobuf"}. Default is {@code 058 * "grpc"}. 059 * 060 * <p>See OpenTelemetry's <a 061 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_protocol">OTEL_EXPORTER_OTLP_PROTOCOL</a>. 062 */ 063 public Builder protocol(String protocol) { 064 if (!protocol.equals("grpc") && !protocol.equals("http/protobuf")) { 065 throw new IllegalArgumentException( 066 protocol + ": Unsupported protocol. Expecting grpc or http/protobuf"); 067 } 068 this.protocol = protocol; 069 return this; 070 } 071 072 /** 073 * The OTLP endpoint to send metric data to. 074 * 075 * <p>The default depends on the protocol: 076 * 077 * <ul> 078 * <li>{@code "grpc"}: {@code "http://localhost:4317"} 079 * <li>{@code "http/protobuf"}: {@code "http://localhost:4318/v1/metrics"} 080 * </ul> 081 * 082 * If the protocol is {@code "http/protobuf"} and the endpoint does not have the {@code 083 * "/v1/metrics"} suffix, the {@code "/v1/metrics"} suffix will automatically be appended. 084 * 085 * <p>See OpenTelemetry's <a 086 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_metrics_endpoint">OTEL_EXPORTER_OTLP_METRICS_ENDPOINT</a>. 087 */ 088 public Builder endpoint(String endpoint) { 089 this.endpoint = endpoint; 090 return this; 091 } 092 093 /** 094 * Add an HTTP header to be applied to outgoing requests. Call multiple times to add multiple 095 * headers. 096 * 097 * <p>See OpenTelemetry's <a 098 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_headers">OTEL_EXPORTER_OTLP_HEADERS</a>. 099 */ 100 public Builder header(String name, String value) { 101 this.headers.put(name, value); 102 return this; 103 } 104 105 /** 106 * The interval between the start of two export attempts. Default is 60000. 107 * 108 * <p>Like OpenTelemetry's <a 109 * href="https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#periodic-metric-reader">OTEL_METRIC_EXPORT_INTERVAL</a>, 110 * but in seconds rather than milliseconds. 111 */ 112 public Builder intervalSeconds(int intervalSeconds) { 113 if (intervalSeconds <= 0) { 114 throw new IllegalStateException(intervalSeconds + ": expecting a push interval > 0s"); 115 } 116 this.interval = intervalSeconds + "s"; 117 return this; 118 } 119 120 /** 121 * The timeout for outgoing requests. Default is 10. 122 * 123 * <p>Like OpenTelemetry's <a 124 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_metrics_timeout">OTEL_EXPORTER_OTLP_METRICS_TIMEOUT</a>, 125 * but in seconds rather than milliseconds. 126 */ 127 public Builder timeoutSeconds(int timeoutSeconds) { 128 if (timeoutSeconds <= 0) { 129 throw new IllegalStateException(timeoutSeconds + ": expecting a push interval > 0s"); 130 } 131 this.timeout = timeoutSeconds + "s"; 132 return this; 133 } 134 135 /** 136 * The {@code service.name} resource attribute. 137 * 138 * <p>If not explicitly specified, {@code client_java} will try to initialize it with a 139 * reasonable default, like the JAR file name. 140 * 141 * <p>See {@code service.name} in OpenTelemetry's <a 142 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service">Resource 143 * Semantic Conventions</a>. 144 */ 145 public Builder serviceName(String serviceName) { 146 this.serviceName = serviceName; 147 return this; 148 } 149 150 /** 151 * The {@code service.namespace} resource attribute. 152 * 153 * <p>See {@code service.namespace} in OpenTelemetry's <a 154 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service-experimental">Resource 155 * Semantic Conventions</a>. 156 */ 157 public Builder serviceNamespace(String serviceNamespace) { 158 this.serviceNamespace = serviceNamespace; 159 return this; 160 } 161 162 /** 163 * The {@code service.instance.id} resource attribute. 164 * 165 * <p>See {@code service.instance.id} in OpenTelemetry's <a 166 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service-experimental">Resource 167 * Semantic Conventions</a>. 168 */ 169 public Builder serviceInstanceId(String serviceInstanceId) { 170 this.serviceInstanceId = serviceInstanceId; 171 return this; 172 } 173 174 /** 175 * The {@code service.version} resource attribute. 176 * 177 * <p>See {@code service.version} in OpenTelemetry's <a 178 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service-experimental">Resource 179 * Semantic Conventions</a>. 180 */ 181 public Builder serviceVersion(String serviceVersion) { 182 this.serviceVersion = serviceVersion; 183 return this; 184 } 185 186 /** 187 * Add a resource attribute. Call multiple times to add multiple resource attributes. 188 * 189 * <p>See OpenTelemetry's <a 190 * href="https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration">OTEL_RESOURCE_ATTRIBUTES</a>. 191 */ 192 public Builder resourceAttribute(String name, String value) { 193 this.resourceAttributes.put(name, value); 194 return this; 195 } 196 197 public OpenTelemetryExporter buildAndStart() { 198 if (registry == null) { 199 registry = PrometheusRegistry.defaultRegistry; 200 } 201 return new OpenTelemetryExporter(OtelAutoConfig.createReader(this, config, registry)); 202 } 203 } 204}