Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch exporter #53

Merged
merged 3 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ The following properties are nested properties below the `inspectit-eum-server.e
Tracing exporters are responsible for passing the recorded tracing data to a corresponding storage.
The inspectIT Ocelot EUM Server currently supports the following trace exporters:

* [Jaeger](#jaeger-exporter) [[Homepage](https://www.jaegertracing.io/)]
* [OTLP (Traces)](#otlp-exporter-traces) [[Homepage](https://github.com/open-telemetry/opentelemetry-java/tree/main/exporters/otlp/trace)]
* [Jaeger](#jaeger-exporter) [[Homepage](https://www.jaegertracing.io/)] (deprecated)

###### General Trace Exporter Settings

Expand All @@ -231,22 +231,6 @@ These settings apply to all trace exporters and can set below the `inspectit-eum
|-----------------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `.service-name` | `${inspectit.service-name}` | The value of this property will be used to identify the service a trace came from. Please note that changes of this property only take effect after restarting the agent. |

###### Jaeger Exporter

InspectIT EUM Server supports thrift and gRPC Jaeger exporter.

By default, the Jaeger exporters are enabled but the URL/gRPC `endpoint` needed for the exporter to actually start is set to `null`.

The following properties are nested properties below the `inspectit.exporters.tracing.jaeger` property:

