Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions shared/otel-core/Tests/Unit/src/sdk/OTelLogger.Tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { setContextSpanContext } from "../../../../src/otel/api/trace/utils";
import { createLogger } from "../../../../src/otel/sdk/OTelLogger";
import { createResolvedPromise } from "@nevware21/ts-async";
import { IOTelApi, IOTelConfig } from "../../../../src";
import { IOTelResource, OTelRawResourceAttribute } from "../../../../src/interfaces/otel/resources/IOTelResource";
import { IOTelAttributes } from "../../../../src/interfaces/otel/IOTelAttributes";
import { IOTelLoggerProviderConfig } from "../../../../src/interfaces/otel/logs/IOTelLoggerProviderConfig";

// W3C trace flags constant for sampled traces
const eW3CTraceFlags_Sampled = 1;
Expand Down Expand Up @@ -38,9 +41,7 @@ export class OTelLoggerTests extends AITestClass {

private setup() {
const logProcessor = this._createMockProcessor();
const provider = createLoggerProvider({
processors: [logProcessor]
});
const provider = createLoggerProvider(this._cfg([logProcessor]));
const logger = provider.getLogger("test name", "test version", {
schemaUrl: "test schema url"
}) as LoggerWithScope;
Expand All @@ -53,7 +54,7 @@ export class OTelLoggerTests extends AITestClass {
name: "Logger: factory returns logger instance",
test: () => {
const logProcessor = this._createMockProcessor();
const provider = createLoggerProvider({ processors: [logProcessor] });
const provider = createLoggerProvider(this._cfg([logProcessor]));
const sharedState = provider._sharedState;
const scope: IOTelInstrumentationScope = {
name: "test name",
Expand Down Expand Up @@ -151,4 +152,17 @@ export class OTelLoggerTests extends AITestClass {
shutdown: () => createResolvedPromise(undefined)
};
}

private _cfg(processors: IOTelLogRecordProcessor[]): IOTelLoggerProviderConfig {
const resource: IOTelResource = {
attributes: {} as IOTelAttributes,
merge: () => resource,
getRawAttributes: () => [] as OTelRawResourceAttribute[]
};
return {
resource: resource,
errorHandlers: {},
processors: processors
};
}
}
84 changes: 57 additions & 27 deletions shared/otel-core/Tests/Unit/src/sdk/OTelLoggerProvider.Tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { createMultiLogRecordProcessor } from "../../../../src/otel/sdk/OTelMult
import { loadDefaultConfig } from "../../../../src/otel/sdk/config";
import { IOTelResource, OTelRawResourceAttribute } from "../../../../src/interfaces/otel/resources/IOTelResource";
import { IOTelLogRecordProcessor } from "../../../../src/interfaces/otel/logs/IOTelLogRecordProcessor";
import { IOTelLoggerProviderConfig } from "../../../../src/interfaces/otel/logs/IOTelLoggerProviderConfig";
import { IOTelErrorHandlers } from "../../../../src/interfaces/otel/config/IOTelErrorHandlers";
import { createResolvedPromise } from "@nevware21/ts-async";

type LoggerProviderInstance = ReturnType<typeof createLoggerProvider>;
Expand All @@ -31,7 +33,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: constructor without options should construct an instance",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
Assert.equal(typeof provider.getLogger, "function", "Should create a LoggerProvider instance");
const sharedState = provider._sharedState;
Assert.ok(sharedState.loggers instanceof Map, "Should expose shared state instance");
Expand All @@ -41,7 +43,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: constructor without options should use default processor",
test: (): IPromise<void> => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.registeredLogRecordProcessors.length, 0, "Expected no processors to be registered by default");
const flushResult = sharedState.activeProcessor.forceFlush();
Expand All @@ -53,9 +55,9 @@ export class OTelLoggerProviderTests extends AITestClass {
name: "LoggerProvider: constructor should register provided processors",
test: () => {
const logRecordProcessor = this._createMockProcessor();
const provider = createLoggerProvider({
const provider = createLoggerProvider(this._cfg({
processors: [logRecordProcessor]
});
}));
const sharedState = this._getSharedState(provider);
const activeProcessor = sharedState.activeProcessor as MultiLogRecordProcessorInstance;
Assert.equal(activeProcessor.processors.length, 1, "Should register one processor");
Expand All @@ -66,7 +68,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: constructor should use default resource when not provided",
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test name now says it "should use default resource when not provided", but the updated construction path always provides a resource via this._cfg(). Consider updating the test name (and/or scenario) so it matches what’s actually being tested after the API change.

Suggested change
name: "LoggerProvider: constructor should use default resource when not provided",
name: "LoggerProvider: constructor should expose configured default resource",

Copilot uses AI. Check for mistakes.
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
const resource = sharedState.resource;
Assert.ok(!!resource, "Should have a resource available");
Expand All @@ -78,9 +80,9 @@ export class OTelLoggerProviderTests extends AITestClass {
name: "LoggerProvider: constructor should honor provided resource",
test: () => {
const passedInResource = this._createTestResource({ foo: "bar" });
const provider = createLoggerProvider({
const provider = createLoggerProvider(this._cfg({
resource: passedInResource
});
}));
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.resource, passedInResource, "Should use the provided resource instance");
}
Expand All @@ -89,7 +91,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: constructor should use default forceFlushTimeoutMillis when omitted",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.forceFlushTimeoutMillis, loadDefaultConfig().forceFlushTimeoutMillis, "Should use default forceFlush timeout");
}
Expand All @@ -98,7 +100,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: logRecordLimits should default values when not provided",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
Assert.deepEqual(sharedState.logRecordLimits, {
attributeCountLimit: 128,
Expand All @@ -110,11 +112,11 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: logRecordLimits should respect provided attributeCountLimit",
test: () => {
const provider = createLoggerProvider({
const provider = createLoggerProvider(this._cfg({
logRecordLimits: {
attributeCountLimit: 100
}
});
}));
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.logRecordLimits.attributeCountLimit, 100, "Should use provided attributeCountLimit");
}
Expand All @@ -123,11 +125,11 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: logRecordLimits should respect provided attributeValueLengthLimit",
test: () => {
const provider = createLoggerProvider({
const provider = createLoggerProvider(this._cfg({
logRecordLimits: {
attributeValueLengthLimit: 10
}
});
}));
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.logRecordLimits.attributeValueLengthLimit, 10, "Should use provided attributeValueLengthLimit");
}
Expand All @@ -136,11 +138,11 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: logRecordLimits should allow negative attributeValueLengthLimit",
test: () => {
const provider = createLoggerProvider({
const provider = createLoggerProvider(this._cfg({
logRecordLimits: {
attributeValueLengthLimit: -10
}
});
}));
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.logRecordLimits.attributeValueLengthLimit, -10, "Should preserve provided negative attributeValueLengthLimit");
}
Expand All @@ -149,7 +151,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: logRecordLimits should use default attributeValueLengthLimit when omitted",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.logRecordLimits.attributeValueLengthLimit, Infinity, "Should default attributeValueLengthLimit to Infinity");
}
Expand All @@ -158,7 +160,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: logRecordLimits should use default attributeCountLimit when omitted",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.logRecordLimits.attributeCountLimit, 128, "Should default attributeCountLimit to 128");
}
Expand All @@ -167,7 +169,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: getLogger should default name when invalid",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const logger = provider.getLogger("") as LoggerWithScope;
Assert.equal(logger.instrumentationScope.name, DEFAULT_LOGGER_NAME, "Should use default logger name when name is invalid");
}
Expand All @@ -176,7 +178,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: getLogger should create new logger when name not seen",
test: () => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);
Assert.equal(sharedState.loggers.size, 0, "Should start with no loggers");
provider.getLogger("test name");
Expand All @@ -190,7 +192,7 @@ export class OTelLoggerProviderTests extends AITestClass {
const testName = "test name";
const testVersion = "test version";
const testSchemaUrl = "test schema url";
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);

