Skip to content

Commit 9c1fde2

Browse files
authored
add telemetry hook implementation guidelines (#348)
Signed-off-by: Michael Beemer <[email protected]>
1 parent ed50557 commit 9c1fde2

File tree

1 file changed

+72
-1
lines changed

1 file changed

+72
-1
lines changed

specification/appendix-d-observability.md

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,77 @@ The following describes how keys in [flag metadata](types.md#flag-metadata) are
5151
| ---------------------------- | ----------------------- | ----------------- | -------- | ------------------------------------------------------------------------------------------------ |
5252
| `feature_flag.provider.name` | `name` | `Recommended` | `string` | The name of the provider as defined in the `provider metadata`, available in the `hook context`. |
5353

54+
## Telemetry Hook Implementation Guide
55+
56+
This section provides guidance for implementing observability hooks that emit OpenTelemetry signals during feature flag evaluations. The recommendations ensure consistency across SDK implementations while allowing for language-specific idioms.
57+
58+
### Signal Emission Patterns
59+
60+
Telemetry hooks can emit OpenTelemetry signals in three distinct ways:
61+
62+
| Pattern | Advantages | Disadvantages |
63+
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
64+
| **Span Events**</br>![recommended](https://img.shields.io/badge/recommended-green) | - Leverages existing trace configuration and tooling</br> - Minimal overhead, no additional spans created</br> - Maintains trace context relationships</br> - Simpler than creating spans | - Requires an active span to function</br> - Must gracefully handle absence of active span</br> - Limited to span lifetime and context. |
65+
| **Event Logging** | - Works independently without active spans</br> - Aligns with OpenTelemetry's emerging direction</br> - Suitable for environments without tracing</br> - Simpler implementation model | - Requires an event exporter to be configured</br> - Processed and stored separately from spans</br> - Event logging standards still evolving |
66+
| **Standalone Spans** | - Distributed traces contain every evaluation</br> - Detailed timing information</br> - Full span lifecycle control | - Creates one span per evaluation</br> - May clutter trace visualizations</br> - Increased overhead and resource usage</br> - Potential performance impact at scale</br> - More complex implementation |
67+
68+
> [!NOTE]
69+
> While span events are recommended for their low overhead and ease of use, OpenTelemetry is trending toward using log-based events instead of span events. Please refer to the [OpenTelemetry Span Event Deprecation Plan][otel-span-event-deprecation-plan] for more details.
70+
71+
### Hook Lifecycle Implementation
72+
73+
#### Before Stage
74+
75+
The `before` hook stage is primarily used by standalone span hooks to create and store spans. When creating spans, it's recommended to use the name `feature_flag.evaluation` and store them in hook data using a consistent, documented key for easy retrieval in later stages.
76+
77+
#### Error Stage
78+
79+
The `error` hook stage records exception information unless explicitly configured to exclude it. Implementations typically use [OpenTelemetry's standard exception][otel-record-error] recording semantics (`recordException` for spans, exception log events for event logging). Configuration options like `excludeExceptions` allow users to control this behavior based on their needs.
80+
81+
#### Finally Stage
82+
83+
The `finally` hook stage is where telemetry signals are emitted with complete evaluation details. This stage should include all required and conditionally required attributes as defined in the attribute mapping tables above. It's also responsible for proper resource cleanup (like ending spans or closing connections).
84+
85+
### Attribute Transformations
86+
87+
When building telemetry attributes, implementations should extract and map well-known fields from flag metadata to their corresponding event record attributes as defined in the Flag Metadata table above. Remember to transform enumeration values (like error codes and reasons) from OpenFeature's uppercase format to OpenTelemetry's lowercase snake_case convention.
88+
89+
### Value Handling and Privacy
90+
91+
Flag values can contain large or sensitive data, so implementations should provide configuration to control whether values are included in telemetry signals. It's the users' responsibility to manage this configuration. When values are included, they need to be serialized appropriately for OpenTelemetry.
92+
93+
Consider providing mechanisms to redact or obfuscate sensitive flag values, along with size limits to prevent telemetry bloat. This helps balance observability needs with privacy and performance concerns.
94+
95+
### Configuration Options
96+
97+
For consistency across implementations, consider supporting a common set of configuration options:
98+
99+
- `attributeMapper` (function): Custom function to add additional attributes to the signal
100+
- `excludeAttributes` (list): List of attribute keys to exclude from the signal
101+
- `excludeExceptions` (boolean): Whether to omit [exception details][otel-exception-details] from error signals
102+
- `eventMutator` (function): Custom function to modify event attributes before sending
103+
104+
### Error Handling
105+
106+
Hooks should be designed to never throw exceptions that interrupt flag evaluation. Any internal errors can be logged at appropriate levels (debug/trace) without affecting application execution.
107+
108+
### Implementation Patterns
109+
110+
#### Common Base Class
111+
112+
In object-oriented languages, you might find it helpful to create a base hook class containing common functionality shared across all telemetry hook types. This typically includes:
113+
114+
- Shared configuration options
115+
- Attribute building and transformation methods
116+
- Enumeration format conversion
117+
- Metadata extraction logic
118+
- Logger instances for internal debugging
119+
120+
This pattern can reduce code duplication and ensure consistency across different hook implementations, though it's not required.
121+
54122
## History
55123

56-
Feature flags in the OpenTelemetry semantic conventions are currently in development and are marked as experimental.
124+
Feature flags in the OpenTelemetry semantic conventions are currently in development and are marked as a release candidate.
57125
The following table describes the history of changes to the OpenTelemetry feature flag event records as it progresses towards a stable release.
58126

59127
| Original Field Name | New Field Name | Semantic Convention Release |
@@ -71,3 +139,6 @@ The following table describes the history of changes to the OpenTelemetry featur
71139
[^3]: Include `error.type` and `error.message`, if and only if an error occurred during a flag evaluation.
72140

73141
[otel-ff-events]: https://opentelemetry.io/docs/specs/semconv/feature-flags/feature-flags-logs/
142+
[otel-span-event-deprecation-plan]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/4430-span-event-api-deprecation-plan.md
143+
[otel-record-error]: https://opentelemetry.io/docs/specs/semconv/general/recording-errors/
144+
[otel-exception-details]: https://opentelemetry.io/docs/specs/semconv/exceptions/

0 commit comments

Comments
 (0)