From 5f2663dc08fb9952f629f6cca53c42762ac351d7 Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 7 Aug 2025 21:24:39 +0200 Subject: [PATCH 01/10] Adds initial otel spec documents --- .vscode/settings.json | 12 ++++ spec/registry.yaml | 89 ++++++++++++++++++++++++ spec/spans.yml | 153 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 spec/registry.yaml create mode 100644 spec/spans.yml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0cee69e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "editor.rulers": [ + 80 + ], + "yaml.schemas": { + "https://raw.githubusercontent.com/open-telemetry/weaver/v0.16.1/schemas/semconv.schema.json": [ + "spec/**/*.yaml" + ] + }, + "json.schemaDownload.enable": true, + "markdown.extension.toc.levels": "2..6" +} \ No newline at end of file diff --git a/spec/registry.yaml b/spec/registry.yaml new file mode 100644 index 0000000..14b9bf6 --- /dev/null +++ b/spec/registry.yaml @@ -0,0 +1,89 @@ +groups: + - id: registry.graphql + type: attribute_group + display_name: GraphQL Attributes + brief: "This document defines attributes for GraphQL operations and resolvers." + attributes: + - id: graphql.operation.name + brief: "The name of the operation being executed." + type: string + stability: development + examples: ["FindBookById", "GetUserProfile"] + note: > + This represents the operation name as specified in the GraphQL query document. + When the operation name is not provided, this attribute SHOULD be omitted. + - id: graphql.operation.type + brief: "The type of the operation being executed." + stability: development + type: + members: + - id: query + value: "query" + brief: "GraphQL query operation" + stability: development + - id: mutation + value: "mutation" + brief: "GraphQL mutation operation" + stability: development + - id: subscription + value: "subscription" + brief: "GraphQL subscription operation" + stability: development + examples: ["query", "mutation", "subscription"] + - id: graphql.operation.hash + brief: "The hash of the operation document." + type: string + stability: development + examples: + [ + "sha256:400483f38c08e8a3d3b972409c9dfb8e4a326e1b1940864932acd9f873d8664c", + ] + note: > + The hash algorithm used SHOULD be specified as part of the value (e.g., "sha256:..."). + This can be used for monitoring operation distribution and caching strategies. + - id: graphql.operation.id + brief: > + The document identifier for persisted operations. + type: string + stability: development + examples: ["aa3e37c1bf54708e93f12c137afba004"] + note: > + This is a hash or identifier of the document provided by the user to identify + persisted operations. This attribute SHOULD only be set when using persisted operations. + - id: graphql.selection.name + brief: "The name of the selection that is being resolved. Either the field name or an alias." + type: string + stability: development + examples: ["newAddress", "bookTitle"] + note: > + If the field has an alias, this SHOULD be the alias name. Otherwise, it SHOULD be the field name. + - id: graphql.selection.path + brief: "The path of the selection that is being resolved." + type: string + stability: development + examples: ["/persons/0/address", "person[0].address"] + note: > + The path represents the location of the field being resolved within the result structure. + Path format may vary between implementations but SHOULD be consistent within an implementation. + - id: graphql.selection.field.name + brief: "The name of the field that is being resolved." + type: string + stability: development + examples: ["address", "name", "id"] + note: > + This is always the actual field name as defined in the schema, not an alias. + - id: graphql.selection.field.parent_type + brief: "The type that declares the field that is being resolved." + type: string + stability: development + examples: ["Person", "Query", "Mutation"] + note: > + This is the GraphQL type name that contains the field definition. + - id: graphql.selection.field.coordinate + brief: "The coordinate of the field that is being resolved." + type: string + stability: development + examples: ["Person.address", "Query.findBookById"] + note: > + The coordinate follows the format "{ParentType}.{fieldName}" and uniquely + identifies the field within the GraphQL schema. diff --git a/spec/spans.yml b/spec/spans.yml new file mode 100644 index 0000000..a6233f3 --- /dev/null +++ b/spec/spans.yml @@ -0,0 +1,153 @@ +groups: + - id: span.graphql.server.operation + type: span + stability: development + span_kind: server + brief: > + This span represents an incoming GraphQL operation on a server implementation. + note: | + **Span name** SHOULD be of the format `{graphql.operation.type}` provided + `graphql.operation.type` is available. If `graphql.operation.type` is not available, + the span SHOULD be named `GraphQL Operation`. + + For persisted operations with a specified operation name, instrumentations MAY provide + a configuration option to enable a more descriptive span name following + `{graphql.operation.type} {graphql.operation.name}` format when + `graphql.operation.name` is available and the operation is successfully identified + in the document. + + > **Warning** + > The `graphql.operation.name` value is provided by the client and can have high + > cardinality. Using it in the GraphQL server span name is NOT RECOMMENDED for + > ad-hoc operations without careful consideration of cardinality implications. + > For persisted operations, the cardinality is bounded and using the operation + > name in the span name is more acceptable. + > + > Implementations MUST NOT include the operation name in the span name when + > the operation was not found or could not be identified in the document. + > This prevents potential security issues and ensures span names remain meaningful. + attributes: + - ref: graphql.operation.type + requirement_level: required + - ref: graphql.operation.name + requirement_level: + conditionally_required: If available and not empty. + - ref: graphql.operation.hash + requirement_level: recommended + - ref: graphql.operation.id + requirement_level: + conditionally_required: If using persisted operations. + - ref: user_agent.original + requirement_level: recommended + + - id: span.graphql.server.document.parsing + type: span + stability: development + span_kind: internal + brief: > + This span represents the time spent parsing a GraphQL document. + note: | + **Span name** SHOULD be `GraphQL Document Parsing`. + + This span covers the parsing phase of GraphQL request processing, + where the document string is parsed into an abstract syntax tree (AST). + attributes: + - ref: graphql.operation.type + requirement_level: required + - ref: graphql.operation.name + requirement_level: + conditionally_required: If available and not empty. + - ref: graphql.operation.hash + requirement_level: recommended + - ref: graphql.operation.id + requirement_level: + conditionally_required: If using persisted operations. + + - id: span.graphql.server.document.validation + type: span + stability: development + span_kind: internal + brief: > + This span represents the time spent validating a GraphQL document. + note: | + **Span name** SHOULD be `GraphQL Document Validation`. + + This span covers the validation phase of GraphQL request processing, + where the document AST is validated against the GraphQL schema. + attributes: + - ref: graphql.operation.type + requirement_level: required + - ref: graphql.operation.name + requirement_level: + conditionally_required: If available and not empty. + - ref: graphql.operation.hash + requirement_level: recommended + - ref: graphql.operation.id + requirement_level: + conditionally_required: If using persisted operations. + + - id: span.graphql.server.document.variable_coercion + type: span + stability: development + span_kind: internal + brief: > + This span represents the time spent coercing variables for a GraphQL request. + note: | + **Span name** SHOULD be `GraphQL Variable Coercion`. + + This span covers the variable coercion phase of GraphQL request processing, + where input variables are coerced and validated according to their types. + attributes: + - ref: graphql.operation.type + requirement_level: required + - ref: graphql.operation.name + requirement_level: + conditionally_required: If available and not empty. + - ref: graphql.operation.hash + requirement_level: recommended + - ref: graphql.operation.id + requirement_level: + conditionally_required: If using persisted operations. + + - id: span.graphql.server.operation.execution + type: span + stability: development + span_kind: internal + brief: > + This span represents the execution phase of a GraphQL operation. + note: | + **Span name** SHOULD be `GraphQL Operation Execution`. + + This span covers the whole execution part of a GraphQL request, + including field resolution and result formatting. + attributes: + - ref: graphql.operation.type + requirement_level: required + - ref: graphql.operation.name + requirement_level: recommended + - ref: graphql.operation.hash + requirement_level: recommended + + - id: span.graphql.server.resolver.execution + type: span + stability: development + span_kind: internal + brief: > + This span represents the execution of a GraphQL field resolver. + note: | + **Span name** SHOULD be `{graphql.selection.field.coordinate}`. + + This span covers the execution of an individual field resolver, + including both synchronous and asynchronous resolvers. + The span ends when the resolver result is available. + attributes: + - ref: graphql.selection.name + requirement_level: recommended + - ref: graphql.selection.path + requirement_level: recommended + - ref: graphql.selection.field.name + requirement_level: required + - ref: graphql.selection.field.parent_type + requirement_level: required + - ref: graphql.selection.field.coordinate + requirement_level: required From a3130be9c3a6342ade289de215f06b45951cbd79 Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 7 Aug 2025 22:01:49 +0200 Subject: [PATCH 02/10] cleanup --- spec/registry.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/registry.yaml b/spec/registry.yaml index 14b9bf6..c3a97cc 100644 --- a/spec/registry.yaml +++ b/spec/registry.yaml @@ -64,7 +64,6 @@ groups: examples: ["/persons/0/address", "person[0].address"] note: > The path represents the location of the field being resolved within the result structure. - Path format may vary between implementations but SHOULD be consistent within an implementation. - id: graphql.selection.field.name brief: "The name of the field that is being resolved." type: string From 9d5df68b79ace66a475fe717c276e9e7ec05965c Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 7 Aug 2025 22:20:19 +0200 Subject: [PATCH 03/10] cleanup --- spec/spans.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spans.yml b/spec/spans.yml index a6233f3..9b19278 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -50,7 +50,7 @@ groups: **Span name** SHOULD be `GraphQL Document Parsing`. This span covers the parsing phase of GraphQL request processing, - where the document string is parsed into an abstract syntax tree (AST). + where the document string is parsed into an abstract syntax tree. attributes: - ref: graphql.operation.type requirement_level: required From 1cf37e4781c59918c18f1b0bc5aaff2461ad4da0 Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 7 Aug 2025 22:26:17 +0200 Subject: [PATCH 04/10] adds traces for dataloaders --- spec/registry.yaml | 18 ++++++++++++++++++ spec/spans.yml | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/spec/registry.yaml b/spec/registry.yaml index c3a97cc..ea57262 100644 --- a/spec/registry.yaml +++ b/spec/registry.yaml @@ -86,3 +86,21 @@ groups: note: > The coordinate follows the format "{ParentType}.{fieldName}" and uniquely identifies the field within the GraphQL schema. + - id: graphql.dataloader.name + brief: "The name of the DataLoader instance." + type: string + stability: development + examples: ["UserLoader", "ProductByIdLoader", "CommentsByPostIdLoader"] + note: > + This represents the name or identifier of the DataLoader instance. + When the DataLoader implementation supports naming, this SHOULD be set. + This helps in identifying specific DataLoader instances in observability. + - id: graphql.dataloader.batch.size + brief: "The number of individual requests in the DataLoader batch." + type: int + stability: development + examples: [5, 12, 25] + note: > + This represents the total number of individual load requests that were + batched together in a single batch operation. This includes both cache + hits and cache misses. diff --git a/spec/spans.yml b/spec/spans.yml index 9b19278..b4d5887 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -151,3 +151,27 @@ groups: requirement_level: required - ref: graphql.selection.field.coordinate requirement_level: required + + - id: span.graphql.server.dataloader.batch + type: span + stability: development + span_kind: internal + brief: > + This span represents the execution of a DataLoader batch operation. + note: | + **Span name** SHOULD be `GraphQL DataLoader Batch {dataloader.name}` when + the DataLoader has a name, otherwise `GraphQL DataLoader Batch`. + + This span covers the batched execution of multiple individual DataLoader + requests. It represents the time from when the batch is scheduled to + when all results are available. This span is created when a DataLoader + batches multiple individual load requests into a single batch operation + to optimize data access patterns. + + The span SHOULD be a child of the span that initiated the batch loading, + which is typically a resolver execution span. + attributes: + - ref: graphql.dataloader.name + requirement_level: recommended + - ref: graphql.dataloader.batch.size + requirement_level: required From fbe883d28df0e959d4e4c0e2c428a0faa9c589ae Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 7 Aug 2025 22:38:27 +0200 Subject: [PATCH 05/10] improve resolver execution --- spec/spans.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/spec/spans.yml b/spec/spans.yml index 9b19278..1ea4315 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -50,7 +50,7 @@ groups: **Span name** SHOULD be `GraphQL Document Parsing`. This span covers the parsing phase of GraphQL request processing, - where the document string is parsed into an abstract syntax tree. + where the document string is parsed into an abstract syntax tree (AST). attributes: - ref: graphql.operation.type requirement_level: required @@ -140,6 +140,27 @@ groups: This span covers the execution of an individual field resolver, including both synchronous and asynchronous resolvers. The span ends when the resolver result is available. + + > **Warning** + > Creating spans for every resolver execution can result in traces with + > hundreds or thousands of spans, severely impacting performance and + > trace readability. Instrumentations MUST NOT create resolver execution + > spans by default for all resolvers. + + Instrumentations SHOULD provide configuration options to control which + resolvers generate spans. Recommended strategies include: + + - **Manual selection**: Allow developers to explicitly mark specific + resolvers for tracing (e.g., via annotations, decorators, or configuration) + - **Asynchronous resolvers only**: Only trace resolvers that return + promises or other asynchronous constructs + - **Depth-based filtering**: Only trace resolvers at the top N levels + of the query (e.g., top 2 levels) + - **Performance-based filtering**: Only trace resolvers that exceed + a certain execution time threshold + + The selection criteria SHOULD be documented clearly for users to + understand which resolvers will generate spans. attributes: - ref: graphql.selection.name requirement_level: recommended From 4d9fa6c3887b1ab5a47c80bba061ceea6a4a9a6f Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 7 Aug 2025 23:02:22 +0200 Subject: [PATCH 06/10] change the name of the resolver span --- spec/spans.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/spans.yml b/spec/spans.yml index 1ea4315..aa4d1b6 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -128,18 +128,18 @@ groups: - ref: graphql.operation.hash requirement_level: recommended - - id: span.graphql.server.resolver.execution + - id: span.graphql.server.field.execution type: span stability: development span_kind: internal brief: > - This span represents the execution of a GraphQL field resolver. + This span represents the execution of a GraphQL field. note: | **Span name** SHOULD be `{graphql.selection.field.coordinate}`. - This span covers the execution of an individual field resolver, - including both synchronous and asynchronous resolvers. - The span ends when the resolver result is available. + This span covers the execution of an individual field, including both + synchronous and asynchronous resolvers. The span ends when the resolver + result is available. > **Warning** > Creating spans for every resolver execution can result in traces with From 10bc3bbe2c2e2087c20788fb5b8bc048e848ca5f Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 28 Aug 2025 22:31:12 +0200 Subject: [PATCH 07/10] Align with what we have discussed in the wg --- spec/registry.yaml | 6 +++--- spec/spans.yml | 33 ++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/spec/registry.yaml b/spec/registry.yaml index c3a97cc..8619358 100644 --- a/spec/registry.yaml +++ b/spec/registry.yaml @@ -30,7 +30,7 @@ groups: brief: "GraphQL subscription operation" stability: development examples: ["query", "mutation", "subscription"] - - id: graphql.operation.hash + - id: graphql.document.hash brief: "The hash of the operation document." type: string stability: development @@ -41,7 +41,7 @@ groups: note: > The hash algorithm used SHOULD be specified as part of the value (e.g., "sha256:..."). This can be used for monitoring operation distribution and caching strategies. - - id: graphql.operation.id + - id: graphql.document.id brief: > The document identifier for persisted operations. type: string @@ -61,7 +61,7 @@ groups: brief: "The path of the selection that is being resolved." type: string stability: development - examples: ["/persons/0/address", "person[0].address"] + examples: ["person[0].address"] note: > The path represents the location of the field being resolved within the result structure. - id: graphql.selection.field.name diff --git a/spec/spans.yml b/spec/spans.yml index aa4d1b6..34abd63 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -1,10 +1,10 @@ groups: - - id: span.graphql.server.operation + - id: span.graphql.server.request type: span stability: development span_kind: server brief: > - This span represents an incoming GraphQL operation on a server implementation. + This span represents an incoming GraphQL request on a server implementation. note: | **Span name** SHOULD be of the format `{graphql.operation.type}` provided `graphql.operation.type` is available. If `graphql.operation.type` is not available, @@ -28,17 +28,16 @@ groups: > This prevents potential security issues and ensures span names remain meaningful. attributes: - ref: graphql.operation.type - requirement_level: required + requirement_level: + conditionally_required: If parsing succeeded - ref: graphql.operation.name requirement_level: conditionally_required: If available and not empty. - - ref: graphql.operation.hash + - ref: graphql.document.hash requirement_level: recommended - - ref: graphql.operation.id + - ref: graphql.document.id requirement_level: conditionally_required: If using persisted operations. - - ref: user_agent.original - requirement_level: recommended - id: span.graphql.server.document.parsing type: span @@ -53,13 +52,14 @@ groups: where the document string is parsed into an abstract syntax tree (AST). attributes: - ref: graphql.operation.type - requirement_level: required + requirement_level: + conditionally_required: If parsing succeeded - ref: graphql.operation.name requirement_level: conditionally_required: If available and not empty. - - ref: graphql.operation.hash + - ref: graphql.document.hash requirement_level: recommended - - ref: graphql.operation.id + - ref: graphql.document.id requirement_level: conditionally_required: If using persisted operations. @@ -80,9 +80,9 @@ groups: - ref: graphql.operation.name requirement_level: conditionally_required: If available and not empty. - - ref: graphql.operation.hash + - ref: graphql.document.hash requirement_level: recommended - - ref: graphql.operation.id + - ref: graphql.document.id requirement_level: conditionally_required: If using persisted operations. @@ -103,9 +103,9 @@ groups: - ref: graphql.operation.name requirement_level: conditionally_required: If available and not empty. - - ref: graphql.operation.hash + - ref: graphql.document.hash requirement_level: recommended - - ref: graphql.operation.id + - ref: graphql.document.id requirement_level: conditionally_required: If using persisted operations. @@ -125,8 +125,11 @@ groups: requirement_level: required - ref: graphql.operation.name requirement_level: recommended - - ref: graphql.operation.hash + - ref: graphql.document.hash requirement_level: recommended + - ref: graphql.document.id + requirement_level: + conditionally_required: If using persisted operations. - id: span.graphql.server.field.execution type: span From 59341b731bcb4a39472fc3eb6a606265797de3fa Mon Sep 17 00:00:00 2001 From: PascalSenn Date: Thu, 28 Aug 2025 22:32:08 +0200 Subject: [PATCH 08/10] change from @marcotc Co-authored-by: Marco Costa --- spec/registry.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/registry.yaml b/spec/registry.yaml index 8619358..755c4ae 100644 --- a/spec/registry.yaml +++ b/spec/registry.yaml @@ -10,7 +10,7 @@ groups: stability: development examples: ["FindBookById", "GetUserProfile"] note: > - This represents the operation name as specified in the GraphQL query document. + This represents the operation name as specified in the GraphQL operation document. When the operation name is not provided, this attribute SHOULD be omitted. - id: graphql.operation.type brief: "The type of the operation being executed." From e00b2cb8e7e0ec6c20b886884b7988cd177db67a Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 26 Feb 2026 07:43:14 +0100 Subject: [PATCH 09/10] cleanup --- spec/registry.yaml | 2 ++ spec/spans.yml | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/registry.yaml b/spec/registry.yaml index 755c4ae..27fdf28 100644 --- a/spec/registry.yaml +++ b/spec/registry.yaml @@ -64,6 +64,8 @@ groups: examples: ["person[0].address"] note: > The path represents the location of the field being resolved within the result structure. + Therefore, if a field is aliased, the path will use the alias name instead of the actual field name. + - id: graphql.selection.field.name brief: "The name of the field that is being resolved." type: string diff --git a/spec/spans.yml b/spec/spans.yml index 34abd63..3631ab2 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -10,9 +10,9 @@ groups: `graphql.operation.type` is available. If `graphql.operation.type` is not available, the span SHOULD be named `GraphQL Operation`. - For persisted operations with a specified operation name, instrumentations MAY provide + For operation domains with bounded cardinality (e.g. trusted documents), instrumentations MAY provide a configuration option to enable a more descriptive span name following - `{graphql.operation.type} {graphql.operation.name}` format when + the `{graphql.operation.type} {graphql.operation.name}` format when `graphql.operation.name` is available and the operation is successfully identified in the document. @@ -20,7 +20,7 @@ groups: > The `graphql.operation.name` value is provided by the client and can have high > cardinality. Using it in the GraphQL server span name is NOT RECOMMENDED for > ad-hoc operations without careful consideration of cardinality implications. - > For persisted operations, the cardinality is bounded and using the operation + > For trusted documents, the cardinality is bounded and using the operation > name in the span name is more acceptable. > > Implementations MUST NOT include the operation name in the span name when From 0ab2986c74905413f67a68e1353f5d355677fdc7 Mon Sep 17 00:00:00 2001 From: Pascal Senn Date: Thu, 26 Feb 2026 09:15:24 +0100 Subject: [PATCH 10/10] cleanup --- spec/registry.yaml | 26 ++++++++++++++++++++++++++ spec/spans.yml | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/spec/registry.yaml b/spec/registry.yaml index 2eae591..f1e7403 100644 --- a/spec/registry.yaml +++ b/spec/registry.yaml @@ -106,3 +106,29 @@ groups: This represents the total number of individual load requests that were batched together in a single batch operation. This includes both cache hits and cache misses. + - id: graphql.dataloader.batch.keys + brief: "A subset of the keys requested in the DataLoader batch." + type: string[] + stability: development + examples: [["user:1", "user:2", "user:3"], ["post:42", "post:99"]] + note: > + This attribute is opt-in and SHOULD NOT be enabled by default, as keys + may contain sensitive or high-cardinality data. When enabled, implementations + MAY truncate the list to a configurable maximum number of keys. + The string representation of each key depends on the DataLoader implementation. + - id: graphql.dataloader.cache.hit_count + brief: "The number of requests in the batch that were served from the DataLoader cache." + type: int + stability: development + examples: [0, 3, 10] + note: > + This represents the number of individual load requests that were + resolved from the DataLoader's cache without requiring a fetch. + - id: graphql.dataloader.cache.miss_count + brief: "The number of requests in the batch that required fetching." + type: int + stability: development + examples: [2, 5, 12] + note: > + This represents the number of individual load requests that were + not found in the DataLoader's cache and required a fetch operation. diff --git a/spec/spans.yml b/spec/spans.yml index 0752464..af31d3b 100644 --- a/spec/spans.yml +++ b/spec/spans.yml @@ -176,6 +176,26 @@ groups: - ref: graphql.selection.field.coordinate requirement_level: required + - id: span.graphql.server.dataloader.dispatch + type: span + stability: development + span_kind: internal + brief: > + This optional span groups all DataLoader batch operations for a given request. + note: | + **Span name** SHOULD be `GraphQL DataLoader Dispatch`. + + This span is OPTIONAL. When present, it acts as a grouping span for all + DataLoader batch spans within a single GraphQL request. It represents + the overall dispatch of DataLoader batch operations. + + The span SHOULD be a child of the `graphql.server.request` span. + + Instrumentations that do not produce this span SHOULD attach DataLoader + batch spans directly to the `graphql.server.request` span or to the + resolver execution span that triggered the batch dispatch. + attributes: [] + - id: span.graphql.server.dataloader.batch type: span stability: development @@ -192,10 +212,23 @@ groups: batches multiple individual load requests into a single batch operation to optimize data access patterns. - The span SHOULD be a child of the span that initiated the batch loading, - which is typically a resolver execution span. + The parent of this span depends on what the instrumentation supports: + - If the `graphql.server.dataloader.dispatch` span is present, + this span SHOULD be a child of it. + - Otherwise, this span SHOULD be a child of the `graphql.server.request` + span, or of the resolver execution span that triggered the batch dispatch. + + The span SHOULD have links to all resolver execution spans that + contributed load requests to this batch, so that the causal + relationship between resolvers and the batch is preserved. attributes: - ref: graphql.dataloader.name requirement_level: recommended - ref: graphql.dataloader.batch.size requirement_level: required + - ref: graphql.dataloader.batch.keys + requirement_level: opt_in + - ref: graphql.dataloader.cache.hit_count + requirement_level: opt_in + - ref: graphql.dataloader.cache.miss_count + requirement_level: opt_in