Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
import io.grpc.Metadata;
import io.opentelemetry.context.propagation.TextMapGetter;
import java.util.Iterator;
import java.util.stream.Collectors;
import javax.annotation.Nullable;

enum GrpcRequestGetter implements TextMapGetter<GrpcRequest> {
INSTANCE;

@Override
public Iterable<String> keys(GrpcRequest request) {
return request.getMetadata().keys();
// Filter out HTTP/2 pseudo-headers (starting with ':') as they cannot be
// accessed via Metadata.Key.of() and would cause IllegalArgumentException
return request.getMetadata().keys().stream()
.filter(key -> !key.startsWith(":"))
.collect(Collectors.toList());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixes:

09:21:45.711 [armeria-common-worker-nio-2-2] WARN c.l.a.server.grpc.FramedGrpcService - Exception thrown from streaming request stub method before processing any request data - this is likely a bug in the stub implementation.
java.lang.IllegalArgumentException: Invalid character ':' in key name ':method'
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:273)
at io.grpc.Metadata$Key.validateName(Metadata.java:754)
at io.grpc.Metadata$Key.(Metadata.java:762)
at io.grpc.Metadata$Key.(Metadata.java:671)
at io.grpc.Metadata$AsciiKey.(Metadata.java:971)
at io.grpc.Metadata$AsciiKey.(Metadata.java:966)
at io.grpc.Metadata$Key.of(Metadata.java:708)
at io.grpc.Metadata$Key.of(Metadata.java:704)
at io.opentelemetry.javaagent.shaded.instrumentation.grpc.v1_6.GrpcRequestGetter.get(GrpcRequestGetter.java:29)
at io.opentelemetry.javaagent.shaded.instrumentation.grpc.v1_6.GrpcRequestGetter.get(GrpcRequestGetter.java:15)
at io.opentelemetry.javaagent.testing.util.KeysVerifyingPropagator.lambda$extract$0(KeysVerifyingPropagator.java:45)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)

}

@Override
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.opentelemetry.instrumentation.testing.provider.TestLogRecordExporterComponentProvider;
import io.opentelemetry.instrumentation.testing.provider.TestMetricExporterComponentProvider;
import io.opentelemetry.instrumentation.testing.provider.TestSpanExporterComponentProvider;
import io.opentelemetry.instrumentation.testing.util.KeysVerifyingPropagator;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
Expand Down Expand Up @@ -102,9 +103,10 @@ public final class LibraryTestRunner extends InstrumentationTestRunner {
.build())
.setPropagators(
ContextPropagators.create(
TextMapPropagator.composite(
W3CTraceContextPropagator.getInstance(),
W3CBaggagePropagator.getInstance())))
new KeysVerifyingPropagator(
TextMapPropagator.composite(
W3CTraceContextPropagator.getInstance(),
W3CBaggagePropagator.getInstance()))))
.buildAndRegisterGlobal();
openTelemetry = wrap(openTelemetrySdk);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.testing.util;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;
import java.util.Collection;
import javax.annotation.Nullable;

/**
* A TextMapPropagator wrapper that verifies TextMapGetter methods can be called without errors.
*
* <p>This propagator wraps another propagator and calls methods during extraction. This catches
* compatibility issues where underlying library APIs change (e.g., NoSuchMethodError).
*/
public final class KeysVerifyingPropagator implements TextMapPropagator {
private final TextMapPropagator delegate;

public KeysVerifyingPropagator(TextMapPropagator delegate) {
this.delegate = delegate;
}

@Override
public Collection<String> fields() {
return delegate.fields();
}

@Override
public <C> void inject(Context context, C carrier, TextMapSetter<C> setter) {
delegate.inject(context, carrier, setter);
}

@Override
public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {
// exercise methods to verify no errors
Iterable<String> keys = getter.keys(carrier);
if (keys != null) {
keys.iterator().forEachRemaining(key -> getter.get(carrier, key));
}

return delegate.extract(context, carrier, getter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ private static Map<String, String> getTestProperties() {
properties.put("otel.logs.exporter", "none");
properties.put("otel.metrics.exporter", "none");
properties.put("otel.traces.exporter", "none");
properties.put("otel.propagators", "testing-verifying-propagator");
return properties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.testing.propagator;

import com.google.auto.service.AutoService;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.javaagent.testing.util.KeysVerifyingPropagator;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurablePropagatorProvider;

/** Provides a propagator that wraps the default W3C propagators with additional verification. */
@AutoService(ConfigurablePropagatorProvider.class)
public final class KeysVerifyingPropagatorProvider implements ConfigurablePropagatorProvider {
@Override
public TextMapPropagator getPropagator(ConfigProperties configProperties) {
TextMapPropagator composite =
TextMapPropagator.composite(
W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance());

return new KeysVerifyingPropagator(composite);
}

@Override
public String getName() {
return "testing-verifying-propagator";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.testing.util;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;
import java.util.Collection;
import javax.annotation.Nullable;

/**
* A TextMapPropagator wrapper that verifies TextMapGetter methods can be called without errors.
*
* <p>This propagator wraps another propagator and calls methods during extraction. This catches
* compatibility issues where underlying library APIs change (e.g., NoSuchMethodError).
*
* <p>Note: This is a copy of the class in testing-common to avoid dependency conflicts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I tried adding test-common as a dependency, I hit a bunch of ASM errors. I was able to get it to work by adding some dependency exclusions, but this seemed simpler. I can go back to the other approach if that is preferable

*/
public final class KeysVerifyingPropagator implements TextMapPropagator {
private final TextMapPropagator delegate;

public KeysVerifyingPropagator(TextMapPropagator delegate) {
this.delegate = delegate;
}

@Override
public Collection<String> fields() {
return delegate.fields();
}

@Override
public <C> void inject(Context context, C carrier, TextMapSetter<C> setter) {
delegate.inject(context, carrier, setter);
}

@Override
public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {
// exercise methods to verify no errors
Iterable<String> keys = getter.keys(carrier);
if (keys != null) {
keys.iterator().forEachRemaining(key -> getter.get(carrier, key));
}

return delegate.extract(context, carrier, getter);
}
}
Loading