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