Assert.equal(sharedState.loggers.size, 0, "Should start with no loggers");
Expand All @@ -209,7 +211,7 @@ export class OTelLoggerProviderTests extends AITestClass {
const testName = "test name";
const testVersion = "test version";
const testSchemaUrl = "test schema url";
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
const sharedState = this._getSharedState(provider);

Assert.equal(sharedState.loggers.size, 0, "Should start with no loggers");
Expand All @@ -234,7 +236,7 @@ export class OTelLoggerProviderTests extends AITestClass {
const processor2 = this._createMockProcessor();
const forceFlushStub1 = this.sandbox.stub(processor1, "forceFlush").resolves();
const forceFlushStub2 = this.sandbox.stub(processor2, "forceFlush").resolves();
const provider = createLoggerProvider({ processors: [processor1, processor2] });
const provider = createLoggerProvider(this._cfg({ processors: [processor1, processor2] }));

return createPromise((resolve, reject) => {
provider.forceFlush().then(() => {
Expand All @@ -257,7 +259,7 @@ export class OTelLoggerProviderTests extends AITestClass {
const processor2 = this._createMockProcessor();
const forceFlushStub1 = this.sandbox.stub(processor1, "forceFlush").rejects("Error");
const forceFlushStub2 = this.sandbox.stub(processor2, "forceFlush").rejects("Error");
const provider = createLoggerProvider({ processors: [processor1, processor2] });
const provider = createLoggerProvider(this._cfg({ processors: [processor1, processor2] }));

return createPromise((resolve, reject) => {
provider.forceFlush().then(() => {
Expand All @@ -280,7 +282,7 @@ export class OTelLoggerProviderTests extends AITestClass {
test: (): IPromise<void> => {
const processor = this._createMockProcessor();
const shutdownStub = this.sandbox.stub(processor, "shutdown").resolves();
const provider = createLoggerProvider({ processors: [processor] });
const provider = createLoggerProvider(this._cfg({ processors: [processor] }));

return createPromise((resolve, reject) => {
provider.shutdown().then(() => {
Expand All @@ -298,7 +300,7 @@ export class OTelLoggerProviderTests extends AITestClass {
this.testCase({
name: "LoggerProvider: shutdown should return null for new requests",
test: (): IPromise<void> => {
const provider = createLoggerProvider();
const provider = createLoggerProvider(this._cfg());
return createPromise((resolve, reject) => {
provider.shutdown().then(() => {
try {
Expand All @@ -317,7 +319,7 @@ export class OTelLoggerProviderTests extends AITestClass {
name: "LoggerProvider: forceFlush after shutdown should not call processors",
test: (): IPromise<void> => {
const logRecordProcessor = this._createMockProcessor();
const provider = createLoggerProvider({ processors: [logRecordProcessor] });
const provider = createLoggerProvider(this._cfg({ processors: [logRecordProcessor] }));
const forceFlushStub = this.sandbox.stub(logRecordProcessor, "forceFlush").resolves();
const warnStub = this.sandbox.stub(console, "warn");

Expand All @@ -341,7 +343,7 @@ export class OTelLoggerProviderTests extends AITestClass {
name: "LoggerProvider: second shutdown should not re-run processor shutdown",
test: (): IPromise<void> => {
const logRecordProcessor = this._createMockProcessor();
const provider = createLoggerProvider({ processors: [logRecordProcessor] });
const provider = createLoggerProvider(this._cfg({ processors: [logRecordProcessor] }));
const shutdownStub = this.sandbox.stub(logRecordProcessor, "shutdown").resolves();
const warnStub = this.sandbox.stub(console, "warn");

Expand All @@ -366,6 +368,34 @@ export class OTelLoggerProviderTests extends AITestClass {
return provider._sharedState;
}

/**
* Creates a valid IOTelLoggerProviderConfig with required fields plus any overrides.
*/
private _cfg(overrides?: Partial<IOTelLoggerProviderConfig>): IOTelLoggerProviderConfig {
let cfg: IOTelLoggerProviderConfig = {
resource: this._createTestResource(),
errorHandlers: {} as IOTelErrorHandlers
};
if (overrides) {
if (overrides.resource !== undefined) {
cfg.resource = overrides.resource;
}
if (overrides.errorHandlers !== undefined) {
cfg.errorHandlers = overrides.errorHandlers;
}
if (overrides.processors !== undefined) {
cfg.processors = overrides.processors;
}
if (overrides.forceFlushTimeoutMillis !== undefined) {
cfg.forceFlushTimeoutMillis = overrides.forceFlushTimeoutMillis;
}
if (overrides.logRecordLimits !== undefined) {
cfg.logRecordLimits = overrides.logRecordLimits;
}
}
return cfg;
}

private _createTestResource(attributes: IOTelAttributes = {} as IOTelAttributes): IOTelResource {
const resourceAttributes: IOTelAttributes = {} as IOTelAttributes;
const rawAttributes: OTelRawResourceAttribute[] = [];
Expand Down
Loading
Loading