From ae6fc0cac9528ee1f57c902e6c823eafc327d797 Mon Sep 17 00:00:00 2001 From: Michael Beemer Date: Wed, 14 May 2025 19:58:51 +0000 Subject: [PATCH] refactor(telemetry): update telemetry attributes and remove unused evaluation data Signed-off-by: Michael Beemer --- packages/shared/src/evaluation/evaluation.ts | 2 +- packages/shared/src/telemetry/attributes.ts | 31 ++++++++++++------- .../shared/src/telemetry/evaluation-data.ts | 17 ---------- .../shared/src/telemetry/evaluation-event.ts | 17 +++++----- packages/shared/src/telemetry/index.ts | 1 - packages/shared/test/telemetry.spec.ts | 8 ++--- 6 files changed, 34 insertions(+), 42 deletions(-) delete mode 100644 packages/shared/src/telemetry/evaluation-data.ts diff --git a/packages/shared/src/evaluation/evaluation.ts b/packages/shared/src/evaluation/evaluation.ts index 895a1ddcc..78e7b65cb 100644 --- a/packages/shared/src/evaluation/evaluation.ts +++ b/packages/shared/src/evaluation/evaluation.ts @@ -3,7 +3,7 @@ import type { JsonValue } from '../types/structure'; export type FlagValueType = 'boolean' | 'string' | 'number' | 'object'; /** - * Represents a JSON node value, or Date. + * Represents a JSON node value. */ export type FlagValue = boolean | string | number | JsonValue; diff --git a/packages/shared/src/telemetry/attributes.ts b/packages/shared/src/telemetry/attributes.ts index 320e24881..c61808456 100644 --- a/packages/shared/src/telemetry/attributes.ts +++ b/packages/shared/src/telemetry/attributes.ts @@ -20,6 +20,14 @@ export const TelemetryAttribute = { * - example: `flag_not_found` */ ERROR_CODE: 'error.type', + /** + * A message explaining the nature of an error occurring during flag evaluation. + * + * - type: `string` + * - requirement level: `recommended` + * - example: `Flag not found` + */ + ERROR_MESSAGE: 'error.message', /** * A semantic identifier for an evaluated flag value. * @@ -28,23 +36,24 @@ export const TelemetryAttribute = { * - condition: variant is defined on the evaluation details * - example: `blue`; `on`; `true` */ - VARIANT: 'feature_flag.variant', + VARIANT: 'feature_flag.result.variant', /** - * The unique identifier for the flag evaluation context. For example, the targeting key. + * The evaluated value of the feature flag. * - * - type: `string` - * - requirement level: `recommended` - * - example: `5157782b-2203-4c80-a857-dbbd5e7761db` + * - type: `undefined` + * - requirement level: `conditionally required` + * - condition: variant is not defined on the evaluation details + * - example: `#ff0000`; `1`; `true` */ - CONTEXT_ID: 'feature_flag.context.id', + VALUE: 'feature_flag.result.value', /** - * A message explaining the nature of an error occurring during flag evaluation. + * The unique identifier for the flag evaluation context. For example, the targeting key. * * - type: `string` * - requirement level: `recommended` - * - example: `Flag not found` + * - example: `5157782b-2203-4c80-a857-dbbd5e7761db` */ - ERROR_MESSAGE: 'feature_flag.evaluation.error.message', + CONTEXT_ID: 'feature_flag.context.id', /** * The reason code which shows how a feature flag value was determined. * @@ -52,7 +61,7 @@ export const TelemetryAttribute = { * - requirement level: `recommended` * - example: `targeting_match` */ - REASON: 'feature_flag.evaluation.reason', + REASON: 'feature_flag.result.reason', /** * Describes a class of error the operation ended with. * @@ -60,7 +69,7 @@ export const TelemetryAttribute = { * - requirement level: `recommended` * - example: `flag_not_found` */ - PROVIDER: 'feature_flag.provider_name', + PROVIDER: 'feature_flag.provider.name', /** * The identifier of the flag set to which the feature flag belongs. * diff --git a/packages/shared/src/telemetry/evaluation-data.ts b/packages/shared/src/telemetry/evaluation-data.ts deleted file mode 100644 index ef0b5f6ab..000000000 --- a/packages/shared/src/telemetry/evaluation-data.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Event data, sometimes referred as "body", is specific to a specific event. - * In this case, the event is `feature_flag.evaluation`. That's why the prefix - * is omitted from the values. - * @see https://opentelemetry.io/docs/specs/semconv/feature-flags/feature-flags-logs/ - */ -export const TelemetryEvaluationData = { - /** - * The evaluated value of the feature flag. - * - * - type: `undefined` - * - requirement level: `conditionally required` - * - condition: variant is not defined on the evaluation details - * - example: `#ff0000`; `1`; `true` - */ - VALUE: 'value', -} as const; diff --git a/packages/shared/src/telemetry/evaluation-event.ts b/packages/shared/src/telemetry/evaluation-event.ts index 3ee1630d7..81a85aad2 100644 --- a/packages/shared/src/telemetry/evaluation-event.ts +++ b/packages/shared/src/telemetry/evaluation-event.ts @@ -1,14 +1,19 @@ import { ErrorCode, StandardResolutionReasons, type EvaluationDetails, type FlagValue } from '../evaluation/evaluation'; import type { HookContext } from '../hooks/hooks'; -import type { JsonValue } from '../types'; import { TelemetryAttribute } from './attributes'; -import { TelemetryEvaluationData } from './evaluation-data'; import { TelemetryFlagMetadata } from './flag-metadata'; type EvaluationEvent = { + /** + * The name of the feature flag evaluation event. + */ name: string; - attributes: Record; - body: Record; + /** + * The attributes of an OpenTelemetry compliant event for flag evaluation. + * @experimental The attributes are subject to change. + * @see https://opentelemetry.io/docs/specs/semconv/feature-flags/feature-flags-logs/ + */ + attributes: Record; }; const FLAG_EVALUATION_EVENT_NAME = 'feature_flag.evaluation'; @@ -28,12 +33,11 @@ export function createEvaluationEvent( [TelemetryAttribute.PROVIDER]: hookContext.providerMetadata.name, [TelemetryAttribute.REASON]: (evaluationDetails.reason ?? StandardResolutionReasons.UNKNOWN).toLowerCase(), }; - const body: EvaluationEvent['body'] = {}; if (evaluationDetails.variant) { attributes[TelemetryAttribute.VARIANT] = evaluationDetails.variant; } else { - body[TelemetryEvaluationData.VALUE] = evaluationDetails.value; + attributes[TelemetryAttribute.VALUE] = evaluationDetails.value; } const contextId = @@ -62,6 +66,5 @@ export function createEvaluationEvent( return { name: FLAG_EVALUATION_EVENT_NAME, attributes, - body, }; } diff --git a/packages/shared/src/telemetry/index.ts b/packages/shared/src/telemetry/index.ts index f77746305..2f1561707 100644 --- a/packages/shared/src/telemetry/index.ts +++ b/packages/shared/src/telemetry/index.ts @@ -1,4 +1,3 @@ export * from './attributes'; -export * from './evaluation-data'; export * from './flag-metadata'; export * from './evaluation-event'; diff --git a/packages/shared/test/telemetry.spec.ts b/packages/shared/test/telemetry.spec.ts index 62d9871cf..35cbe7917 100644 --- a/packages/shared/test/telemetry.spec.ts +++ b/packages/shared/test/telemetry.spec.ts @@ -1,7 +1,7 @@ import { createEvaluationEvent } from '../src/telemetry/evaluation-event'; import { ErrorCode, StandardResolutionReasons, type EvaluationDetails } from '../src/evaluation/evaluation'; import type { HookContext } from '../src/hooks/hooks'; -import { TelemetryAttribute, TelemetryFlagMetadata, TelemetryEvaluationData } from '../src/telemetry'; +import { TelemetryAttribute, TelemetryFlagMetadata } from '../src/telemetry'; describe('evaluationEvent', () => { const flagKey = 'test-flag'; @@ -43,9 +43,7 @@ describe('evaluationEvent', () => { [TelemetryAttribute.PROVIDER]: 'test-provider', [TelemetryAttribute.REASON]: StandardResolutionReasons.STATIC.toLowerCase(), [TelemetryAttribute.CONTEXT_ID]: 'test-target', - }); - expect(result.body).toEqual({ - [TelemetryEvaluationData.VALUE]: true, + [TelemetryAttribute.VALUE]: true, }); }); @@ -61,7 +59,7 @@ describe('evaluationEvent', () => { const result = createEvaluationEvent(mockHookContext, details); expect(result.attributes[TelemetryAttribute.VARIANT]).toBe('test-variant'); - expect(result.attributes[TelemetryEvaluationData.VALUE]).toBeUndefined(); + expect(result.attributes[TelemetryAttribute.VALUE]).toBeUndefined(); }); it('should include flag metadata when provided', () => {