From cc5a237cbe06d9d7ce931e350b50cd50a52f1811 Mon Sep 17 00:00:00 2001 From: Hector Date: Fri, 2 Feb 2024 16:25:41 -0800 Subject: [PATCH 1/4] Auto collection of logs aligning to OpenTelemetry --- src/logs/{console.ts => autoCollectLogs.ts} | 16 ++-- src/logs/diagnostic-channel/console.sub.ts | 62 ++++++------- src/logs/diagnostic-channel/winston.sub.ts | 99 +++++++++------------ src/logs/exceptions.ts | 2 +- src/main.ts | 12 +-- src/{logs/api.ts => shim/logsApi.ts} | 4 +- src/shim/telemetryClient.ts | 2 +- src/types.ts | 9 +- test/unitTests/logs/api.tests.ts | 2 +- test/unitTests/logs/console.tests.ts | 78 ++++++++-------- test/unitTests/logs/winston.tests.ts | 79 ++++++++-------- 11 files changed, 178 insertions(+), 187 deletions(-) rename src/logs/{console.ts => autoCollectLogs.ts} (61%) rename src/{logs/api.ts => shim/logsApi.ts} (98%) diff --git a/src/logs/console.ts b/src/logs/autoCollectLogs.ts similarity index 61% rename from src/logs/console.ts rename to src/logs/autoCollectLogs.ts index 94ceaa397..c0ce083c9 100644 --- a/src/logs/console.ts +++ b/src/logs/autoCollectLogs.ts @@ -1,26 +1,20 @@ import { InstrumentationOptions } from "../types"; -import { LogApi } from "./api"; import { enablePublishers } from "./diagnostic-channel/initialization"; enablePublishers(); -export class AutoCollectConsole { - private _client: LogApi; - - constructor(client: LogApi) { - this._client = client; - } +export class AutoCollectLogs { public enable(options: InstrumentationOptions) { // eslint-disable-next-line @typescript-eslint/no-var-requires - require("./diagnostic-channel/console.sub").enable(options.console?.enabled, this._client); + require("./diagnostic-channel/console.sub").enable(options.console); // eslint-disable-next-line @typescript-eslint/no-var-requires - require("./diagnostic-channel/winston.sub").enable(options.winston?.enabled, this._client); + require("./diagnostic-channel/winston.sub").enable(options.winston); } public shutdown() { // eslint-disable-next-line @typescript-eslint/no-var-requires - require("./diagnostic-channel/console.sub").enable(false, this._client); + require("./diagnostic-channel/console.sub").dispose(); // eslint-disable-next-line @typescript-eslint/no-var-requires - require("./diagnostic-channel/winston.sub").enable(false, this._client); + require("./diagnostic-channel/winston.sub").dispose(); } } diff --git a/src/logs/diagnostic-channel/console.sub.ts b/src/logs/diagnostic-channel/console.sub.ts index 7850404a3..d69e883eb 100644 --- a/src/logs/diagnostic-channel/console.sub.ts +++ b/src/logs/diagnostic-channel/console.sub.ts @@ -1,51 +1,43 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. + +import { Logger, LogRecord, logs } from "@opentelemetry/api-logs"; + import { channel, IStandardEvent, trueFilter } from "diagnostic-channel"; import { console as consolePub } from "diagnostic-channel-publishers"; -import { KnownSeverityLevel } from "../../declarations/generated"; -import { LogApi } from "../api"; +import { SeverityNumber } from "@opentelemetry/api-logs"; +import { InstrumentationConfig } from "@opentelemetry/instrumentation"; -let clients: LogApi[] = []; + +let logger: Logger; +let logSendingLevel: SeverityNumber; const subscriber = (event: IStandardEvent) => { - let message = event.data.message as Error | string; - clients.forEach((client) => { - if (message instanceof Error) { - client.trackException({ exception: message }); - } else { - // Message can have a trailing newline - if (message.lastIndexOf("\n") === message.length - 1) { - message = message.substring(0, message.length - 1); - } - client.trackTrace({ - message: message, - severity: event.data.stderr - ? KnownSeverityLevel.Warning - : KnownSeverityLevel.Information, - }); + let severity = (event.data.message as string | Error) instanceof Error ? SeverityNumber.ERROR : (event.data.stderr + ? SeverityNumber.WARN + : SeverityNumber.INFO); + if (logSendingLevel <= severity) { + let message = event.data.message.toString(); + // Message can have a trailing newline + if (message.lastIndexOf("\n") === message.length - 1) { + message = message.substring(0, message.length - 1); } - }); + let logRecord: LogRecord = { + body: message, + severityNumber: severity + }; + logger.emit(logRecord); + } }; -export function enable(enabled: boolean, client: LogApi) { - if (enabled) { - const handlerFound = clients.find((c) => c === client); - if (handlerFound) { - return; - } - if (clients.length === 0) { - channel.subscribe("console", subscriber, trueFilter); - } - clients.push(client); - } else { - clients = clients.filter((c) => c !== client); - if (clients.length === 0) { - channel.unsubscribe("console", subscriber); - } +export function enable(config?: InstrumentationConfig & { logSendingLevel?: SeverityNumber }) { + if (config?.enabled) { + logger = logs.getLogger("ApplicationInsightsConsoleLogger"); + logSendingLevel = config.logSendingLevel || SeverityNumber.UNSPECIFIED; + channel.subscribe("console", subscriber, trueFilter); } } export function dispose() { channel.unsubscribe("console", subscriber); - clients = []; } diff --git a/src/logs/diagnostic-channel/winston.sub.ts b/src/logs/diagnostic-channel/winston.sub.ts index 0fd22fce8..07f364f22 100644 --- a/src/logs/diagnostic-channel/winston.sub.ts +++ b/src/logs/diagnostic-channel/winston.sub.ts @@ -1,82 +1,69 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. + +import { Logger, LogRecord, logs, SeverityNumber } from "@opentelemetry/api-logs"; import { channel, IStandardEvent, trueFilter } from "diagnostic-channel"; import { winston } from "diagnostic-channel-publishers"; -import { KnownSeverityLevel } from "../../declarations/generated"; -import { LogApi } from "../api"; +import { InstrumentationConfig } from "@opentelemetry/instrumentation"; + -let clients: LogApi[] = []; +let logger: Logger; +let logSendingLevel: SeverityNumber; -const winstonToAILevelMap: { [key: string]: (og: string) => string } = { +const winstonToAILevelMap: { [key: string]: (og: string) => number } = { syslog(og: string) { - const map: { [key: string]: string } = { - emerg: KnownSeverityLevel.Critical, - alert: KnownSeverityLevel.Critical, - crit: KnownSeverityLevel.Critical, - error: KnownSeverityLevel.Error, - warning: KnownSeverityLevel.Warning, - notice: KnownSeverityLevel.Information, - info: KnownSeverityLevel.Information, - debug: KnownSeverityLevel.Verbose, + const map: { [key: string]: number } = { + emerg: SeverityNumber.FATAL3, + alert: SeverityNumber.FATAL2, + crit: SeverityNumber.FATAL, + error: SeverityNumber.ERROR, + warning: SeverityNumber.WARN, + notice: SeverityNumber.INFO2, + info: SeverityNumber.INFO, + debug: SeverityNumber.DEBUG, }; - return map[og] === undefined ? KnownSeverityLevel.Information : map[og]; + return map[og] === undefined ? SeverityNumber.INFO : map[og]; }, npm(og: string) { - const map: { [key: string]: string } = { - error: KnownSeverityLevel.Error, - warn: KnownSeverityLevel.Warning, - info: KnownSeverityLevel.Information, - verbose: KnownSeverityLevel.Verbose, - debug: KnownSeverityLevel.Verbose, - silly: KnownSeverityLevel.Verbose, + const map: { [key: string]: number } = { + error: SeverityNumber.ERROR, + warn: SeverityNumber.WARN, + info: SeverityNumber.INFO, + http: SeverityNumber.DEBUG3, + verbose: SeverityNumber.DEBUG2, + debug: SeverityNumber.DEBUG, + silly: SeverityNumber.TRACE, }; - return map[og] === undefined ? KnownSeverityLevel.Information : map[og]; + return map[og] === undefined ? SeverityNumber.INFO : map[og]; }, unknown(og: string) { - return KnownSeverityLevel.Information; + return SeverityNumber.INFO; }, }; -const subscriber = (event: IStandardEvent) => { - const message = event.data.message as Error | string; - clients.forEach((client) => { - if (message instanceof Error) { - client.trackException({ - exception: message, - properties: event.data.meta, - }); - } else { - const AIlevel = winstonToAILevelMap[event.data.levelKind](event.data.level); - client.trackTrace({ - message: message, - severity: AIlevel, - properties: event.data.meta, - }); - } - }); +const subscriber = (event: IStandardEvent) => { + const severity = winstonToAILevelMap[event.data.levelKind](event.data.level); + if (logSendingLevel <= severity) { + const message = event.data.message.toString(); + let logRecord: LogRecord = { + body: message, + severityNumber: severity, + attributes: event.data.meta + }; + logger.emit(logRecord); + } }; -export function enable(enabled: boolean, client: LogApi) { - if (enabled) { - const handlerFound = clients.find((c) => c === client); - if (handlerFound) { - return; - } - if (clients.length === 0) { - channel.subscribe("winston", subscriber, trueFilter); - } - clients.push(client); - } else { - clients = clients.filter((c) => c !== client); - if (clients.length === 0) { - channel.unsubscribe("winston", subscriber); - } +export function enable(config?: InstrumentationConfig & { logSendingLevel?: SeverityNumber }) { + if (config?.enabled) { + logger = logs.getLogger("ApplicationInsightsConsoleLogger"); + logSendingLevel = config.logSendingLevel || SeverityNumber.UNSPECIFIED; + channel.subscribe("winston", subscriber, trueFilter); } } export function dispose() { channel.unsubscribe("winston", subscriber); - clients = []; } diff --git a/src/logs/exceptions.ts b/src/logs/exceptions.ts index 3e4970f33..91ba17d7c 100644 --- a/src/logs/exceptions.ts +++ b/src/logs/exceptions.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for details. import { logs } from "@opentelemetry/api-logs"; import { Util } from "../shared/util"; -import { LogApi } from "./api"; +import { LogApi } from "../shim/logsApi"; import { LoggerProvider } from "@opentelemetry/sdk-logs"; type ExceptionHandle = "uncaughtExceptionMonitor" | "uncaughtException" | "unhandledRejection"; diff --git a/src/main.ts b/src/main.ts index f8833a2b9..0fabbfdf3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,15 +11,15 @@ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http"; import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http"; import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"; -import { AutoCollectConsole } from "./logs/console"; +import { AutoCollectLogs } from "./logs/autoCollectLogs"; import { AutoCollectExceptions } from "./logs/exceptions"; import { AzureMonitorOpenTelemetryOptions } from "./types"; import { ApplicationInsightsConfig } from "./shared/configuration/config"; -import { LogApi } from "./logs/api"; +import { LogApi } from "./shim/logsApi"; import { PerformanceCounterMetrics } from "./metrics/performanceCounters"; import { AzureMonitorSpanProcessor } from "./traces/spanProcessor"; -let console: AutoCollectConsole; +let autoCollectLogs: AutoCollectLogs; let exceptions: AutoCollectExceptions; let perfCounters: PerformanceCounterMetrics; @@ -31,7 +31,7 @@ export function useAzureMonitor(options?: AzureMonitorOpenTelemetryOptions) { distroUseAzureMonitor(options); const internalConfig = new ApplicationInsightsConfig(options); const logApi = new LogApi(logs.getLogger("ApplicationInsightsLogger")); - console = new AutoCollectConsole(logApi); + autoCollectLogs = new AutoCollectLogs(); if (internalConfig.enableAutoCollectExceptions) { exceptions = new AutoCollectExceptions(logApi); } @@ -42,7 +42,7 @@ export function useAzureMonitor(options?: AzureMonitorOpenTelemetryOptions) { (trace.getTracerProvider() as BasicTracerProvider).addSpanProcessor(new AzureMonitorSpanProcessor(perfCounters)); } } - console.enable(internalConfig.instrumentationOptions); + autoCollectLogs.enable(internalConfig.instrumentationOptions); _addOtlpExporters(internalConfig); } @@ -51,7 +51,7 @@ export function useAzureMonitor(options?: AzureMonitorOpenTelemetryOptions) { */ export async function shutdownAzureMonitor() { await distroShutdownAzureMonitor(); - console.shutdown(); + autoCollectLogs.shutdown(); exceptions?.shutdown(); perfCounters?.shutdown(); } diff --git a/src/logs/api.ts b/src/shim/logsApi.ts similarity index 98% rename from src/logs/api.ts rename to src/shim/logsApi.ts index ab76de114..eff478a05 100644 --- a/src/logs/api.ts +++ b/src/shim/logsApi.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { Logger as OtelLogger, LogRecord, logs } from "@opentelemetry/api-logs"; +import { Logger as OtelLogger, LogRecord } from "@opentelemetry/api-logs"; import { LogRecord as SDKLogRecord } from "@opentelemetry/sdk-logs"; import { Attributes, diag } from "@opentelemetry/api"; import { IdGenerator, RandomIdGenerator } from "@opentelemetry/sdk-trace-base"; @@ -18,7 +18,7 @@ import { TelemetryExceptionDetails } from "../declarations/generated"; import { Util } from "../shared/util"; -import { parseStack } from "./exceptions"; +import { parseStack } from "../logs/exceptions"; /** * Log manual API to generate Application Insights telemetry diff --git a/src/shim/telemetryClient.ts b/src/shim/telemetryClient.ts index 58a59608f..0be98eeb1 100644 --- a/src/shim/telemetryClient.ts +++ b/src/shim/telemetryClient.ts @@ -13,7 +13,7 @@ import Config = require("./shim-config"); import { AttributeSpanProcessor } from "../shared/util/attributeSpanProcessor"; import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node"; import { AttributeLogProcessor } from "../shared/util/attributeLogRecordProcessor"; -import { LogApi } from "../logs/api"; +import { LogApi } from "./logsApi"; import { flushAzureMonitor, shutdownAzureMonitor, useAzureMonitor } from "../main"; import { AzureMonitorOpenTelemetryOptions } from "../types"; diff --git a/src/types.ts b/src/types.ts index 9cd0e97a0..b72aee452 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { AzureMonitorOpenTelemetryOptions as DistroOptions, InstrumentationOptions as DistroInstrumentationOptions } from "@azure/monitor-opentelemetry"; +import { SeverityNumber } from "@opentelemetry/api-logs"; import { InstrumentationConfig } from "@opentelemetry/instrumentation"; import { OTLPExporterNodeConfigBase } from "@opentelemetry/otlp-exporter-base"; @@ -37,10 +38,10 @@ export interface AzureMonitorOpenTelemetryOptions extends DistroOptions { } export interface InstrumentationOptions extends DistroInstrumentationOptions { - /** Console Instrumentation Config */ - console?: InstrumentationConfig; - /** Winston Instrumentation Config */ - winston?: InstrumentationConfig; + /** Console Instrumentation Config */ + console?: InstrumentationConfig & { logSendingLevel?: SeverityNumber }; + /** Winston Instrumentation Config */ + winston?: InstrumentationConfig & { logSendingLevel?: SeverityNumber }; } /** diff --git a/test/unitTests/logs/api.tests.ts b/test/unitTests/logs/api.tests.ts index 0348741f4..7a3dbb9eb 100644 --- a/test/unitTests/logs/api.tests.ts +++ b/test/unitTests/logs/api.tests.ts @@ -13,7 +13,7 @@ import { TraceTelemetry } from "../../../src/declarations/contracts"; import { AvailabilityData, MessageData, MonitorDomain, PageViewData, TelemetryEventData, TelemetryExceptionData } from "../../../src/declarations/generated"; -import { LogApi } from "../../../src/logs/api"; +import { LogApi } from "../../../src/shim/logsApi"; describe("logs/API", () => { let sandbox: sinon.SinonSandbox; diff --git a/test/unitTests/logs/console.tests.ts b/test/unitTests/logs/console.tests.ts index 717b29409..8801524dc 100644 --- a/test/unitTests/logs/console.tests.ts +++ b/test/unitTests/logs/console.tests.ts @@ -1,76 +1,84 @@ import * as assert from "assert"; -import * as sinon from "sinon"; import { channel } from "diagnostic-channel"; import { console } from "diagnostic-channel-publishers"; -import { logs } from "@opentelemetry/api-logs"; -import { enable, dispose } from "../../../src/logs/diagnostic-channel/console.sub"; -import { LogApi } from "../../../src/logs/api"; -import { AutoCollectConsole } from "../../../src/logs/console"; +import { SeverityNumber, logs } from '@opentelemetry/api-logs'; +import { + LoggerProvider, + SimpleLogRecordProcessor, + InMemoryLogRecordExporter, +} from '@opentelemetry/sdk-logs'; + +import { dispose } from "../../../src/logs/diagnostic-channel/console.sub"; +import { AutoCollectLogs } from "../../../src/logs/autoCollectLogs"; describe("AutoCollection/Console", () => { - let sandbox: sinon.SinonSandbox; + let memoryLogExporter: InMemoryLogRecordExporter; before(() => { - sandbox = sinon.createSandbox(); + logs.disable(); + const loggerProvider = new LoggerProvider(); + memoryLogExporter = new InMemoryLogRecordExporter(); + loggerProvider.addLogRecordProcessor( + new SimpleLogRecordProcessor(memoryLogExporter) + ); + logs.setGlobalLoggerProvider(loggerProvider); + }); + + beforeEach(() => { + memoryLogExporter.getFinishedLogRecords().length = 0; // clear }); afterEach(() => { - sandbox.restore(); dispose(); }); describe("#log and #error()", () => { - it("should call trackException for errors", () => { - let logApi = new LogApi(logs.getLogger("testLogger")); - let autoCollect = new AutoCollectConsole(logApi); + it("should log event for errors", () => { + let autoCollect = new AutoCollectLogs(); autoCollect.enable({ console: { enabled: true } }); - const stub = sandbox.stub(logApi, "trackException"); const dummyError = new Error("test error"); const errorEvent: console.IConsoleData = { message: dummyError as any, - stderr: false, // log() should still log as ExceptionData + stderr: false, }; - channel.publish("console", errorEvent); - assert.ok(stub.calledOnce); - assert.deepEqual(stub.args[0][0].exception, dummyError); + const logRecords = memoryLogExporter.getFinishedLogRecords(); + assert.strictEqual(logRecords.length, 1); + assert.strictEqual(logRecords[0].body, "Error: test error"); + assert.strictEqual(logRecords[0].severityNumber, SeverityNumber.ERROR); }); - it("should call trackTrace for logs", () => { - let logApi = new LogApi(logs.getLogger("testLogger")); - let autoCollect = new AutoCollectConsole(logApi); + it("should log event for logs", () => { + let autoCollect = new AutoCollectLogs(); autoCollect.enable({ console: { enabled: true } }); - const stub = sandbox.stub(logApi, "trackTrace"); const logEvent: console.IConsoleData = { message: "test log", - stderr: true, // should log as MessageData regardless of this setting + stderr: true, }; channel.publish("console", logEvent); - assert.ok(stub.calledOnce); - assert.deepEqual(stub.args[0][0].message, "test log"); + const logRecords = memoryLogExporter.getFinishedLogRecords(); + assert.strictEqual(logRecords.length, 1); + assert.strictEqual(logRecords[0].body, "test log"); + assert.strictEqual(logRecords[0].severityNumber, SeverityNumber.WARN); }); - it("should notify multiple handlers", () => { - let logApi = new LogApi(logs.getLogger("testLogger")); - let secondLogApi = new LogApi(logs.getLogger("testLogger")); - const stub = sandbox.stub(logApi, "trackTrace"); - const secondStub = sandbox.stub(secondLogApi, "trackTrace"); - enable(true, logApi); - enable(true, secondLogApi); + it("severityLevel", () => { + let autoCollect = new AutoCollectLogs(); + autoCollect.enable({ + console: { enabled: true, logSendingLevel: SeverityNumber.ERROR } + }); const logEvent: console.IConsoleData = { message: "test log", - stderr: true, // should log as MessageData regardless of this setting + stderr: true, }; channel.publish("console", logEvent); - assert.ok(stub.calledOnce); - assert.deepEqual(stub.args[0][0].message, "test log"); - assert.ok(secondStub.calledOnce); - assert.deepEqual(secondStub.args[0][0].message, "test log"); + const logRecords = memoryLogExporter.getFinishedLogRecords(); + assert.strictEqual(logRecords.length, 0); }); }); }); diff --git a/test/unitTests/logs/winston.tests.ts b/test/unitTests/logs/winston.tests.ts index 1a27376a6..0f6b7a8e7 100644 --- a/test/unitTests/logs/winston.tests.ts +++ b/test/unitTests/logs/winston.tests.ts @@ -1,79 +1,88 @@ import * as assert from "assert"; -import * as sinon from "sinon"; import { channel } from "diagnostic-channel"; import { winston } from "diagnostic-channel-publishers"; -import { logs } from "@opentelemetry/api-logs"; -import { enable, dispose } from "../../../src/logs/diagnostic-channel/winston.sub"; -import { LogApi } from "../../../src/logs/api"; -import { AutoCollectConsole } from "../../../src/logs/console"; +import { SeverityNumber, logs } from '@opentelemetry/api-logs'; +import { + LoggerProvider, + SimpleLogRecordProcessor, + InMemoryLogRecordExporter, +} from '@opentelemetry/sdk-logs'; +import { dispose } from "../../../src/logs/diagnostic-channel/winston.sub"; +import { AutoCollectLogs } from "../../../src/logs/autoCollectLogs"; describe("diagnostic-channel/winston", () => { - let sandbox: sinon.SinonSandbox; + let memoryLogExporter: InMemoryLogRecordExporter; before(() => { - sandbox = sinon.createSandbox(); + logs.disable(); + const loggerProvider = new LoggerProvider(); + memoryLogExporter = new InMemoryLogRecordExporter(); + loggerProvider.addLogRecordProcessor( + new SimpleLogRecordProcessor(memoryLogExporter) + ); + logs.setGlobalLoggerProvider(loggerProvider); + }); + + beforeEach(() => { + memoryLogExporter.getFinishedLogRecords().length = 0; // clear }); afterEach(() => { - sandbox.restore(); dispose(); }); - it("should call trackException for errors", () => { - let logApi = new LogApi(logs.getLogger("testLogger")); - let autoCollect = new AutoCollectConsole(logApi); + it("should emit log for errors", () => { + let autoCollect = new AutoCollectLogs(); autoCollect.enable({ winston: { enabled: true } }); - const stub = sandbox.stub(logApi, "trackException"); const dummyError = new Error("test error"); const errorEvent: winston.IWinstonData = { message: dummyError as any, meta: {}, - level: "foo", + level: "error", levelKind: "npm", }; channel.publish("winston", errorEvent); - assert.ok(stub.calledOnce); - assert.deepEqual(stub.args[0][0].exception, dummyError); + const logRecords = memoryLogExporter.getFinishedLogRecords(); + assert.strictEqual(logRecords.length, 1); + assert.strictEqual(logRecords[0].body, "Error: test error"); + assert.strictEqual(logRecords[0].severityNumber, SeverityNumber.ERROR); }); - it("should call trackTrace for logs", () => { - let logApi = new LogApi(logs.getLogger("testLogger")); - let autoCollect = new AutoCollectConsole(logApi); + it("should emit log for winston log", () => { + let autoCollect = new AutoCollectLogs(); autoCollect.enable({ winston: { enabled: true } }); - const stub = sandbox.stub(logApi, "trackTrace"); const logEvent: winston.IWinstonData = { message: "test log", - meta: {}, - level: "foo", + meta: { "test1": "testValue" }, + level: "debug", levelKind: "npm", }; channel.publish("winston", logEvent); - assert.ok(stub.calledOnce); - assert.deepEqual(stub.args[0][0].message, "test log"); + const logRecords = memoryLogExporter.getFinishedLogRecords(); + assert.strictEqual(logRecords.length, 1); + assert.strictEqual(logRecords[0].body, "test log"); + assert.strictEqual(logRecords[0].severityNumber, SeverityNumber.DEBUG); + assert.strictEqual(logRecords[0].attributes["test1"], "testValue"); }); - it("should notify multiple handlers", () => { - let logApi = new LogApi(logs.getLogger("testLogger")); - let secondLogApi = new LogApi(logs.getLogger("testLogger")); - const stub = sandbox.stub(logApi, "trackTrace"); - const secondStub = sandbox.stub(secondLogApi, "trackTrace"); - enable(true, logApi); - enable(true, secondLogApi); + it("severityLevel", () => { + let autoCollect = new AutoCollectLogs(); + autoCollect.enable({ + console: { enabled: true, logSendingLevel: SeverityNumber.ERROR } + }); const logEvent: winston.IWinstonData = { message: "test log", meta: {}, - level: "foo", + level: "debug", levelKind: "npm", }; channel.publish("winston", logEvent); - assert.ok(stub.calledOnce); - assert.deepEqual(stub.args[0][0].message, "test log"); - assert.ok(secondStub.calledOnce); - assert.deepEqual(secondStub.args[0][0].message, "test log"); + const logRecords = memoryLogExporter.getFinishedLogRecords(); + assert.strictEqual(logRecords.length, 0); }); }); From a6b7ff5d21781bedf710a4b9e0d7b68760a8adac Mon Sep 17 00:00:00 2001 From: Hector Date: Fri, 2 Feb 2024 16:29:50 -0800 Subject: [PATCH 2/4] Lint --- src/logs/diagnostic-channel/console.sub.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/logs/diagnostic-channel/console.sub.ts b/src/logs/diagnostic-channel/console.sub.ts index d69e883eb..80c2a1d2f 100644 --- a/src/logs/diagnostic-channel/console.sub.ts +++ b/src/logs/diagnostic-channel/console.sub.ts @@ -1,12 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. -import { Logger, LogRecord, logs } from "@opentelemetry/api-logs"; - +import { Logger, LogRecord, SeverityNumber, logs } from "@opentelemetry/api-logs"; +import { InstrumentationConfig } from "@opentelemetry/instrumentation"; import { channel, IStandardEvent, trueFilter } from "diagnostic-channel"; import { console as consolePub } from "diagnostic-channel-publishers"; -import { SeverityNumber } from "@opentelemetry/api-logs"; -import { InstrumentationConfig } from "@opentelemetry/instrumentation"; let logger: Logger; From 9127f9efcd9e9a24ef2e56bd9789752a9168078e Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:11:09 -0800 Subject: [PATCH 3/4] Update src/logs/diagnostic-channel/console.sub.ts Co-authored-by: Jackson Weber <47067795+JacksonWeber@users.noreply.github.com> --- src/logs/diagnostic-channel/console.sub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logs/diagnostic-channel/console.sub.ts b/src/logs/diagnostic-channel/console.sub.ts index 80c2a1d2f..3ae5b2f22 100644 --- a/src/logs/diagnostic-channel/console.sub.ts +++ b/src/logs/diagnostic-channel/console.sub.ts @@ -20,7 +20,7 @@ const subscriber = (event: IStandardEvent) => { if (message.lastIndexOf("\n") === message.length - 1) { message = message.substring(0, message.length - 1); } - let logRecord: LogRecord = { + const logRecord: LogRecord = { body: message, severityNumber: severity }; From 43ad414a81e3c4bfa68f1f7cb904d77acaf9b500 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:11:16 -0800 Subject: [PATCH 4/4] Update src/logs/diagnostic-channel/console.sub.ts Co-authored-by: Jackson Weber <47067795+JacksonWeber@users.noreply.github.com> --- src/logs/diagnostic-channel/console.sub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logs/diagnostic-channel/console.sub.ts b/src/logs/diagnostic-channel/console.sub.ts index 3ae5b2f22..0e23a4a0a 100644 --- a/src/logs/diagnostic-channel/console.sub.ts +++ b/src/logs/diagnostic-channel/console.sub.ts @@ -11,7 +11,7 @@ let logger: Logger; let logSendingLevel: SeverityNumber; const subscriber = (event: IStandardEvent) => { - let severity = (event.data.message as string | Error) instanceof Error ? SeverityNumber.ERROR : (event.data.stderr + const severity = (event.data.message as string | Error) instanceof Error ? SeverityNumber.ERROR : (event.data.stderr ? SeverityNumber.WARN : SeverityNumber.INFO); if (logSendingLevel <= severity) {