Skip to content

Commit 4cca19f

Browse files
committed
feat(sdk-logs): logger option support includeTraceContext & LogRecordProcessor onEmit suport context
1 parent f423693 commit 4cca19f

File tree

12 files changed

+126
-71
lines changed

12 files changed

+126
-71
lines changed

experimental/packages/api-logs/src/types/LogRecord.ts

+3-13
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Attributes } from '@opentelemetry/api';
17+
import { Attributes, Context } from '@opentelemetry/api';
1818

1919
export enum SeverityNumber {
2020
UNSPECIFIED = 0,
@@ -71,17 +71,7 @@ export interface LogRecord {
7171
attributes?: Attributes;
7272

7373
/**
74-
* 8 least significant bits are the trace flags as defined in W3C Trace Context specification.
74+
* The Context associated with the LogRecord.
7575
*/
76-
traceFlags?: number;
77-
78-
/**
79-
* A unique identifier for a trace.
80-
*/
81-
traceId?: string;
82-
83-
/**
84-
* A unique identifier for a span within a trace.
85-
*/
86-
spanId?: string;
76+
context?: Context;
8777
}

experimental/packages/api-logs/src/types/LoggerOptions.ts

+6
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,10 @@ export interface LoggerOptions {
2727
* The instrumentation scope attributes to associate with emitted telemetry
2828
*/
2929
scopeAttributes?: Attributes;
30+
31+
/**
32+
* Specifies whether the Trace Context should automatically be passed on to the LogRecords emitted by the Logger.
33+
* @default true
34+
*/
35+
includeTraceContext?: boolean;
3036
}

experimental/packages/sdk-logs/src/LogRecord.ts

+12-12
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ import type { ReadableLogRecord } from './export/ReadableLogRecord';
2828
import type { LogRecordLimits } from './types';
2929
import { Logger } from './Logger';
3030

31-
export class LogRecord implements logsAPI.LogRecord, ReadableLogRecord {
32-
readonly time: api.HrTime;
33-
readonly traceId?: string;
34-
readonly spanId?: string;
35-
readonly traceFlags?: number;
31+
export class LogRecord implements ReadableLogRecord {
32+
readonly hrTime: api.HrTime;
33+
readonly spanContext?: api.SpanContext;
3634
readonly resource: IResource;
3735
readonly instrumentationScope: InstrumentationScope;
3836
readonly attributes: Attributes = {};
3937
private _severityText?: string;
4038
private _severityNumber?: logsAPI.SeverityNumber;
4139
private _body?: string;
40+
4241
private _isReadonly: boolean = false;
4342
private readonly _logRecordLimits: LogRecordLimits;
4443

@@ -79,15 +78,16 @@ export class LogRecord implements logsAPI.LogRecord, ReadableLogRecord {
7978
severityText,
8079
body,
8180
attributes = {},
82-
spanId,
83-
traceFlags,
84-
traceId,
81+
context,
8582
} = logRecord;
8683

87-
this.time = timeInputToHrTime(timestamp);
88-
this.spanId = spanId;
89-
this.traceId = traceId;
90-
this.traceFlags = traceFlags;
84+
this.hrTime = timeInputToHrTime(timestamp);
85+
if (context) {
86+
const spanContext = api.trace.getSpanContext(context);
87+
if (spanContext && api.isSpanContextValid(spanContext)) {
88+
this.spanContext = spanContext;
89+
}
90+
}
9191
this.severityNumber = severityNumber;
9292
this.severityText = severityText;
9393
this.body = body;

experimental/packages/sdk-logs/src/LogRecordProcessor.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { Context } from '@opentelemetry/api';
18+
1719
import { LogRecord } from './LogRecord';
1820

1921
export interface LogRecordProcessor {
@@ -25,8 +27,9 @@ export interface LogRecordProcessor {
2527
/**
2628
* Called when a {@link LogRecord} is emit
2729
* @param logRecord the ReadWriteLogRecord that just emitted.
30+
* @param context the current Context, or an empty Context if the Logger was obtained with include_trace_context=false
2831
*/
29-
onEmit(logRecord: LogRecord): void;
32+
onEmit(logRecord: LogRecord, context?: Context): void;
3033

3134
/**
3235
* Shuts down the processor. Called when SDK is shut down. This is an

experimental/packages/sdk-logs/src/Logger.ts

+24-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import type * as logsAPI from '@opentelemetry/api-logs';
1818
import type { IResource } from '@opentelemetry/resources';
1919
import type { InstrumentationScope } from '@opentelemetry/core';
20+
import { context } from '@opentelemetry/api';
2021

2122
import type { LoggerConfig, LogRecordLimits } from './types';
2223
import { LogRecord } from './LogRecord';
@@ -26,21 +27,38 @@ import { LogRecordProcessor } from './LogRecordProcessor';
2627

2728
export class Logger implements logsAPI.Logger {
2829
public readonly resource: IResource;
29-
private readonly _logRecordLimits: LogRecordLimits;
30+
private readonly _loggerConfig: Required<LoggerConfig>;
3031

3132
constructor(
3233
public readonly instrumentationScope: InstrumentationScope,
3334
config: LoggerConfig,
3435
private _loggerProvider: LoggerProvider
3536
) {
36-
const localConfig = mergeConfig(config);
37+
this._loggerConfig = mergeConfig(config);
3738
this.resource = _loggerProvider.resource;
38-
this._logRecordLimits = localConfig.logRecordLimits!;
3939
}
4040

4141
public emit(logRecord: logsAPI.LogRecord): void {
42-
const logRecordInstance = new LogRecord(this, logRecord);
43-
this.getActiveLogRecordProcessor().onEmit(logRecordInstance);
42+
const currentContext = this._loggerConfig.includeTraceContext
43+
? context.active()
44+
: undefined;
45+
/**
46+
* If a Logger was obtained with include_trace_context=true,
47+
* the LogRecords it emits MUST automatically include the Trace Context from the active Context,
48+
* if Context has not been explicitly set.
49+
*/
50+
const logRecordInstance = new LogRecord(this, {
51+
context: currentContext,
52+
...logRecord,
53+
});
54+
/**
55+
* the explicitly passed Context,
56+
* the current Context, or an empty Context if the Logger was obtained with include_trace_context=false
57+
*/
58+
this.getActiveLogRecordProcessor().onEmit(
59+
logRecordInstance,
60+
currentContext
61+
);
4462
/**
4563
* A LogRecordProcessor may freely modify logRecord for the duration of the OnEmit call.
4664
* If logRecord is needed after OnEmit returns (i.e. for asynchronous processing) only reads are permitted.
@@ -49,7 +67,7 @@ export class Logger implements logsAPI.Logger {
4967
}
5068

5169
public getLogRecordLimits(): LogRecordLimits {
52-
return this._logRecordLimits;
70+
return this._loggerConfig.logRecordLimits;
5371
}
5472

5573
public getActiveLogRecordProcessor(): LogRecordProcessor {

experimental/packages/sdk-logs/src/LoggerProvider.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ export class LoggerProvider implements logsAPI.LoggerProvider {
8282
key,
8383
new Logger(
8484
{ name: loggerName, version, schemaUrl: options?.schemaUrl },
85-
this._config,
85+
{
86+
logRecordLimits: this._config.logRecordLimits,
87+
includeTraceContext: options?.includeTraceContext,
88+
},
8689
this
8790
)
8891
);

experimental/packages/sdk-logs/src/config.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
getEnv,
2121
getEnvWithoutDefaults,
2222
} from '@opentelemetry/core';
23-
import { LoggerConfig, LogRecordLimits } from './types';
23+
import { LoggerConfig } from './types';
2424

2525
export function loadDefaultConfig() {
2626
return {
@@ -30,6 +30,7 @@ export function loadDefaultConfig() {
3030
getEnv().OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT,
3131
attributeCountLimit: getEnv().OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT,
3232
},
33+
includeTraceContext: true,
3334
};
3435
}
3536

@@ -68,9 +69,7 @@ export function reconfigureLimits(userConfig: LoggerConfig): LoggerConfig {
6869
* Function to merge Default configuration (as specified in './config') with
6970
* user provided configurations.
7071
*/
71-
export function mergeConfig(userConfig: LoggerConfig): LoggerConfig & {
72-
logRecordLimits: LogRecordLimits;
73-
} {
72+
export function mergeConfig(userConfig: LoggerConfig): Required<LoggerConfig> {
7473
const DEFAULT_CONFIG = loadDefaultConfig();
7574

7675
const target = Object.assign({}, DEFAULT_CONFIG, userConfig);

experimental/packages/sdk-logs/src/export/ConsoleLogRecordExporter.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ export class ConsoleLogRecordExporter implements LogRecordExporter {
5252
*/
5353
private _exportInfo(logRecord: ReadableLogRecord) {
5454
return {
55-
timestamp: hrTimeToMicroseconds(logRecord.time),
56-
traceId: logRecord.traceId,
57-
spanId: logRecord.spanId,
58-
traceFlags: logRecord.traceFlags,
55+
timestamp: hrTimeToMicroseconds(logRecord.hrTime),
56+
traceId: logRecord.spanContext?.traceId,
57+
spanId: logRecord.spanContext?.spanId,
58+
traceFlags: logRecord.spanContext?.traceFlags,
5959
severityText: logRecord.severityText,
6060
severityNumber: logRecord.severityNumber,
6161
body: logRecord.body,

experimental/packages/sdk-logs/src/export/ReadableLogRecord.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@
1515
*/
1616

1717
import type { IResource } from '@opentelemetry/resources';
18-
import type { Attributes, HrTime } from '@opentelemetry/api';
18+
import type { Attributes, HrTime, SpanContext } from '@opentelemetry/api';
1919
import type { InstrumentationScope } from '@opentelemetry/core';
2020
import type { SeverityNumber } from '@opentelemetry/api-logs';
2121

2222
export interface ReadableLogRecord {
23-
readonly time: HrTime;
24-
readonly traceId?: string;
25-
readonly spanId?: string;
26-
readonly traceFlags?: number;
23+
readonly hrTime: HrTime;
24+
readonly spanContext?: SpanContext;
2725
readonly severityText?: string;
2826
readonly severityNumber?: SeverityNumber;
2927
readonly body?: string;

experimental/packages/sdk-logs/src/types.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import type { IResource } from '@opentelemetry/resources';
1818

19-
export interface LoggerProviderConfig extends LoggerConfig {
19+
export interface LoggerProviderConfig {
2020
/** Resource associated with trace telemetry */
2121
resource?: IResource;
2222

@@ -25,11 +25,17 @@ export interface LoggerProviderConfig extends LoggerConfig {
2525
* The default value is 30000ms
2626
*/
2727
forceFlushTimeoutMillis?: number;
28+
29+
/** Log Record Limits*/
30+
logRecordLimits?: LogRecordLimits;
2831
}
2932

3033
export interface LoggerConfig {
3134
/** Log Record Limits*/
3235
logRecordLimits?: LogRecordLimits;
36+
37+
/** include Trace Context */
38+
includeTraceContext?: boolean;
3339
}
3440

3541
export interface LogRecordLimits {

experimental/packages/sdk-logs/test/common/LogRecord.test.ts

+25-19
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@
1616

1717
import * as sinon from 'sinon';
1818
import * as assert from 'assert';
19-
import { Attributes, AttributeValue, diag } from '@opentelemetry/api';
19+
import {
20+
Attributes,
21+
AttributeValue,
22+
diag,
23+
ROOT_CONTEXT,
24+
trace,
25+
TraceFlags,
26+
} from '@opentelemetry/api';
2027
import * as logsAPI from '@opentelemetry/api-logs';
2128
import type { HrTime } from '@opentelemetry/api';
2229
import { hrTimeToMilliseconds, timeInputToHrTime } from '@opentelemetry/core';
@@ -61,14 +68,21 @@ describe('LogRecord', () => {
6168

6269
it('should have a default timestamp', () => {
6370
const { logRecord } = setup();
64-
assert.ok(logRecord.time !== undefined);
71+
assert.ok(logRecord.hrTime !== undefined);
6572
assert.ok(
66-
hrTimeToMilliseconds(logRecord.time) >
73+
hrTimeToMilliseconds(logRecord.hrTime) >
6774
hrTimeToMilliseconds(performanceTimeOrigin)
6875
);
6976
});
7077

7178
it('should return LogRecord', () => {
79+
const spanContext = {
80+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
81+
spanId: '6e0c63257de34c92',
82+
traceFlags: TraceFlags.SAMPLED,
83+
};
84+
const activeContext = trace.setSpanContext(ROOT_CONTEXT, spanContext);
85+
7286
const logRecordData: logsAPI.LogRecord = {
7387
timestamp: new Date().getTime(),
7488
severityNumber: logsAPI.SeverityNumber.DEBUG,
@@ -77,16 +91,14 @@ describe('LogRecord', () => {
7791
attributes: {
7892
name: 'test name',
7993
},
80-
traceId: 'trance id',
81-
spanId: 'span id',
82-
traceFlags: 1,
94+
context: activeContext,
8395
};
8496
const { logRecord, resource, instrumentationScope } = setup(
8597
undefined,
8698
logRecordData
8799
);
88100
assert.deepStrictEqual(
89-
logRecord.time,
101+
logRecord.hrTime,
90102
timeInputToHrTime(logRecordData.timestamp!)
91103
);
92104
assert.strictEqual(
@@ -96,9 +108,12 @@ describe('LogRecord', () => {
96108
assert.strictEqual(logRecord.severityText, logRecordData.severityText);
97109
assert.strictEqual(logRecord.body, logRecordData.body);
98110
assert.deepStrictEqual(logRecord.attributes, logRecordData.attributes);
99-
assert.deepStrictEqual(logRecord.traceId, logRecordData.traceId);
100-
assert.deepStrictEqual(logRecord.spanId, logRecordData.spanId);
101-
assert.deepStrictEqual(logRecord.traceFlags, logRecordData.traceFlags);
111+
assert.strictEqual(logRecord.spanContext?.traceId, spanContext.traceId);
112+
assert.strictEqual(logRecord.spanContext?.spanId, spanContext.spanId);
113+
assert.strictEqual(
114+
logRecord.spanContext?.traceFlags,
115+
spanContext.traceFlags
116+
);
102117
assert.deepStrictEqual(logRecord.resource, resource);
103118
assert.deepStrictEqual(
104119
logRecord.instrumentationScope,
@@ -115,9 +130,6 @@ describe('LogRecord', () => {
115130
attributes: {
116131
name: 'test name',
117132
},
118-
traceId: 'trance id',
119-
spanId: 'span id',
120-
traceFlags: 1,
121133
};
122134
const { logRecord } = setup(undefined, logRecordData);
123135

@@ -258,9 +270,6 @@ describe('LogRecord', () => {
258270
attributes: {
259271
name: 'test name',
260272
},
261-
traceId: 'trance id',
262-
spanId: 'span id',
263-
traceFlags: 1,
264273
};
265274

266275
const newBody = 'this is a new body';
@@ -302,9 +311,6 @@ describe('LogRecord', () => {
302311
attributes: {
303312
name: 'test name',
304313
},
305-
traceId: 'trance id',
306-
spanId: 'span id',
307-
traceFlags: 1,
308314
};
309315

310316
const newBody = 'this is a new body';

0 commit comments

Comments
 (0)