001package io.prometheus.metrics.config;
002
003import java.util.HashMap;
004import java.util.Map;
005import javax.annotation.Nullable;
006
007// TODO: JavaDoc is currently only in OpenTelemetryExporter.Builder. Look there for reference.
008public class ExporterOpenTelemetryProperties {
009
010  // See
011  // https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md
012  private static final String PROTOCOL = "protocol"; // otel.exporter.otlp.protocol
013  private static final String ENDPOINT = "endpoint"; // otel.exporter.otlp.endpoint
014  private static final String HEADERS = "headers"; // otel.exporter.otlp.headers
015  private static final String INTERVAL_SECONDS = "intervalSeconds"; // otel.metric.export.interval
016  private static final String TIMEOUT_SECONDS = "timeoutSeconds"; // otel.exporter.otlp.timeout
017  private static final String SERVICE_NAME = "serviceName"; // otel.service.name
018  private static final String SERVICE_NAMESPACE = "serviceNamespace";
019  private static final String SERVICE_INSTANCE_ID = "serviceInstanceId";
020  private static final String SERVICE_VERSION = "serviceVersion";
021  private static final String RESOURCE_ATTRIBUTES =
022      "resourceAttributes"; // otel.resource.attributes
023  private static final String PREFIX = "io.prometheus.exporter.opentelemetry";
024
025  @Nullable private final String endpoint;
026  @Nullable private final String protocol;
027  private final Map<String, String> headers;
028  @Nullable private final String interval;
029  @Nullable private final String timeout;
030  @Nullable private final String serviceName;
031  @Nullable private final String serviceNamespace;
032  @Nullable private final String serviceInstanceId;
033  @Nullable private final String serviceVersion;
034  private final Map<String, String> resourceAttributes;
035
036  private ExporterOpenTelemetryProperties(
037      @Nullable String protocol,
038      @Nullable String endpoint,
039      Map<String, String> headers,
040      @Nullable String interval,
041      @Nullable String timeout,
042      @Nullable String serviceName,
043      @Nullable String serviceNamespace,
044      @Nullable String serviceInstanceId,
045      @Nullable String serviceVersion,
046      Map<String, String> resourceAttributes) {
047    this.protocol = protocol;
048    this.endpoint = endpoint;
049    this.headers = headers;
050    this.interval = interval;
051    this.timeout = timeout;
052    this.serviceName = serviceName;
053    this.serviceNamespace = serviceNamespace;
054    this.serviceInstanceId = serviceInstanceId;
055    this.serviceVersion = serviceVersion;
056    this.resourceAttributes = resourceAttributes;
057  }
058
059  @Nullable
060  public String getProtocol() {
061    return protocol;
062  }
063
064  @Nullable
065  public String getEndpoint() {
066    return endpoint;
067  }
068
069  public Map<String, String> getHeaders() {
070    return headers;
071  }
072
073  @Nullable
074  public String getInterval() {
075    return interval;
076  }
077
078  @Nullable
079  public String getTimeout() {
080    return timeout;
081  }
082
083  @Nullable
084  public String getServiceName() {
085    return serviceName;
086  }
087
088  @Nullable
089  public String getServiceNamespace() {
090    return serviceNamespace;
091  }
092
093  @Nullable
094  public String getServiceInstanceId() {
095    return serviceInstanceId;
096  }
097
098  @Nullable
099  public String getServiceVersion() {
100    return serviceVersion;
101  }
102
103  public Map<String, String> getResourceAttributes() {
104    return resourceAttributes;
105  }
106
107  /**
108   * Note that this will remove entries from {@code properties}. This is because we want to know if
109   * there are unused properties remaining after all properties have been loaded.
110   */
111  static ExporterOpenTelemetryProperties load(Map<Object, Object> properties)
112      throws PrometheusPropertiesException {
113    String protocol = Util.loadString(PREFIX + "." + PROTOCOL, properties);
114    String endpoint = Util.loadString(PREFIX + "." + ENDPOINT, properties);
115    Map<String, String> headers = Util.loadMap(PREFIX + "." + HEADERS, properties);
116    String interval = Util.loadStringAddSuffix(PREFIX + "." + INTERVAL_SECONDS, properties, "s");
117    String timeout = Util.loadStringAddSuffix(PREFIX + "." + TIMEOUT_SECONDS, properties, "s");
118    String serviceName = Util.loadString(PREFIX + "." + SERVICE_NAME, properties);
119    String serviceNamespace = Util.loadString(PREFIX + "." + SERVICE_NAMESPACE, properties);
120    String serviceInstanceId = Util.loadString(PREFIX + "." + SERVICE_INSTANCE_ID, properties);
121    String serviceVersion = Util.loadString(PREFIX + "." + SERVICE_VERSION, properties);
122    Map<String, String> resourceAttributes =
123        Util.loadMap(PREFIX + "." + RESOURCE_ATTRIBUTES, properties);
124    return new ExporterOpenTelemetryProperties(
125        protocol,
126        endpoint,
127        headers,
128        interval,
129        timeout,
130        serviceName,
131        serviceNamespace,
132        serviceInstanceId,
133        serviceVersion,
134        resourceAttributes);
135  }
136
137  public static Builder builder() {
138    return new Builder();
139  }
140
141  public static class Builder {
142
143    @Nullable private String protocol;
144    @Nullable private String endpoint;
145    private final Map<String, String> headers = new HashMap<>();
146    @Nullable private String interval;
147    @Nullable private String timeout;
148    @Nullable private String serviceName;
149    @Nullable private String serviceNamespace;
150    @Nullable private String serviceInstanceId;
151    @Nullable private String serviceVersion;
152    private final Map<String, String> resourceAttributes = new HashMap<>();
153
154    private Builder() {}
155
156    public Builder protocol(String protocol) {
157      if (!protocol.equals("grpc") && !protocol.equals("http/protobuf")) {
158        throw new IllegalArgumentException(
159            protocol + ": Unsupported protocol. Expecting grpc or http/protobuf");
160      }
161      this.protocol = protocol;
162      return this;
163    }
164
165    public Builder endpoint(String endpoint) {
166      this.endpoint = endpoint;
167      return this;
168    }
169
170    /** Add a request header. Call multiple times to add multiple headers. */
171    public Builder header(String name, String value) {
172      this.headers.put(name, value);
173      return this;
174    }
175
176    public Builder intervalSeconds(int intervalSeconds) {
177      if (intervalSeconds <= 0) {
178        throw new IllegalArgumentException(intervalSeconds + ": Expecting intervalSeconds > 0");
179      }
180      this.interval = intervalSeconds + "s";
181      return this;
182    }
183
184    public Builder timeoutSeconds(int timeoutSeconds) {
185      if (timeoutSeconds <= 0) {
186        throw new IllegalArgumentException(timeoutSeconds + ": Expecting timeoutSeconds > 0");
187      }
188      this.timeout = timeoutSeconds + "s";
189      return this;
190    }
191
192    public Builder serviceName(String serviceName) {
193      this.serviceName = serviceName;
194      return this;
195    }
196
197    public Builder serviceNamespace(String serviceNamespace) {
198      this.serviceNamespace = serviceNamespace;
199      return this;
200    }
201
202    public Builder serviceInstanceId(String serviceInstanceId) {
203      this.serviceInstanceId = serviceInstanceId;
204      return this;
205    }
206
207    public Builder serviceVersion(String serviceVersion) {
208      this.serviceVersion = serviceVersion;
209      return this;
210    }
211
212    public Builder resourceAttribute(String name, String value) {
213      this.resourceAttributes.put(name, value);
214      return this;
215    }
216
217    public ExporterOpenTelemetryProperties build() {
218      return new ExporterOpenTelemetryProperties(
219          protocol,
220          endpoint,
221          headers,
222          interval,
223          timeout,
224          serviceName,
225          serviceNamespace,
226          serviceInstanceId,
227          serviceVersion,
228          resourceAttributes);
229    }
230  }
231}