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