Skip to content

Commit ca171b7

Browse files
authored
Add OTLP authentication section to ./java/sdk.md (#5866)
1 parent dc55d9d commit ca171b7

File tree

3 files changed

+134
-16
lines changed

3 files changed

+134
-16
lines changed

.gitmodules

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@
3232
[submodule "content-modules/opentelemetry-java-examples"]
3333
path = content-modules/opentelemetry-java-examples
3434
url = https://github.com/open-telemetry/opentelemetry-java-examples.git
35-
javaexamples-pin = 63cc9b4
35+
javaexamples-pin = cce0f6a

content/en/docs/languages/java/sdk.md

+132-14
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,7 @@ Span exporters built-in to the SDK and maintained by the community in
435435
| `InterceptableSpanExporter` | `io.opentelemetry.contrib:opentelemetry-processors:{{% param vers.contrib %}}-alpha` | Passes spans to a flexible interceptor before exporting. |
436436
| `KafkaSpanExporter` | `io.opentelemetry.contrib:opentelemetry-kafka-exporter:{{% param vers.contrib %}}-alpha` | Exports spans by writing to a Kafka topic. |
437437

438-
**[1]**: See [OTLP exporter sender](#otlp-exporter-senders) for implementation
439-
details.
438+
**[1]**: See [OTLP exporters](#otlp-exporters) for implementation details.
440439

441440
The following code snippet demonstrates `SpanExporter` programmatic
442441
configuration:
@@ -767,8 +766,7 @@ Metric exporters built-in to the SDK and maintained by the community in
767766
| `OtlpStdoutMetricExporter` | `io.opentelemetry:opentelemetry-exporter-logging-otlp:{{% param vers.otel %}}` | Logs metrics to `System.out` in the OTLP [JSON file encoding][] (experimental). |
768767
| `InterceptableMetricExporter` | `io.opentelemetry.contrib:opentelemetry-processors:{{% param vers.contrib %}}-alpha` | Passes metrics to a flexible interceptor before exporting. |
769768

770-
**[1]**: See [OTLP exporter sender](#otlp-exporter-senders) for implementation
771-
details.
769+
**[1]**: See [OTLP exporters](#otlp-exporters) for implementation details.
772770

773771
The following code snippet demonstrates `MetricExporter` programmatic
774772
configuration:
@@ -1095,8 +1093,7 @@ Span exporters built-in to the SDK and maintained by the community in
10951093
| `OtlpStdoutLogRecordExporter` | `io.opentelemetry:opentelemetry-exporter-logging-otlp:{{% param vers.otel %}}` | Logs log records to `System.out` in the OTLP [JSON file encoding][] (experimental). |
10961094
| `InterceptableLogRecordExporter` | `io.opentelemetry.contrib:opentelemetry-processors:{{% param vers.contrib %}}-alpha` | Passes log records to a flexible interceptor before exporting. |
10971095

1098-
**[1]**: See [OTLP exporter sender](#otlp-exporter-senders) for implementation
1099-
details.
1096+
**[1]**: See [OTLP exporters](#otlp-exporters) for implementation details.
11001097

11011098
**[2]**: `OtlpJsonLoggingLogRecordExporter` logs to JUL, and may cause infinite
11021099
loops (i.e. JUL -> SLF4J -> Logback -> OpenTelemetry Appender -> OpenTelemetry
@@ -1362,20 +1359,29 @@ public class IgnoreExportErrorsFilter implements java.util.logging.Filter {
13621359
io.opentelemetry.sdk.trace.export.BatchSpanProcessor = io.opentelemetry.extension.logging.IgnoreExportErrorsFilter
13631360
```
13641361

1365-
### OTLP exporter senders
1362+
### OTLP exporters
13661363

13671364
The [span exporter](#spanexporter), [metric exporter](#metricexporter), and
1368-
[log exporter](#logrecordexporter) discuss OTLP exporters of the form:
1365+
[log exporter](#logrecordexporter) sections describe OTLP exporters of the form:
13691366

1370-
- `OtlpHttp{Signal}Exporter`s export data via OTLP `http/protobuf`.
1371-
- `OtlpGrpc{Signal}Exporter`s export data via OTLP `grpc`.
1367+
- `OtlpHttp{Signal}Exporter`, which exports data via OTLP `http/protobuf`
1368+
- `OtlpGrpc{Signal}Exporter`, which exports data via OTLP `grpc`
13721369

13731370
The exporters for all signals are available via
1374-
`io.opentelemetry:opentelemetry-exporter-otlp:{{% param vers.otel %}}`.
1371+
`io.opentelemetry:opentelemetry-exporter-otlp:{{% param vers.otel %}}`, and have
1372+
significant overlap across `grpc` and `http/protobuf` versions of the OTLP
1373+
protocol, and between signals. The following sections elaborate on these key
1374+
concepts:
13751375

1376-
Internally, these exporters depend on various client libraries to execute HTTP
1377-
and gRPC requests. There is no single HTTP / gRPC client library which satisfies
1378-
all use cases in the Java ecosystem:
1376+
- [Senders](#senders): an abstraction for a different HTTP / gRPC client
1377+
libraries.
1378+
- [Authentication](#authentication) options for OTLP exporters.
1379+
1380+
#### Senders
1381+
1382+
The OTLP exporters depend on various client libraries to execute HTTP and gRPC
1383+
requests. There is no single HTTP / gRPC client library which satisfies all use
1384+
cases in the Java ecosystem:
13791385

13801386
- Java 11+ brings the built-in `java.net.http.HttpClient`, but
13811387
`opentelemetry-java` needs to support Java 8+ users, and this can't be used to
@@ -1403,6 +1409,118 @@ add a dependency on the alternative.
14031409
you must also add a dependency on a
14041410
[gRPC transport implementations](https://github.com/grpc/grpc-java#transport).
14051411

1412+
#### Authentication
1413+
1414+
The OTLP exporters provide mechanisms for static and dynamic header-based
1415+
authentication, and for mTLS.
1416+
1417+
If using
1418+
[zero-code SDK autoconfigure](../configuration/#zero-code-sdk-autoconfigure)
1419+
with environment variables and system properties, see
1420+
[relevant system properties](../configuration/#properties-exporters):
1421+
1422+
- `otel.exporter.otlp.headers` for static header-based authentication.
1423+
- `otel.exporter.otlp.client.key`, `otel.exporter.otlp.client.certificate` for
1424+
mTLS authentication.
1425+
1426+
The following code snippet demonstrates programmatic configuration of static and
1427+
dynamic header-based authentication:
1428+
1429+
<!-- prettier-ignore-start -->
1430+
<?code-excerpt "src/main/java/otel/OtlpAuthenticationConfig.java"?>
1431+
```java
1432+
package otel;
1433+
1434+
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
1435+
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
1436+
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
1437+
import java.time.Duration;
1438+
import java.time.Instant;
1439+
import java.util.Collections;
1440+
import java.util.Map;
1441+
import java.util.function.Supplier;
1442+
1443+
public class OtlpAuthenticationConfig {
1444+
public static void staticAuthenticationHeader(String endpoint) {
1445+
// If the OTLP destination accepts a static, long-lived authentication header like an API key,
1446+
// set it as a header.
1447+
// This reads the API key from the OTLP_API_KEY env var to avoid hard coding the secret in
1448+
// source code.
1449+
String apiKeyHeaderName = "api-key";
1450+
String apiKeyHeaderValue = System.getenv("OTLP_API_KEY");
1451+
1452+
// Initialize OTLP Span, Metric, and LogRecord exporters using a similar pattern
1453+
OtlpHttpSpanExporter spanExporter =
1454+
OtlpHttpSpanExporter.builder()
1455+
.setEndpoint(endpoint)
1456+
.addHeader(apiKeyHeaderName, apiKeyHeaderValue)
1457+
.build();
1458+
OtlpHttpMetricExporter metricExporter =
1459+
OtlpHttpMetricExporter.builder()
1460+
.setEndpoint(endpoint)
1461+
.addHeader(apiKeyHeaderName, apiKeyHeaderValue)
1462+
.build();
1463+
OtlpHttpLogRecordExporter logRecordExporter =
1464+
OtlpHttpLogRecordExporter.builder()
1465+
.setEndpoint(endpoint)
1466+
.addHeader(apiKeyHeaderName, apiKeyHeaderValue)
1467+
.build();
1468+
}
1469+
1470+
public static void dynamicAuthenticationHeader(String endpoint) {
1471+
// If the OTLP destination requires a dynamic authentication header, such as a JWT which needs
1472+
// to be periodically refreshed, use a header supplier.
1473+
// Here we implement a simple supplier which adds a header of the form "Authorization: Bearer
1474+
// <token>", where <token> is fetched from refreshBearerToken every 10 minutes.
1475+
String username = System.getenv("OTLP_USERNAME");
1476+
String password = System.getenv("OTLP_PASSWORD");
1477+
Supplier<Map<String, String>> supplier =
1478+
new AuthHeaderSupplier(() -> refreshToken(username, password), Duration.ofMinutes(10));
1479+
1480+
// Initialize OTLP Span, Metric, and LogRecord exporters using a similar pattern
1481+
OtlpHttpSpanExporter spanExporter =
1482+
OtlpHttpSpanExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build();
1483+
OtlpHttpMetricExporter metricExporter =
1484+
OtlpHttpMetricExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build();
1485+
OtlpHttpLogRecordExporter logRecordExporter =
1486+
OtlpHttpLogRecordExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build();
1487+
}
1488+
1489+
private static class AuthHeaderSupplier implements Supplier<Map<String, String>> {
1490+
private final Supplier<String> tokenRefresher;
1491+
private final Duration tokenRefreshInterval;
1492+
private Instant refreshedAt = Instant.ofEpochMilli(0);
1493+
private String currentTokenValue;
1494+
1495+
private AuthHeaderSupplier(Supplier<String> tokenRefresher, Duration tokenRefreshInterval) {
1496+
this.tokenRefresher = tokenRefresher;
1497+
this.tokenRefreshInterval = tokenRefreshInterval;
1498+
}
1499+
1500+
@Override
1501+
public Map<String, String> get() {
1502+
return Collections.singletonMap("Authorization", "Bearer " + getToken());
1503+
}
1504+
1505+
private synchronized String getToken() {
1506+
Instant now = Instant.now();
1507+
if (currentTokenValue == null || now.isAfter(refreshedAt.plus(tokenRefreshInterval))) {
1508+
currentTokenValue = tokenRefresher.get();
1509+
refreshedAt = now;
1510+
}
1511+
return currentTokenValue;
1512+
}
1513+
}
1514+
1515+
private static String refreshToken(String username, String password) {
1516+
// For a production scenario, this would be replaced with out-of-band request to exchange
1517+
// username / password for bearer token.
1518+
return "abc123";
1519+
}
1520+
}
1521+
```
1522+
<!-- prettier-ignore-end -->
1523+
14061524
### Testing
14071525

14081526
TODO: document tools available for testing the SDK

0 commit comments

Comments
 (0)