|Property | Default | Description |
|---|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|`.enabled`| `IF_CONFIGURED` | If `ENABLED` or `IF_CONFIGURED`, the agent will try to start the Jaeger exporter. If the url is not set, it will log a warning if set to `ENABLED` but fail silently if set to `IF_CONFIGURED`. |
|`.endpoint`| `null` | URL endpoint under which the Jaeger server can be accessed (e.g. http://127.0.0.1:14268/api/traces). |
|`.protocol`| `grpc` | The transport protocol. Supported protocols are `grpc` and `http/thrift`. |
| `.compression` | `NONE` | The compression method, see [OTEL documentation](https://opentelemetry.io/docs/reference/specification/protocol/exporter/). Supported compression methods are `gzip` and `none`. This property only takes effect when the protocol is set to `grpc`. |
| `.timeout` | `10s` | Maximum time the OTLP exporter will wait for each batch export, see [OTEL documentation](https://opentelemetry.io/docs/reference/specification/protocol/exporter/). This property only takes effect when the protocol is set to `grpc`. |

###### OTLP Exporter (Traces)

The OpenTelemetry Protocol (OTLP) exporters export the Traces in OTLP to the desired endpoint at a specified interval.
Expand All @@ -263,6 +247,24 @@ The following properties are nested properties below the `inspectit.exporters.tr
| `.compression` | `NONE` | The compression method, see [OTEL documentation](https://opentelemetry.io/docs/reference/specification/protocol/exporter/). Supported compression methods are `gzip` and `none`. |
| `.timeout` | `10s` | Maximum time the OTLP exporter will wait for each batch export, see [OTEL documentation](https://opentelemetry.io/docs/reference/specification/protocol/exporter/). |


###### Jaeger Exporter

InspectIT EUM Server supports thrift and gRPC Jaeger exporter. However, since OpenTelemetry has announced to [migrate away from the
Jaeger exporter](https://opentelemetry.io/blog/2023/jaeger-exporter-collector-migration/), it is **deprecated**.

By default, the Jaeger exporters are enabled but the URL/gRPC `endpoint` needed for the exporter to actually start is set to `null`.

The following properties are nested properties below the `inspectit.exporters.tracing.jaeger` property:

|Property | Default | Description |
|---|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|`.enabled`| `IF_CONFIGURED` | If `ENABLED` or `IF_CONFIGURED`, the agent will try to start the Jaeger exporter. If the url is not set, it will log a warning if set to `ENABLED` but fail silently if set to `IF_CONFIGURED`. |
|`.endpoint`| `null` | URL endpoint under which the Jaeger server can be accessed (e.g. http://127.0.0.1:14268/api/traces). |
|`.protocol`| `grpc` | The transport protocol. Supported protocols are `grpc` and `http/thrift`. |
| `.compression` | `NONE` | The compression method, see [OTEL documentation](https://opentelemetry.io/docs/reference/specification/protocol/exporter/). Supported compression methods are `gzip` and `none`. This property only takes effect when the protocol is set to `grpc`. |
| `.timeout` | `10s` | Maximum time the OTLP exporter will wait for each batch export, see [OTEL documentation](https://opentelemetry.io/docs/reference/specification/protocol/exporter/). This property only takes effect when the protocol is set to `grpc`. |

##### Security
Currently, the EUM Server only supports a simple API token security concept. In future, additional authentication providers
will be supported.
Expand Down
17 changes: 7 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,25 @@ dependencies {
"io.opencensus:opencensus-api:${openCensusVersion}",
"io.opencensus:opencensus-impl:${openCensusVersion}",
"io.opencensus:opencensus-exporter-stats-prometheus:${openCensusVersion}",
"rocks.inspectit:opencensus-influxdb-exporter:${openCensusInfluxdbExporterVersion}",

"io.grpc:grpc-context:${grpcVersion}",

platform("io.opentelemetry:opentelemetry-bom-alpha:${openTelemetryAlphaVersion}"),
platform("io.opentelemetry:opentelemetry-bom:${openTelemetryVersion}"),
"io.opentelemetry:opentelemetry-exporter-otlp:${openTelemetryVersion}",
"io.opentelemetry:opentelemetry-semconv:${openTelemetrySemConvVersion}",
"io.opentelemetry:opentelemetry-exporter-jaeger:${openTelemetryJaegerVersion}",
"io.opentelemetry:opentelemetry-exporter-jaeger-thrift:${openTelemetryJaegerVersion}",
"io.opentelemetry:opentelemetry-sdk:${openTelemetryVersion}",
"io.opentelemetry:opentelemetry-exporter-otlp:${openTelemetryVersion}",
"io.opentelemetry:opentelemetry-exporter-jaeger:${openTelemetryVersion}",
"io.opentelemetry:opentelemetry-exporter-jaeger-thrift:${openTelemetryVersion}",
"io.opentelemetry:opentelemetry-semconv:${openTelemetryAlphaVersion}",
"io.opentelemetry.proto:opentelemetry-proto:${openTelemetryProtoVersion}",

"com.google.protobuf:protobuf-java:${protobufVersion}",
"com.google.protobuf:protobuf-java-util:${protobufVersion}",

"com.google.guava:guava:${guavaVersion}",

"com.maxmind.geoip2:geoip2:${geoip2Version}",

"commons-net:commons-net:${commonsNetVersion}",
"org.apache.commons:commons-lang3:${commonsLang3Version}",
"org.apache.commons:commons-math3:${commonsMath3Version}",
Expand All @@ -165,9 +166,7 @@ dependencies {
// If there is a higher new version, remove the dependency override of okio-jvm
"org.influxdb:influxdb-java:${influxdbJavaVersion}",
// Override transitive dependency with newer version, due to security concerns
"com.squareup.okio:okio-jvm:${okioJvmVersion}",

"rocks.inspectit:opencensus-influxdb-exporter:${opencensusInfluxdbExporterVersion}",
"com.squareup.okio:okio-jvm:${okioJvmVersion}"
)

compileOnly "org.projectlombok:lombok"
Expand All @@ -182,8 +181,6 @@ dependencies {
"com.linecorp.armeria:armeria-junit5:${armeriaVersion}",
"com.linecorp.armeria:armeria-grpc-protocol:${armeriaVersion}",

"io.opentelemetry:opentelemetry-semconv:${openTelemetryAlphaVersion}",

// for docker test containers
"org.testcontainers:testcontainers:${testContainersVersion}",
"org.testcontainers:junit-jupiter:${testContainersVersion}"
Expand Down
12 changes: 6 additions & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ snakeYamlVersion=2.2

# Ensure to adapt the netty version (inspectit-ocelot-core/build.gradle) when changing the OpenCensus version
openCensusVersion=0.31.1
openCensusInfluxdbExporterVersion=1.2
grpcVersion=1.61.1

# pin Prometheus client to 0.6.0 to prevent auto prefixing counter metrics with "_total"
# see: https://github.com/prometheus/client_java/issues/640, https://github.com/prometheus/client_java/pull/653
prometheusClientVersion = 0.6.0
# Keep the OpenTelemetry versions consistent
openTelemetryVersion=1.30.0
openTelemetryAlphaVersion=1.30.0-alpha
openTelemetryVersion=1.30.1
openTelemetryAlphaVersion=1.30.1-alpha

openTelemetryProtoVersion=1.1.0-alpha
openTelemetrySemConvVersion=1.30.1-alpha
openTelemetryJaegerVersion=1.34.1
# Use version of opentelemetry-proto
protobufVersion=3.23.4

protobufVersion=3.25.3
guavaVersion=33.0.0-jre
geoip2Version=4.2.0

Expand All @@ -36,7 +37,6 @@ commonsIoVersion=2.14.0
influxdbJavaVersion=2.24
okioJvmVersion=3.5.0

opencensusInfluxdbExporterVersion=1.2
armeriaVersion=1.27.1
testContainersVersion=1.19.5

Expand Down
114 changes: 62 additions & 52 deletions src/main/java/io/opentelemetry/sdk/trace/OcelotSpanUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.proto.common.v1.AnyValue;
import io.opentelemetry.proto.common.v1.ArrayValue;
import io.opentelemetry.proto.common.v1.KeyValue;
import io.opentelemetry.proto.trace.v1.Span;
import io.opentelemetry.proto.trace.v1.Status;
Expand Down Expand Up @@ -164,17 +165,12 @@ static SpanContext createSpanContext(String traceId, String spanId) {
*/
@VisibleForTesting
static StatusCode toStatusCode(Status.StatusCode code) {
switch (code) {
case STATUS_CODE_UNSET:
return StatusCode.UNSET;
case STATUS_CODE_OK:
return StatusCode.OK;
case STATUS_CODE_ERROR:
return StatusCode.ERROR;
case UNRECOGNIZED:
default:
return null;
}
return switch (code) {
case STATUS_CODE_UNSET -> StatusCode.UNSET;
case STATUS_CODE_OK -> StatusCode.OK;
case STATUS_CODE_ERROR -> StatusCode.ERROR;
default -> null;
};
}

/**
Expand Down Expand Up @@ -233,25 +229,18 @@ public static Attributes toAttributes(List<KeyValue> attributesList, Map<String,

if (!CollectionUtils.isEmpty(attributesList)) {
for (KeyValue attribute : attributesList) {
// skip invalid data
if (attribute == null) continue;

AttributeKey attributeKey = toAttributeKey(attribute);
if (attributeKey != null) {
AnyValue value = attribute.getValue();
switch (attribute.getValue().getValueCase()) {
case STRING_VALUE:
builder.put(attributeKey, value.getStringValue());
break;
case BOOL_VALUE:
builder.put(attributeKey, value.getBoolValue());
break;
case INT_VALUE:
builder.put(attributeKey, value.getIntValue());
break;
case DOUBLE_VALUE:
builder.put(attributeKey, value.getDoubleValue());
break;
case ARRAY_VALUE:
builder.put(attributeKey, value.getArrayValue());
break;
case STRING_VALUE -> builder.put(attributeKey, value.getStringValue());
case BOOL_VALUE -> builder.put(attributeKey, value.getBoolValue());
case INT_VALUE -> builder.put(attributeKey, value.getIntValue());
case DOUBLE_VALUE -> builder.put(attributeKey, value.getDoubleValue());
case ARRAY_VALUE -> builder.put(attributeKey, mergeArray(value.getArrayValue()));
}
}
}
Expand All @@ -270,38 +259,59 @@ public static Attributes toAttributes(List<KeyValue> attributesList, Map<String,
private static AttributeKey<?> toAttributeKey(KeyValue attribute) {
String key = attribute.getKey();
AnyValue.ValueCase valueCase = attribute.getValue().getValueCase();
switch (valueCase) {
case STRING_VALUE:
return AttributeKey.stringKey(key);
case BOOL_VALUE:
return AttributeKey.booleanKey(key);
case INT_VALUE:
return AttributeKey.longKey(key);
case DOUBLE_VALUE:
return AttributeKey.doubleKey(key);
case ARRAY_VALUE:
return AttributeKey.stringArrayKey(key);
}
return null;
return switch (valueCase) {
case STRING_VALUE -> AttributeKey.stringKey(key);
case BOOL_VALUE -> AttributeKey.booleanKey(key);
case INT_VALUE -> AttributeKey.longKey(key);
case DOUBLE_VALUE -> AttributeKey.doubleKey(key);
// Currently, OTel is not able to process arrayValue in attributes
case ARRAY_VALUE -> AttributeKey.stringKey(key);
default -> null;
};
}

/**
* @return Returns a {@link SpanKind} representing the given {@link Span.SpanKind} instance.
*/
private static SpanKind toSpanKind(Span.SpanKind spanKind) {
switch (spanKind) {
case SPAN_KIND_SERVER:
return SpanKind.SERVER;
case SPAN_KIND_CLIENT:
return SpanKind.CLIENT;
case SPAN_KIND_PRODUCER:
return SpanKind.PRODUCER;
case SPAN_KIND_CONSUMER:
return SpanKind.CONSUMER;
case SPAN_KIND_INTERNAL:
default:
return switch (spanKind) {
case SPAN_KIND_SERVER -> SpanKind.SERVER;
case SPAN_KIND_CLIENT -> SpanKind.CLIENT;
case SPAN_KIND_PRODUCER -> SpanKind.PRODUCER;
case SPAN_KIND_CONSUMER -> SpanKind.CONSUMER;
default ->
// default value if we can not map
return SpanKind.INTERNAL;
}
SpanKind.INTERNAL;
};
}

/**
* Merges all values of an array. The values will always be converted to strings.
* Currently, OTel is not able to process arrayValue objects in Attributes.
* See <a href="https://github.com/open-telemetry/opentelemetry-java/issues/6243">issue</a>
*
* @param arrayValue the array containing any values
*
* @return the merged string of all values
*/
private static String mergeArray(ArrayValue arrayValue) {
List<AnyValue> values = arrayValue.getValuesList();
String mergedString = values.stream()
.map(OcelotSpanUtils::getValueAsString)
.collect(Collectors.joining(", "));
return mergedString;
}

/**
* @return the {@link AnyValue} as string.
*/
private static String getValueAsString(AnyValue value) {
return switch (value.getValueCase()) {
case STRING_VALUE -> value.getStringValue();
case INT_VALUE -> String.valueOf(value.getIntValue());
case DOUBLE_VALUE -> String.valueOf(value.getDoubleValue());
case BOOL_VALUE -> String.valueOf(value.getBoolValue());
default -> "";
};
}
}
Loading
Loading