From 8eb9bf30a3e4b1fbe410a5d3e1176297cb4a60a5 Mon Sep 17 00:00:00 2001 From: Abinet18 <35442169+Abinet18@users.noreply.github.com> Date: Thu, 1 Jun 2023 22:23:06 -0700 Subject: [PATCH] feat/logattributes support map type (#3821) Co-authored-by: Marc Pichler --- experimental/CHANGELOG.md | 1 + .../packages/api-logs/src/types/LogRecord.ts | 9 +++++++-- .../packages/api-logs/src/types/LoggerOptions.ts | 2 -- .../packages/otlp-transformer/package.json | 1 + .../otlp-transformer/src/common/internal.ts | 2 +- .../packages/otlp-transformer/src/logs/index.ts | 10 ++++++++-- experimental/packages/sdk-logs/package.json | 2 +- experimental/packages/sdk-logs/src/LogRecord.ts | 16 ++++++++++++---- .../sdk-logs/src/export/ReadableLogRecord.ts | 6 +++--- .../packages/sdk-logs/test/common/utils.ts | 5 +++-- 10 files changed, 37 insertions(+), 17 deletions(-) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 60a3bb2664..f5dbfd2a8f 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to experimental packages in this project will be documented ### :rocket: (Enhancement) +* feat(api-logs): support map in log attributes. [#3821](https://github.com/open-telemetry/opentelemetry-js/pull/3821) @Abinet18 * feat(instrumentation): add ESM support for instrumentation. [#3698](https://github.com/open-telemetry/opentelemetry-js/pull/3698) @JamieDanielson, @pkanal, @vmarchaud, @lizthegrey, @bengl * feat(exporter-logs-otlp-http): otlp-http exporter for logs. [#3764](https://github.com/open-telemetry/opentelemetry-js/pull/3764/) @fuaiyi * feat(otlp-trace-exporters): Add User-Agent header to OTLP trace exporters. [#3790](https://github.com/open-telemetry/opentelemetry-js/pull/3790) @JamieDanielson diff --git a/experimental/packages/api-logs/src/types/LogRecord.ts b/experimental/packages/api-logs/src/types/LogRecord.ts index e1c1100c5f..59718aa30b 100644 --- a/experimental/packages/api-logs/src/types/LogRecord.ts +++ b/experimental/packages/api-logs/src/types/LogRecord.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { Attributes, Context } from '@opentelemetry/api'; +import { AttributeValue, Context } from '@opentelemetry/api'; + +export type LogAttributeValue = AttributeValue | LogAttributes; +export interface LogAttributes { + [attributeKey: string]: LogAttributeValue | undefined; +} export enum SeverityNumber { UNSPECIFIED = 0, @@ -73,7 +78,7 @@ export interface LogRecord { /** * Attributes that define the log record. */ - attributes?: Attributes; + attributes?: LogAttributes; /** * The Context associated with the LogRecord. diff --git a/experimental/packages/api-logs/src/types/LoggerOptions.ts b/experimental/packages/api-logs/src/types/LoggerOptions.ts index a57d44a739..fdcedcb464 100644 --- a/experimental/packages/api-logs/src/types/LoggerOptions.ts +++ b/experimental/packages/api-logs/src/types/LoggerOptions.ts @@ -13,9 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { Attributes } from '@opentelemetry/api'; - export interface LoggerOptions { /** * The schemaUrl of the tracer or instrumentation library diff --git a/experimental/packages/otlp-transformer/package.json b/experimental/packages/otlp-transformer/package.json index 0935e42559..cc1e43642e 100644 --- a/experimental/packages/otlp-transformer/package.json +++ b/experimental/packages/otlp-transformer/package.json @@ -57,6 +57,7 @@ "devDependencies": { "@opentelemetry/api": "1.4.1", "@opentelemetry/api-logs": "0.39.1", + "@opentelemetry/sdk-logs": "0.39.1", "@types/mocha": "10.0.0", "@types/webpack-env": "1.16.3", "codecov": "3.8.3", diff --git a/experimental/packages/otlp-transformer/src/common/internal.ts b/experimental/packages/otlp-transformer/src/common/internal.ts index 5612b87ce9..0fe649f525 100644 --- a/experimental/packages/otlp-transformer/src/common/internal.ts +++ b/experimental/packages/otlp-transformer/src/common/internal.ts @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { Attributes } from '@opentelemetry/api'; import type { IAnyValue, IKeyValue } from './types'; +import { Attributes } from '@opentelemetry/api'; export function toAttributes(attributes: Attributes): IKeyValue[] { return Object.keys(attributes).map(key => toKeyValue(key, attributes[key])); diff --git a/experimental/packages/otlp-transformer/src/logs/index.ts b/experimental/packages/otlp-transformer/src/logs/index.ts index 6fa4d11e86..c499476498 100644 --- a/experimental/packages/otlp-transformer/src/logs/index.ts +++ b/experimental/packages/otlp-transformer/src/logs/index.ts @@ -22,9 +22,11 @@ import { IResourceLogs, } from './types'; import { IResource } from '@opentelemetry/resources'; -import { toAnyValue, toAttributes } from '../common/internal'; +import { toAnyValue, toAttributes, toKeyValue } from '../common/internal'; import { hexToBase64, hrTimeToNanoseconds } from '@opentelemetry/core'; import { SeverityNumber } from '@opentelemetry/api-logs'; +import { IKeyValue } from '../common/types'; +import { LogAttributes } from '@opentelemetry/api-logs'; export function createExportLogsServiceRequest( logRecords: ReadableLogRecord[], @@ -97,7 +99,7 @@ function toLogRecord(log: ReadableLogRecord, useHex?: boolean): ILogRecord { severityNumber: toSeverityNumber(log.severityNumber), severityText: log.severityText, body: toAnyValue(log.body), - attributes: toAttributes(log.attributes), + attributes: toLogAttributes(log.attributes), droppedAttributesCount: 0, flags: log.spanContext?.traceFlags, traceId: useHex @@ -119,3 +121,7 @@ function optionalHexToBase64(str: string | undefined): string | undefined { if (str === undefined) return undefined; return hexToBase64(str); } + +export function toLogAttributes(attributes: LogAttributes): IKeyValue[] { + return Object.keys(attributes).map(key => toKeyValue(key, attributes[key])); +} diff --git a/experimental/packages/sdk-logs/package.json b/experimental/packages/sdk-logs/package.json index be9010f5a7..f4222cb545 100644 --- a/experimental/packages/sdk-logs/package.json +++ b/experimental/packages/sdk-logs/package.json @@ -69,7 +69,7 @@ "sideEffects": false, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.5.0", - "@opentelemetry/api-logs": ">=0.38.0" + "@opentelemetry/api-logs": ">=0.39.1" }, "devDependencies": { "@opentelemetry/api": ">=1.4.0 <1.5.0", diff --git a/experimental/packages/sdk-logs/src/LogRecord.ts b/experimental/packages/sdk-logs/src/LogRecord.ts index 9d3e909feb..d184004e6b 100644 --- a/experimental/packages/sdk-logs/src/LogRecord.ts +++ b/experimental/packages/sdk-logs/src/LogRecord.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Attributes, AttributeValue, diag } from '@opentelemetry/api'; +import { AttributeValue, diag } from '@opentelemetry/api'; import type * as logsAPI from '@opentelemetry/api-logs'; import * as api from '@opentelemetry/api'; import { @@ -27,6 +27,7 @@ import type { IResource } from '@opentelemetry/resources'; import type { ReadableLogRecord } from './export/ReadableLogRecord'; import type { LogRecordLimits } from './types'; import { Logger } from './Logger'; +import { LogAttributes } from '@opentelemetry/api-logs'; export class LogRecord implements ReadableLogRecord { readonly hrTime: api.HrTime; @@ -34,7 +35,7 @@ export class LogRecord implements ReadableLogRecord { readonly spanContext?: api.SpanContext; readonly resource: IResource; readonly instrumentationScope: InstrumentationScope; - readonly attributes: Attributes = {}; + readonly attributes: logsAPI.LogAttributes = {}; private _severityText?: string; private _severityNumber?: logsAPI.SeverityNumber; private _body?: string; @@ -102,13 +103,20 @@ export class LogRecord implements ReadableLogRecord { this.setAttributes(attributes); } - public setAttribute(key: string, value?: AttributeValue) { + public setAttribute(key: string, value?: LogAttributes | AttributeValue) { if (this._isLogRecordReadonly()) { return this; } if (value === null) { return this; } + if ( + typeof value === 'object' && + !Array.isArray(value) && + Object.keys(value).length > 0 + ) { + this.attributes[key] = value; + } if (key.length === 0) { api.diag.warn(`Invalid attribute key: ${key}`); return this; @@ -128,7 +136,7 @@ export class LogRecord implements ReadableLogRecord { return this; } - public setAttributes(attributes: Attributes) { + public setAttributes(attributes: LogAttributes) { for (const [k, v] of Object.entries(attributes)) { this.setAttribute(k, v); } diff --git a/experimental/packages/sdk-logs/src/export/ReadableLogRecord.ts b/experimental/packages/sdk-logs/src/export/ReadableLogRecord.ts index 72fe7d1d35..a7eff21e2d 100644 --- a/experimental/packages/sdk-logs/src/export/ReadableLogRecord.ts +++ b/experimental/packages/sdk-logs/src/export/ReadableLogRecord.ts @@ -15,9 +15,9 @@ */ import type { IResource } from '@opentelemetry/resources'; -import type { Attributes, HrTime, SpanContext } from '@opentelemetry/api'; +import type { HrTime, SpanContext } from '@opentelemetry/api'; import type { InstrumentationScope } from '@opentelemetry/core'; -import type { SeverityNumber } from '@opentelemetry/api-logs'; +import type { LogAttributes, SeverityNumber } from '@opentelemetry/api-logs'; export interface ReadableLogRecord { readonly hrTime: HrTime; @@ -28,5 +28,5 @@ export interface ReadableLogRecord { readonly body?: string; readonly resource: IResource; readonly instrumentationScope: InstrumentationScope; - readonly attributes: Attributes; + readonly attributes: LogAttributes; } diff --git a/experimental/packages/sdk-logs/test/common/utils.ts b/experimental/packages/sdk-logs/test/common/utils.ts index fd801fc30d..80dc84e0c7 100644 --- a/experimental/packages/sdk-logs/test/common/utils.ts +++ b/experimental/packages/sdk-logs/test/common/utils.ts @@ -21,11 +21,12 @@ export const validAttributes = { 'array': ['str1', 'str2'], 'array': [1, 2], 'array': [true, false], + object: { bar: 'foo' }, }; export const invalidAttributes = { - // invalid attribute type object - object: { foo: 'bar' }, + // invalid attribute empty object + object: {}, // invalid attribute inhomogeneous array 'non-homogeneous-array': [0, ''], // This empty length attribute should not be set