From e16b2befcecc1ccae269c3d09801ed793bd4836a Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 12 Nov 2025 12:42:08 +0100 Subject: [PATCH] feat(core): Apply scope attributes to logs --- packages/core/src/attributes.ts | 4 +- packages/core/src/logs/internal.ts | 62 +++++----------------------- packages/core/src/scope.ts | 8 ++-- packages/core/src/types-hoist/log.ts | 9 +--- 4 files changed, 18 insertions(+), 65 deletions(-) diff --git a/packages/core/src/attributes.ts b/packages/core/src/attributes.ts index 529a89bce05f..9be3a0aa1c0a 100644 --- a/packages/core/src/attributes.ts +++ b/packages/core/src/attributes.ts @@ -1,4 +1,4 @@ -export type Attributes = Record; +export type TypedAttributes = Record; export type AttributeValueType = string | number | boolean | Array | Array | Array; @@ -47,7 +47,7 @@ type Units = 'ms' | 's' | 'bytes' | 'count' | 'percent'; * @param value - The value of the passed attribute. * @returns The typed attribute. */ -export function attributeValueToTypedAttributeValue(value: AttributeValueType): TypedAttributeValue { +export function attributeValueToTypedAttributeValue(value: unknown): TypedAttributeValue { switch (typeof value) { case 'number': if (Number.isInteger(value)) { diff --git a/packages/core/src/logs/internal.ts b/packages/core/src/logs/internal.ts index 601d9be29cb6..137e1cb32220 100644 --- a/packages/core/src/logs/internal.ts +++ b/packages/core/src/logs/internal.ts @@ -1,10 +1,12 @@ +import type { TypedAttributes } from '../attributes'; +import { attributeValueToTypedAttributeValue } from '../attributes'; import { getGlobalSingleton } from '../carrier'; import type { Client } from '../client'; import { getClient, getCurrentScope, getGlobalScope, getIsolationScope } from '../currentScopes'; import { DEBUG_BUILD } from '../debug-build'; import type { Scope, ScopeData } from '../scope'; import type { Integration } from '../types-hoist/integration'; -import type { Log, SerializedLog, SerializedLogAttributeValue } from '../types-hoist/log'; +import type { Log, SerializedLog } from '../types-hoist/log'; import { mergeScopeData } from '../utils/applyScopeDataToEvent'; import { consoleSandbox, debug } from '../utils/debug-logger'; import { isParameterizedString } from '../utils/is'; @@ -16,51 +18,6 @@ import { createLogEnvelope } from './envelope'; const MAX_LOG_BUFFER_SIZE = 100; -/** - * Converts a log attribute to a serialized log attribute. - * - * @param key - The key of the log attribute. - * @param value - The value of the log attribute. - * @returns The serialized log attribute. - */ -export function logAttributeToSerializedLogAttribute(value: unknown): SerializedLogAttributeValue { - switch (typeof value) { - case 'number': - if (Number.isInteger(value)) { - return { - value, - type: 'integer', - }; - } - return { - value, - type: 'double', - }; - case 'boolean': - return { - value, - type: 'boolean', - }; - case 'string': - return { - value, - type: 'string', - }; - default: { - let stringValue = ''; - try { - stringValue = JSON.stringify(value) ?? ''; - } catch { - // Do nothing - } - return { - value: stringValue, - type: 'string', - }; - } - } -} - /** * Sets a log attribute if the value exists and the attribute key is not already present. * @@ -139,6 +96,7 @@ export function _INTERNAL_captureLog( const { user: { id, email, username }, + attributes: scopeAttributes, } = getMergedScopeData(currentScope); setLogAttribute(processedLogAttributes, 'user.id', id, false); setLogAttribute(processedLogAttributes, 'user.email', email, false); @@ -201,13 +159,13 @@ export function _INTERNAL_captureLog( body: message, trace_id: traceContext?.trace_id, severity_number: severityNumber ?? SEVERITY_TEXT_TO_SEVERITY_NUMBER[level], - attributes: Object.keys(attributes).reduce( - (acc, key) => { - acc[key] = logAttributeToSerializedLogAttribute(attributes[key]); + attributes: { + ...scopeAttributes, + ...Object.keys(attributes).reduce((acc, key) => { + acc[key] = attributeValueToTypedAttributeValue(attributes[key]); return acc; - }, - {} as Record, - ), + }, {} as TypedAttributes), + }, }; captureSerializedLog(client, serializedLog); diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index be35f7469a55..70d3745b3a24 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -1,5 +1,5 @@ /* eslint-disable max-lines */ -import type { Attributes, AttributeValueType, TypedAttributeValue } from './attributes'; +import type { AttributeValueType, TypedAttributes, TypedAttributeValue } from './attributes'; import { attributeValueToTypedAttributeValue } from './attributes'; import type { Client } from './client'; import { DEBUG_BUILD } from './debug-build'; @@ -48,7 +48,7 @@ export interface ScopeContext { extra: Extras; contexts: Contexts; tags: { [key: string]: Primitive }; - attributes?: Attributes; + attributes?: TypedAttributes; fingerprint: string[]; propagationContext: PropagationContext; } @@ -75,7 +75,7 @@ export interface ScopeData { user: User; tags: { [key: string]: Primitive }; // TODO(v11): Make this a required field (could be subtly breaking if we did it today) - attributes?: Attributes; + attributes?: TypedAttributes; extra: Extras; contexts: Contexts; attachments: Attachment[]; @@ -110,7 +110,7 @@ export class Scope { protected _tags: { [key: string]: Primitive }; /** Attributes */ - protected _attributes: Attributes; + protected _attributes: TypedAttributes; /** Extra */ protected _extra: Extras; diff --git a/packages/core/src/types-hoist/log.ts b/packages/core/src/types-hoist/log.ts index 1a6e3974e91e..04dbb4f3a149 100644 --- a/packages/core/src/types-hoist/log.ts +++ b/packages/core/src/types-hoist/log.ts @@ -1,3 +1,4 @@ +import type { TypedAttributes } from '../attributes'; import type { ParameterizedString } from './parameterize'; export type LogSeverityLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; @@ -30,12 +31,6 @@ export interface Log { severityNumber?: number; } -export type SerializedLogAttributeValue = - | { value: string; type: 'string' } - | { value: number; type: 'integer' } - | { value: number; type: 'double' } - | { value: boolean; type: 'boolean' }; - export interface SerializedLog { /** * Timestamp in seconds (epoch time) indicating when the log occurred. @@ -60,7 +55,7 @@ export interface SerializedLog { /** * Arbitrary structured data that stores information about the log - e.g., userId: 100. */ - attributes?: Record; + attributes?: TypedAttributes; /** * The severity number.