001package io.prometheus.metrics.config; 002 003import java.util.HashMap; 004import java.util.Map; 005import javax.annotation.Nullable; 006 007/** 008 * Properties for configuring the OpenTelemetry exporter. 009 * 010 * <p>These properties can be configured via {@code prometheus.properties}, system properties, or 011 * programmatically. 012 * 013 * <p>All properties are prefixed with {@code io.prometheus.exporter.opentelemetry}. 014 * 015 * <p>Available properties: 016 * 017 * <ul> 018 * <li>{@code protocol} - OTLP protocol: {@code "grpc"} or {@code "http/protobuf"} 019 * <li>{@code endpoint} - OTLP endpoint URL 020 * <li>{@code headers} - HTTP headers for outgoing requests 021 * <li>{@code intervalSeconds} - Export interval in seconds 022 * <li>{@code timeoutSeconds} - Request timeout in seconds 023 * <li>{@code serviceName} - Service name resource attribute 024 * <li>{@code serviceNamespace} - Service namespace resource attribute 025 * <li>{@code serviceInstanceId} - Service instance ID resource attribute 026 * <li>{@code serviceVersion} - Service version resource attribute 027 * <li>{@code resourceAttributes} - Additional resource attributes 028 * </ul> 029 * 030 * @see <a 031 * href="https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/">OpenTelemetry 032 * SDK Environment Variables</a> 033 */ 034public class ExporterOpenTelemetryProperties { 035 036 // See 037 // https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md 038 private static final String PROTOCOL = "protocol"; // otel.exporter.otlp.protocol 039 private static final String ENDPOINT = "endpoint"; // otel.exporter.otlp.endpoint 040 private static final String HEADERS = "headers"; // otel.exporter.otlp.headers 041 private static final String INTERVAL_SECONDS = "interval_seconds"; // otel.metric.export.interval 042 private static final String TIMEOUT_SECONDS = "timeout_seconds"; // otel.exporter.otlp.timeout 043 private static final String SERVICE_NAME = "service_name"; // otel.service.name 044 private static final String SERVICE_NAMESPACE = "service_namespace"; 045 private static final String SERVICE_INSTANCE_ID = "service_instance_id"; 046 private static final String SERVICE_VERSION = "service_version"; 047 private static final String RESOURCE_ATTRIBUTES = 048 "resource_attributes"; // otel.resource.attributes 049 private static final String PREFIX = "io.prometheus.exporter.opentelemetry"; 050 051 @Nullable private final String endpoint; 052 @Nullable private final String protocol; 053 private final Map<String, String> headers; 054 @Nullable private final String interval; 055 @Nullable private final String timeout; 056 @Nullable private final String serviceName; 057 @Nullable private final String serviceNamespace; 058 @Nullable private final String serviceInstanceId; 059 @Nullable private final String serviceVersion; 060 private final Map<String, String> resourceAttributes; 061 062 private ExporterOpenTelemetryProperties( 063 @Nullable String protocol, 064 @Nullable String endpoint, 065 Map<String, String> headers, 066 @Nullable String interval, 067 @Nullable String timeout, 068 @Nullable String serviceName, 069 @Nullable String serviceNamespace, 070 @Nullable String serviceInstanceId, 071 @Nullable String serviceVersion, 072 Map<String, String> resourceAttributes) { 073 this.protocol = protocol; 074 this.endpoint = endpoint; 075 this.headers = headers; 076 this.interval = interval; 077 this.timeout = timeout; 078 this.serviceName = serviceName; 079 this.serviceNamespace = serviceNamespace; 080 this.serviceInstanceId = serviceInstanceId; 081 this.serviceVersion = serviceVersion; 082 this.resourceAttributes = resourceAttributes; 083 } 084 085 @Nullable 086 public String getProtocol() { 087 return protocol; 088 } 089 090 @Nullable 091 public String getEndpoint() { 092 return endpoint; 093 } 094 095 public Map<String, String> getHeaders() { 096 return headers; 097 } 098 099 @Nullable 100 public String getInterval() { 101 return interval; 102 } 103 104 @Nullable 105 public String getTimeout() { 106 return timeout; 107 } 108 109 @Nullable 110 public String getServiceName() { 111 return serviceName; 112 } 113 114 @Nullable 115 public String getServiceNamespace() { 116 return serviceNamespace; 117 } 118 119 @Nullable 120 public String getServiceInstanceId() { 121 return serviceInstanceId; 122 } 123 124 @Nullable 125 public String getServiceVersion() { 126 return serviceVersion; 127 } 128 129 public Map<String, String> getResourceAttributes() { 130 return resourceAttributes; 131 } 132 133 /** 134 * Note that this will remove entries from {@code propertySource}. This is because we want to know 135 * if there are unused properties remaining after all properties have been loaded. 136 */ 137 static ExporterOpenTelemetryProperties load(PropertySource propertySource) 138 throws PrometheusPropertiesException { 139 String protocol = Util.loadString(PREFIX, PROTOCOL, propertySource); 140 String endpoint = Util.loadString(PREFIX, ENDPOINT, propertySource); 141 Map<String, String> headers = Util.loadMap(PREFIX, HEADERS, propertySource); 142 String interval = Util.loadStringAddSuffix(PREFIX, INTERVAL_SECONDS, propertySource, "s"); 143 String timeout = Util.loadStringAddSuffix(PREFIX, TIMEOUT_SECONDS, propertySource, "s"); 144 String serviceName = Util.loadString(PREFIX, SERVICE_NAME, propertySource); 145 String serviceNamespace = Util.loadString(PREFIX, SERVICE_NAMESPACE, propertySource); 146 String serviceInstanceId = Util.loadString(PREFIX, SERVICE_INSTANCE_ID, propertySource); 147 String serviceVersion = Util.loadString(PREFIX, SERVICE_VERSION, propertySource); 148 Map<String, String> resourceAttributes = 149 Util.loadMap(PREFIX, RESOURCE_ATTRIBUTES, propertySource); 150 return new ExporterOpenTelemetryProperties( 151 protocol, 152 endpoint, 153 headers, 154 interval, 155 timeout, 156 serviceName, 157 serviceNamespace, 158 serviceInstanceId, 159 serviceVersion, 160 resourceAttributes); 161 } 162 163 public static Builder builder() { 164 return new Builder(); 165 } 166 167 public static class Builder { 168 169 @Nullable private String protocol; 170 @Nullable private String endpoint; 171 private final Map<String, String> headers = new HashMap<>(); 172 @Nullable private String interval; 173 @Nullable private String timeout; 174 @Nullable private String serviceName; 175 @Nullable private String serviceNamespace; 176 @Nullable private String serviceInstanceId; 177 @Nullable private String serviceVersion; 178 private final Map<String, String> resourceAttributes = new HashMap<>(); 179 180 private Builder() {} 181 182 /** 183 * The OTLP protocol to use. 184 * 185 * <p>Supported values: {@code "grpc"} or {@code "http/protobuf"}. 186 * 187 * <p>See OpenTelemetry's <a 188 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_protocol">OTEL_EXPORTER_OTLP_PROTOCOL</a>. 189 */ 190 public Builder protocol(String protocol) { 191 if (!protocol.equals("grpc") && !protocol.equals("http/protobuf")) { 192 throw new IllegalArgumentException( 193 protocol + ": Unsupported protocol. Expecting grpc or http/protobuf"); 194 } 195 this.protocol = protocol; 196 return this; 197 } 198 199 /** 200 * The OTLP endpoint to send metric data to. 201 * 202 * <p>The default depends on the protocol: 203 * 204 * <ul> 205 * <li>{@code "grpc"}: {@code "http://localhost:4317"} 206 * <li>{@code "http/protobuf"}: {@code "http://localhost:4318/v1/metrics"} 207 * </ul> 208 * 209 * <p>See OpenTelemetry's <a 210 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_metrics_endpoint">OTEL_EXPORTER_OTLP_METRICS_ENDPOINT</a>. 211 */ 212 public Builder endpoint(String endpoint) { 213 this.endpoint = endpoint; 214 return this; 215 } 216 217 /** 218 * Add an HTTP header to be applied to outgoing requests. Call multiple times to add multiple 219 * headers. 220 * 221 * <p>See OpenTelemetry's <a 222 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_headers">OTEL_EXPORTER_OTLP_HEADERS</a>. 223 */ 224 public Builder header(String name, String value) { 225 this.headers.put(name, value); 226 return this; 227 } 228 229 /** 230 * The interval between the start of two export attempts. Default is 60 seconds. 231 * 232 * <p>Like OpenTelemetry's <a 233 * href="https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#periodic-metric-reader">OTEL_METRIC_EXPORT_INTERVAL</a> 234 * (which defaults to 60000 milliseconds), but specified in seconds rather than milliseconds. 235 */ 236 public Builder intervalSeconds(int intervalSeconds) { 237 if (intervalSeconds <= 0) { 238 throw new IllegalArgumentException(intervalSeconds + ": Expecting intervalSeconds > 0"); 239 } 240 this.interval = intervalSeconds + "s"; 241 return this; 242 } 243 244 /** 245 * The timeout for outgoing requests. Default is 10. 246 * 247 * <p>Like OpenTelemetry's <a 248 * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_metrics_timeout">OTEL_EXPORTER_OTLP_METRICS_TIMEOUT</a>, 249 * but in seconds rather than milliseconds. 250 */ 251 public Builder timeoutSeconds(int timeoutSeconds) { 252 if (timeoutSeconds <= 0) { 253 throw new IllegalArgumentException(timeoutSeconds + ": Expecting timeoutSeconds > 0"); 254 } 255 this.timeout = timeoutSeconds + "s"; 256 return this; 257 } 258 259 /** 260 * The {@code service.name} resource attribute. 261 * 262 * <p>If not explicitly specified, {@code client_java} will try to initialize it with a 263 * reasonable default, like the JAR file name. 264 * 265 * <p>See {@code service.name} in OpenTelemetry's <a 266 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service">Resource 267 * Semantic Conventions</a>. 268 */ 269 public Builder serviceName(String serviceName) { 270 this.serviceName = serviceName; 271 return this; 272 } 273 274 /** 275 * The {@code service.namespace} resource attribute. 276 * 277 * <p>See {@code service.namespace} in OpenTelemetry's <a 278 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service-experimental">Resource 279 * Semantic Conventions</a>. 280 */ 281 public Builder serviceNamespace(String serviceNamespace) { 282 this.serviceNamespace = serviceNamespace; 283 return this; 284 } 285 286 /** 287 * The {@code service.instance.id} resource attribute. 288 * 289 * <p>See {@code service.instance.id} in OpenTelemetry's <a 290 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service-experimental">Resource 291 * Semantic Conventions</a>. 292 */ 293 public Builder serviceInstanceId(String serviceInstanceId) { 294 this.serviceInstanceId = serviceInstanceId; 295 return this; 296 } 297 298 /** 299 * The {@code service.version} resource attribute. 300 * 301 * <p>See {@code service.version} in OpenTelemetry's <a 302 * href="https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/#service-experimental">Resource 303 * Semantic Conventions</a>. 304 */ 305 public Builder serviceVersion(String serviceVersion) { 306 this.serviceVersion = serviceVersion; 307 return this; 308 } 309 310 /** 311 * Add a resource attribute. Call multiple times to add multiple resource attributes. 312 * 313 * <p>See OpenTelemetry's <a 314 * href="https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration">OTEL_RESOURCE_ATTRIBUTES</a>. 315 */ 316 public Builder resourceAttribute(String name, String value) { 317 this.resourceAttributes.put(name, value); 318 return this; 319 } 320 321 public ExporterOpenTelemetryProperties build() { 322 return new ExporterOpenTelemetryProperties( 323 protocol, 324 endpoint, 325 headers, 326 interval, 327 timeout, 328 serviceName, 329 serviceNamespace, 330 serviceInstanceId, 331 serviceVersion, 332 resourceAttributes); 333 } 334 } 335}