diff --git a/.chloggen/exception-group-id.yaml b/.chloggen/exception-group-id.yaml new file mode 100644 index 0000000000..707083d36f --- /dev/null +++ b/.chloggen/exception-group-id.yaml @@ -0,0 +1,22 @@ +# Use this changelog template to create an entry for release notes. +# +# If your change doesn't affect end users you should instead start +# your pull request title with [chore] or use the "Skip Changelog" label. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the area of concern in the attributes-registry, (e.g. http, cloud, db) +component: exception + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Add `exception.group_id` attribute for grouping structurally equivalent exceptions." + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +# The values here must be integers. +issues: [3443] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/docs/exceptions/exceptions-logs.md b/docs/exceptions/exceptions-logs.md index 7a00fe58e9..8fd7da5a0e 100644 --- a/docs/exceptions/exceptions-logs.md +++ b/docs/exceptions/exceptions-logs.md @@ -65,6 +65,7 @@ The table below indicates which attributes should be added to the | [`exception.message`](/docs/registry/attributes/exception.md) | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | `Conditionally Required` [1] | string | The exception message. [2] | `Division by zero`; `Can't convert 'int' object to str implicitly` | | [`exception.type`](/docs/registry/attributes/exception.md) | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | `Conditionally Required` [3] | string | The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. | `java.net.ConnectException`; `OSError` | | [`exception.stacktrace`](/docs/registry/attributes/exception.md) | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | `Recommended` | string | A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. | `Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5)` | +| [`exception.group_id`](/docs/registry/attributes/exception.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | An identifier for the exception group, used to correlate exceptions that are considered structurally equivalent. [4] | `518d34582b6189db69b36414336c47ec6e4144f8` | **[1] `exception.message`:** Required if `exception.type` is not set, recommended otherwise. @@ -76,6 +77,19 @@ The table below indicates which attributes should be added to the **[3] `exception.type`:** Required if `exception.message` is not set, recommended otherwise. +**[4] `exception.group_id`:** Instrumentations SHOULD produce the same `exception.group_id` for +exceptions that share the same type and stacktrace structure, +ignoring high-cardinality parts such as the exception message. +The exact algorithm for computing the value is left to the +instrumentation, but it MUST ensure that structurally equivalent +exceptions produce the same value. + +For Java, the `exception.group_id` SHOULD be derived from the +exception's fully-qualified class name (`exception.type`) and the +structural elements of the stacktrace (e.g. class names and method +names of each frame), excluding the exception +message. + diff --git a/docs/exceptions/exceptions-spans.md b/docs/exceptions/exceptions-spans.md index 122a072941..e4acf1b7e8 100644 --- a/docs/exceptions/exceptions-spans.md +++ b/docs/exceptions/exceptions-spans.md @@ -56,6 +56,7 @@ This event describes a single exception. | [`exception.type`](/docs/registry/attributes/exception.md) | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | `Conditionally Required` [3] | string | The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. | `java.net.ConnectException`; `OSError` | | [`exception.escaped`](/docs/registry/attributes/exception.md) | ![Deprecated](https://img.shields.io/badge/-deprecated-red)
It's no longer recommended to record exceptions that are handled and do not escape the scope of a span. | `Recommended` | boolean | Indicates that the exception is escaping the scope of the span. | | | [`exception.stacktrace`](/docs/registry/attributes/exception.md) | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | `Recommended` | string | A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. | `Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5)` | +| [`exception.group_id`](/docs/registry/attributes/exception.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | An identifier for the exception group, used to correlate exceptions that are considered structurally equivalent. [4] | `518d34582b6189db69b36414336c47ec6e4144f8` | **[1] `exception.message`:** Required if `exception.type` is not set, recommended otherwise. @@ -67,6 +68,19 @@ This event describes a single exception. **[3] `exception.type`:** Required if `exception.message` is not set, recommended otherwise. +**[4] `exception.group_id`:** Instrumentations SHOULD produce the same `exception.group_id` for +exceptions that share the same type and stacktrace structure, +ignoring high-cardinality parts such as the exception message. +The exact algorithm for computing the value is left to the +instrumentation, but it MUST ensure that structurally equivalent +exceptions produce the same value. + +For Java, the `exception.group_id` SHOULD be derived from the +exception's fully-qualified class name (`exception.type`) and the +structural elements of the stacktrace (e.g. class names and method +names of each frame), excluding the exception +message. + diff --git a/docs/registry/attributes/exception.md b/docs/registry/attributes/exception.md index b6629f6240..e3421b5216 100644 --- a/docs/registry/attributes/exception.md +++ b/docs/registry/attributes/exception.md @@ -14,11 +14,25 @@ This document defines the shared attributes used to report a single exception as | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `exception.message` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | string | The exception message. [1] | `Division by zero`; `Can't convert 'int' object to str implicitly` | +| `exception.group_id` | ![Development](https://img.shields.io/badge/-development-blue) | string | An identifier for the exception group, used to correlate exceptions that are considered structurally equivalent. [1] | `518d34582b6189db69b36414336c47ec6e4144f8` | +| `exception.message` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | string | The exception message. [2] | `Division by zero`; `Can't convert 'int' object to str implicitly` | | `exception.stacktrace` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | string | A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. | `Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5)` | | `exception.type` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | string | The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. | `java.net.ConnectException`; `OSError` | -**[1] `exception.message`:** +**[1] `exception.group_id`:** Instrumentations SHOULD produce the same `exception.group_id` for +exceptions that share the same type and stacktrace structure, +ignoring high-cardinality parts such as the exception message. +The exact algorithm for computing the value is left to the +instrumentation, but it MUST ensure that structurally equivalent +exceptions produce the same value. + +For Java, the `exception.group_id` SHOULD be derived from the +exception's fully-qualified class name (`exception.type`) and the +structural elements of the stacktrace (e.g. class names and method +names of each frame), excluding the exception +message. + +**[2] `exception.message`:** > [!WARNING] > diff --git a/model/exceptions/events.yaml b/model/exceptions/events.yaml index 10d9691ebe..dd901522a4 100644 --- a/model/exceptions/events.yaml +++ b/model/exceptions/events.yaml @@ -14,3 +14,5 @@ groups: conditionally_required: Required if `exception.type` is not set, recommended otherwise. - ref: exception.stacktrace - ref: exception.escaped + - ref: exception.group_id + requirement_level: opt_in diff --git a/model/exceptions/logs.yaml b/model/exceptions/logs.yaml index c8b664c0bf..cfe1665040 100644 --- a/model/exceptions/logs.yaml +++ b/model/exceptions/logs.yaml @@ -12,3 +12,5 @@ groups: requirement_level: conditionally_required: Required if `exception.type` is not set, recommended otherwise. - ref: exception.stacktrace + - ref: exception.group_id + requirement_level: opt_in diff --git a/model/exceptions/registry.yaml b/model/exceptions/registry.yaml index cebf6ce34e..31714784b0 100644 --- a/model/exceptions/registry.yaml +++ b/model/exceptions/registry.yaml @@ -35,3 +35,23 @@ groups: at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) + - id: exception.group_id + type: string + stability: development + brief: > + An identifier for the exception group, used to correlate exceptions + that are considered structurally equivalent. + note: | + Instrumentations SHOULD produce the same `exception.group_id` for + exceptions that share the same type and stacktrace structure, + ignoring high-cardinality parts such as the exception message. + The exact algorithm for computing the value is left to the + instrumentation, but it MUST ensure that structurally equivalent + exceptions produce the same value. + + For Java, the `exception.group_id` SHOULD be derived from the + exception's fully-qualified class name (`exception.type`) and the + structural elements of the stacktrace (e.g. class names and method + names of each frame), excluding the exception + message. + examples: ["518d34582b6189db69b36414336c47ec6e4144f8"]