Remove operation name from graphql span name (#13794)

This commit is contained in:
Lauri Tulmin 2025-04-30 08:47:18 +03:00 committed by GitHub
parent e36be4942b
commit fffdb0b751
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 77 additions and 18 deletions

View File

@ -1,8 +1,9 @@
# Settings for the GraphQL instrumentation
| System property | Type | Default | Description |
|--------------------------------------------------------|---------|---------|--------------------------------------------------------------------------------------------|
| `otel.instrumentation.graphql.query-sanitizer.enabled` | Boolean | `true` | Whether to remove sensitive information from query source that is added as span attribute. |
| System property | Type | Default | Description |
|------------------------------------------------------------------------|---------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `otel.instrumentation.graphql.query-sanitizer.enabled` | Boolean | `true` | Whether to remove sensitive information from query source that is added as span attribute. |
| `otel.instrumentation.graphql.add-operation-name-to-span-name.enabled` | Boolean | `false` | Whether GraphQL operation name is added to the span name. <p>**WARNING**: GraphQL operation name is provided by the client and can have high cardinality. Use only when the server is not exposed to malicious clients. |
# Settings for the GraphQL 20 instrumentation

View File

@ -24,3 +24,7 @@ dependencies {
latestDepTestLibrary("com.graphql-java:graphql-java:19.+") // see graphql-java-20.0 module
}
tasks.withType<Test>().configureEach {
jvmArgs("-Dotel.instrumentation.graphql.add-operation-name-to-span-name.enabled=true")
}

View File

@ -16,10 +16,15 @@ public final class GraphqlSingletons {
private static final boolean QUERY_SANITIZATION_ENABLED =
AgentInstrumentationConfig.get()
.getBoolean("otel.instrumentation.graphql.query-sanitizer.enabled", true);
private static final boolean ADD_OPERATION_NAME_TO_SPAN_NAME =
AgentInstrumentationConfig.get()
.getBoolean(
"otel.instrumentation.graphql.add-operation-name-to-span-name.enabled", false);
private static final GraphQLTelemetry TELEMETRY =
GraphQLTelemetry.builder(GlobalOpenTelemetry.get())
.setSanitizeQuery(QUERY_SANITIZATION_ENABLED)
.setAddOperationNameToSpanName(ADD_OPERATION_NAME_TO_SPAN_NAME)
.build();
private GraphqlSingletons() {}

View File

@ -27,10 +27,11 @@ public final class GraphQLTelemetry {
private final OpenTelemetryInstrumentationHelper helper;
GraphQLTelemetry(OpenTelemetry openTelemetry, boolean sanitizeQuery) {
GraphQLTelemetry(
OpenTelemetry openTelemetry, boolean sanitizeQuery, boolean addOperationNameToSpanName) {
helper =
OpenTelemetryInstrumentationHelper.create(
openTelemetry, INSTRUMENTATION_NAME, sanitizeQuery);
openTelemetry, INSTRUMENTATION_NAME, sanitizeQuery, addOperationNameToSpanName);
}
/**

View File

@ -15,6 +15,7 @@ public final class GraphQLTelemetryBuilder {
private final OpenTelemetry openTelemetry;
private boolean sanitizeQuery = true;
private boolean addOperationNameToSpanName = false;
GraphQLTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -27,11 +28,23 @@ public final class GraphQLTelemetryBuilder {
return this;
}
/**
* Sets whether GraphQL operation name is added to the span name. Default is {@code false}.
*
* <p>WARNING: GraphQL operation name is provided by the client and can have high cardinality. Use
* only when the server is not exposed to malicious clients.
*/
@CanIgnoreReturnValue
public GraphQLTelemetryBuilder setAddOperationNameToSpanName(boolean addOperationNameToSpanName) {
this.addOperationNameToSpanName = addOperationNameToSpanName;
return this;
}
/**
* Returns a new {@link GraphQLTelemetry} with the settings of this {@link
* GraphQLTelemetryBuilder}.
*/
public GraphQLTelemetry build() {
return new GraphQLTelemetry(openTelemetry, sanitizeQuery);
return new GraphQLTelemetry(openTelemetry, sanitizeQuery, addOperationNameToSpanName);
}
}

View File

@ -23,7 +23,10 @@ class GraphqlTest extends AbstractGraphqlTest {
@Override
protected void configure(GraphQL.Builder builder) {
GraphQLTelemetry telemetry = GraphQLTelemetry.builder(testing.getOpenTelemetry()).build();
GraphQLTelemetry telemetry =
GraphQLTelemetry.builder(testing.getOpenTelemetry())
.setAddOperationNameToSpanName(true)
.build();
builder.instrumentation(telemetry.newInstrumentation());
}
}

View File

@ -25,6 +25,7 @@ dependencies {
tasks.withType<Test>().configureEach {
jvmArgs("-Dotel.instrumentation.graphql.data-fetcher.enabled=true")
jvmArgs("-Dotel.instrumentation.graphql.add-operation-name-to-span-name.enabled=true")
}
if (findProperty("testLatestDeps") as Boolean) {

View File

@ -22,12 +22,17 @@ public final class GraphqlSingletons {
private static final boolean TRIVIAL_DATA_FETCHER_ENABLED =
AgentInstrumentationConfig.get()
.getBoolean("otel.instrumentation.graphql.trivial-data-fetcher.enabled", false);
private static final boolean ADD_OPERATION_NAME_TO_SPAN_NAME =
AgentInstrumentationConfig.get()
.getBoolean(
"otel.instrumentation.graphql.add-operation-name-to-span-name.enabled", false);
private static final GraphQLTelemetry TELEMETRY =
GraphQLTelemetry.builder(GlobalOpenTelemetry.get())
.setSanitizeQuery(QUERY_SANITIZATION_ENABLED)
.setDataFetcherInstrumentationEnabled(DATA_FETCHER_ENABLED)
.setTrivialDataFetcherInstrumentationEnabled(TRIVIAL_DATA_FETCHER_ENABLED)
.setAddOperationNameToSpanName(ADD_OPERATION_NAME_TO_SPAN_NAME)
.build();
private GraphqlSingletons() {}

View File

@ -34,8 +34,11 @@ public final class GraphQLTelemetry {
OpenTelemetry openTelemetry,
boolean sanitizeQuery,
Instrumenter<DataFetchingEnvironment, Void> dataFetcherInstrumenter,
boolean createSpansForTrivialDataFetcher) {
helper = GraphqlInstrumenterFactory.createInstrumentationHelper(openTelemetry, sanitizeQuery);
boolean createSpansForTrivialDataFetcher,
boolean addOperationNameToSpanName) {
helper =
GraphqlInstrumenterFactory.createInstrumentationHelper(
openTelemetry, sanitizeQuery, addOperationNameToSpanName);
this.dataFetcherInstrumenter = dataFetcherInstrumenter;
this.createSpansForTrivialDataFetcher = createSpansForTrivialDataFetcher;
}

View File

@ -15,10 +15,9 @@ public final class GraphQLTelemetryBuilder {
private final OpenTelemetry openTelemetry;
private boolean sanitizeQuery = true;
private boolean dataFetcherInstrumentationEnabled = false;
private boolean trivialDataFetcherInstrumentationEnabled = false;
private boolean addOperationNameToSpanName = false;
GraphQLTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -50,6 +49,18 @@ public final class GraphQLTelemetryBuilder {
return this;
}
/**
* Sets whether GraphQL operation name is added to the span name. Default is {@code false}.
*
* <p>WARNING: GraphQL operation name is provided by the client and can have high cardinality. Use
* only when the server is not exposed to malicious clients.
*/
@CanIgnoreReturnValue
public GraphQLTelemetryBuilder setAddOperationNameToSpanName(boolean addOperationNameToSpanName) {
this.addOperationNameToSpanName = addOperationNameToSpanName;
return this;
}
/**
* Returns a new {@link GraphQLTelemetry} with the settings of this {@link
* GraphQLTelemetryBuilder}.
@ -60,6 +71,7 @@ public final class GraphQLTelemetryBuilder {
sanitizeQuery,
GraphqlInstrumenterFactory.createDataFetcherInstrumenter(
openTelemetry, dataFetcherInstrumentationEnabled),
trivialDataFetcherInstrumentationEnabled);
trivialDataFetcherInstrumentationEnabled,
addOperationNameToSpanName);
}
}

View File

@ -15,9 +15,9 @@ final class GraphqlInstrumenterFactory {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.graphql-java-20.0";
static OpenTelemetryInstrumentationHelper createInstrumentationHelper(
OpenTelemetry openTelemetry, boolean sanitizeQuery) {
OpenTelemetry openTelemetry, boolean sanitizeQuery, boolean addOperationNameToSpanName) {
return OpenTelemetryInstrumentationHelper.create(
openTelemetry, INSTRUMENTATION_NAME, sanitizeQuery);
openTelemetry, INSTRUMENTATION_NAME, sanitizeQuery, addOperationNameToSpanName);
}
static Instrumenter<DataFetchingEnvironment, Void> createDataFetcherInstrumenter(

View File

@ -41,6 +41,7 @@ class GraphqlTest extends AbstractGraphqlTest {
GraphQLTelemetry telemetry =
GraphQLTelemetry.builder(testing.getOpenTelemetry())
.setDataFetcherInstrumentationEnabled(true)
.setAddOperationNameToSpanName(true)
.build();
builder.instrumentation(telemetry.newInstrumentation());
}
@ -56,6 +57,7 @@ class GraphqlTest extends AbstractGraphqlTest {
GraphQLTelemetry telemetry =
GraphQLTelemetry.builder(testing.getOpenTelemetry())
.setDataFetcherInstrumentationEnabled(true)
.setAddOperationNameToSpanName(true)
.build();
GraphQL graphql =
@ -118,6 +120,7 @@ class GraphqlTest extends AbstractGraphqlTest {
GraphQLTelemetry.builder(testing.getOpenTelemetry())
.setDataFetcherInstrumentationEnabled(true)
.setTrivialDataFetcherInstrumentationEnabled(true)
.setAddOperationNameToSpanName(true)
.build();
GraphQL graphql =
@ -194,6 +197,7 @@ class GraphqlTest extends AbstractGraphqlTest {
GraphQLTelemetry.builder(testing.getOpenTelemetry())
.setDataFetcherInstrumentationEnabled(false)
.setTrivialDataFetcherInstrumentationEnabled(true)
.setAddOperationNameToSpanName(true)
.build();
GraphQL graphql =

View File

@ -48,16 +48,22 @@ public final class OpenTelemetryInstrumentationHelper {
private final Instrumenter<OpenTelemetryInstrumentationState, ExecutionResult> instrumenter;
private final boolean sanitizeQuery;
private final boolean addOperationNameToSpanName;
private OpenTelemetryInstrumentationHelper(
Instrumenter<OpenTelemetryInstrumentationState, ExecutionResult> instrumenter,
boolean sanitizeQuery) {
boolean sanitizeQuery,
boolean addOperationNameToSpanName) {
this.instrumenter = instrumenter;
this.sanitizeQuery = sanitizeQuery;
this.addOperationNameToSpanName = addOperationNameToSpanName;
}
public static OpenTelemetryInstrumentationHelper create(
OpenTelemetry openTelemetry, String instrumentationName, boolean sanitizeQuery) {
OpenTelemetry openTelemetry,
String instrumentationName,
boolean sanitizeQuery,
boolean addOperationNameToSpanName) {
InstrumenterBuilder<OpenTelemetryInstrumentationState, ExecutionResult> builder =
Instrumenter.<OpenTelemetryInstrumentationState, ExecutionResult>builder(
openTelemetry, instrumentationName, ignored -> "GraphQL Operation")
@ -76,7 +82,8 @@ public final class OpenTelemetryInstrumentationHelper {
});
builder.addAttributesExtractor(new GraphqlAttributesExtractor());
return new OpenTelemetryInstrumentationHelper(builder.buildInstrumenter(), sanitizeQuery);
return new OpenTelemetryInstrumentationHelper(
builder.buildInstrumenter(), sanitizeQuery, addOperationNameToSpanName);
}
public InstrumentationContext<ExecutionResult> beginExecution(
@ -118,7 +125,7 @@ public final class OpenTelemetryInstrumentationHelper {
String operationName = operationDefinition.getName();
String spanName = operationType;
if (operationName != null && !operationName.isEmpty()) {
if (addOperationNameToSpanName && operationName != null && !operationName.isEmpty()) {
spanName += " " + operationName;
}
span.updateName(spanName);