@devopsplaybook.io/otel-utils 1.8.0-beta.39.883f25d → 1.9.0-beta.40.3ebb823

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,479 +0,0 @@
1
- import { logs, SeverityNumber } from "@opentelemetry/api";
2
- import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
3
- import { LoggerProvider } from "@opentelemetry/sdk-logs";
4
- import type { ConsoleLogMode } from "./models/ConfigOTelInterface";
5
- import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
6
- import { StandardLogger } from "./StandardLogger";
7
-
8
- jest.mock("@opentelemetry/sdk-logs", () => {
9
- const actual =
10
- jest.requireActual<typeof import("@opentelemetry/sdk-logs")>(
11
- "@opentelemetry/sdk-logs",
12
- );
13
- const batchProcessorOptions: unknown[] = [];
14
- class RecordingBatchLogRecordProcessor extends actual.BatchLogRecordProcessor {
15
- constructor(
16
- options: ConstructorParameters<typeof actual.BatchLogRecordProcessor>[0],
17
- ) {
18
- super(options);
19
- batchProcessorOptions.push(options);
20
- }
21
- }
22
- return {
23
- ...actual,
24
- BatchLogRecordProcessor: RecordingBatchLogRecordProcessor,
25
- __batchProcessorOptions: batchProcessorOptions,
26
- };
27
- });
28
-
29
- interface SdkLogsMock {
30
- __batchProcessorOptions: unknown[];
31
- }
32
-
33
- function batchProcessorOptions(): unknown[] {
34
- return (jest.requireMock("@opentelemetry/sdk-logs") as SdkLogsMock)
35
- .__batchProcessorOptions;
36
- }
37
-
38
- jest.mock("@opentelemetry/exporter-logs-otlp-http", () => {
39
- const { ExportResultCode } = jest.requireActual<
40
- typeof import("@opentelemetry/core")
41
- >("@opentelemetry/core");
42
- return {
43
- OTLPLogExporter: jest.fn().mockImplementation(function () {
44
- const exportedRecords: { body?: unknown }[] = [];
45
- return {
46
- export: (
47
- records: { body?: unknown }[],
48
- resultCallback: (result: { code: number }) => void,
49
- ) => {
50
- exportedRecords.push(...records);
51
- resultCallback({ code: ExportResultCode.SUCCESS });
52
- },
53
- forceFlush: jest.fn().mockResolvedValue(undefined),
54
- shutdown: jest.fn().mockResolvedValue(undefined),
55
- getExportedRecords: () => exportedRecords,
56
- };
57
- }),
58
- };
59
- });
60
-
61
- interface MockLogExporter {
62
- forceFlush: jest.Mock;
63
- shutdown: jest.Mock;
64
- getExportedRecords: () => { body?: unknown }[];
65
- }
66
-
67
- const mockExporterConstructor = OTLPLogExporter as unknown as jest.Mock;
68
-
69
- function exporterAt(index: number): MockLogExporter {
70
- return mockExporterConstructor.mock.results[index].value as MockLogExporter;
71
- }
72
-
73
- function lastExporter(): MockLogExporter {
74
- return exporterAt(mockExporterConstructor.mock.results.length - 1);
75
- }
76
-
77
- function exportedBodies(exporter: MockLogExporter): unknown[] {
78
- return exporter.getExportedRecords().map((record) => record.body);
79
- }
80
-
81
- function collectorConfig(logsUrl: string): ConfigOTelInterface {
82
- return {
83
- SERVICE_ID: "log-service",
84
- VERSION: "1.0.0",
85
- OPENTELEMETRY_COLLECTOR_HTTP_LOGS: logsUrl,
86
- };
87
- }
88
-
89
- describe("StandardLogger", () => {
90
- const createdLoggers: StandardLogger[] = [];
91
- let warnSpy: jest.SpyInstance;
92
- let logSpy: jest.SpyInstance;
93
-
94
- function makeLogger(): StandardLogger {
95
- const logger = new StandardLogger();
96
- createdLoggers.push(logger);
97
- return logger;
98
- }
99
-
100
- beforeEach(() => {
101
- jest.clearAllMocks();
102
- batchProcessorOptions().length = 0;
103
- logs.disable();
104
- warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
105
- logSpy = jest.spyOn(console, "log").mockImplementation(() => {});
106
- });
107
-
108
- afterEach(async () => {
109
- for (const logger of createdLoggers.splice(0)) {
110
- await logger.shutdown();
111
- }
112
- logs.disable();
113
- warnSpy.mockRestore();
114
- logSpy.mockRestore();
115
- });
116
-
117
- it("builds the log exporter with the collector URL and no auth header", async () => {
118
- const logger = makeLogger();
119
- await logger.initOTel(collectorConfig("http://collector:4318/v1/logs"));
120
-
121
- expect(mockExporterConstructor).toHaveBeenCalledTimes(1);
122
- expect(mockExporterConstructor.mock.calls[0][0]).toEqual({
123
- url: "http://collector:4318/v1/logs",
124
- headers: {},
125
- });
126
- await logger.shutdown();
127
- });
128
-
129
- it("adds the Authorization header when configured", async () => {
130
- const logger = makeLogger();
131
- await logger.initOTel({
132
- ...collectorConfig("http://collector:4318/v1/logs"),
133
- OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER: "secret",
134
- });
135
-
136
- expect(mockExporterConstructor.mock.calls[0][0]).toEqual({
137
- url: "http://collector:4318/v1/logs",
138
- headers: { Authorization: "Bearer secret" },
139
- });
140
- await logger.shutdown();
141
- });
142
-
143
- it("registers the provider as the global logger provider", async () => {
144
- const logger = makeLogger();
145
- await logger.initOTel(collectorConfig("http://collector:4318/v1/logs"));
146
-
147
- expect(logs.getLoggerProvider()).toBeInstanceOf(LoggerProvider);
148
- await logger.shutdown();
149
- });
150
-
151
- it("flushes OTel logs and module logger records on shutdown", async () => {
152
- const logger = makeLogger();
153
- await logger.initOTel({
154
- ...collectorConfig("http://collector:4318/v1/logs"),
155
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS: 5,
156
- });
157
-
158
- logs.getLogger("external-lib").emit({
159
- body: "from-global",
160
- severityNumber: SeverityNumber.INFO,
161
- });
162
- logger.createModuleLogger("billing").info("hello");
163
- expect(logger.getLogger()).toBeDefined();
164
-
165
- await logger.shutdown();
166
-
167
- expect(exportedBodies(lastExporter())).toEqual(
168
- expect.arrayContaining(["from-global", "[billing] hello"]),
169
- );
170
- expect(lastExporter().shutdown).toHaveBeenCalled();
171
- });
172
-
173
- it("does not register a global provider without a logs endpoint", async () => {
174
- const logger = makeLogger();
175
- await logger.initOTel({ SERVICE_ID: "log-service", VERSION: "1.0.0" });
176
-
177
- expect(logger.getLogger()).toBeUndefined();
178
- expect(mockExporterConstructor).not.toHaveBeenCalled();
179
- expect(logs.getLoggerProvider()).not.toBeInstanceOf(LoggerProvider);
180
- await expect(logger.shutdown()).resolves.toBeUndefined();
181
- });
182
-
183
- it("routes each instance to its own exporter and warns on the second registration", async () => {
184
- const first = makeLogger();
185
- const second = makeLogger();
186
- await first.initOTel(collectorConfig("http://collector-1/v1/logs"));
187
- await second.initOTel(collectorConfig("http://collector-2/v1/logs"));
188
-
189
- first.createModuleLogger("first").info("from-first");
190
- second.createModuleLogger("second").info("from-second");
191
- logs.getLogger("external-lib").emit({
192
- body: "from-global",
193
- severityNumber: SeverityNumber.INFO,
194
- });
195
-
196
- await first.shutdown();
197
- await second.shutdown();
198
-
199
- expect(exportedBodies(exporterAt(0))).toEqual(
200
- expect.arrayContaining(["[first] from-first", "from-global"]),
201
- );
202
- expect(exportedBodies(exporterAt(1))).toEqual(["[second] from-second"]);
203
- expect(warnSpy).toHaveBeenCalledTimes(1);
204
- expect(warnSpy).toHaveBeenCalledWith(
205
- expect.stringContaining("A global logger provider is already registered"),
206
- );
207
- });
208
-
209
- it("re-initialisation flushes the previous provider and keeps records", async () => {
210
- const logger = makeLogger();
211
- await logger.initOTel(collectorConfig("http://collector-1/v1/logs"));
212
- logger.createModuleLogger("billing").info("before-reinit");
213
-
214
- await logger.initOTel(collectorConfig("http://collector-2/v1/logs"));
215
-
216
- expect(exportedBodies(exporterAt(0))).toContain("[billing] before-reinit");
217
- expect(logs.getLoggerProvider()).toBeInstanceOf(LoggerProvider);
218
-
219
- logs.getLogger("external-lib").emit({
220
- body: "after-reinit",
221
- severityNumber: SeverityNumber.INFO,
222
- });
223
- logger.createModuleLogger("billing").info("after-reinit-module");
224
- await logger.shutdown();
225
-
226
- expect(exportedBodies(exporterAt(1))).toEqual(
227
- expect.arrayContaining(["after-reinit", "[billing] after-reinit-module"]),
228
- );
229
- });
230
-
231
- it("can re-initialise after shutdown", async () => {
232
- const logger = makeLogger();
233
- await logger.initOTel(collectorConfig("http://collector/v1/logs"));
234
- await logger.shutdown();
235
-
236
- expect(logger.getLogger()).toBeUndefined();
237
- expect(logs.getLoggerProvider()).not.toBeInstanceOf(LoggerProvider);
238
-
239
- await logger.initOTel(collectorConfig("http://collector/v1/logs"));
240
- expect(logger.getLogger()).toBeDefined();
241
- expect(logs.getLoggerProvider()).toBeInstanceOf(LoggerProvider);
242
-
243
- logs.getLogger("external-lib").emit({
244
- body: "after-restart",
245
- severityNumber: SeverityNumber.INFO,
246
- });
247
- await logger.shutdown();
248
-
249
- expect(exportedBodies(exporterAt(1))).toContain("after-restart");
250
- });
251
-
252
- it("shuts down idempotently and leaves the global API on Noop", async () => {
253
- const logger = makeLogger();
254
- await logger.initOTel(collectorConfig("http://collector/v1/logs"));
255
- logger.createModuleLogger("billing").info("recorded");
256
-
257
- await logger.shutdown();
258
- await logger.shutdown();
259
-
260
- expect(exporterAt(0).shutdown).toHaveBeenCalledTimes(1);
261
- expect(exportedBodies(exporterAt(0))).toContain("[billing] recorded");
262
- expect(logger.getLogger()).toBeUndefined();
263
- expect(logs.getLoggerProvider()).not.toBeInstanceOf(LoggerProvider);
264
- expect(() =>
265
- logs.getLogger("external-lib").emit({ body: "dropped" }),
266
- ).not.toThrow();
267
- });
268
-
269
- describe("batch processor tunables", () => {
270
- it("passes the documented defaults to BatchLogRecordProcessor", async () => {
271
- const logger = makeLogger();
272
- await logger.initOTel(collectorConfig("http://collector/v1/logs"));
273
-
274
- expect(batchProcessorOptions()).toHaveLength(1);
275
- expect(batchProcessorOptions()[0]).toEqual({
276
- exporter: expect.anything(),
277
- maxQueueSize: 2048,
278
- maxExportBatchSize: 512,
279
- exportTimeoutMillis: 30000,
280
- scheduledDelayMillis: 60000,
281
- });
282
- await logger.shutdown();
283
- });
284
-
285
- it("passes configured batch values to BatchLogRecordProcessor", async () => {
286
- const logger = makeLogger();
287
- await logger.initOTel({
288
- ...collectorConfig("http://collector/v1/logs"),
289
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS: 5,
290
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_MAX_QUEUE_SIZE: 4096,
291
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_MAX_BATCH_SIZE: 1024,
292
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_TIMEOUT_MILLIS: 15000,
293
- });
294
-
295
- expect(batchProcessorOptions()[0]).toEqual({
296
- exporter: expect.anything(),
297
- maxQueueSize: 4096,
298
- maxExportBatchSize: 1024,
299
- exportTimeoutMillis: 15000,
300
- scheduledDelayMillis: 5000,
301
- });
302
- await logger.shutdown();
303
- });
304
-
305
- it("falls back to the documented defaults for invalid batch values", async () => {
306
- const logger = makeLogger();
307
- await logger.initOTel({
308
- ...collectorConfig("http://collector/v1/logs"),
309
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_MAX_QUEUE_SIZE: 0,
310
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_MAX_BATCH_SIZE: -1,
311
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_TIMEOUT_MILLIS: 1.5,
312
- });
313
-
314
- expect(batchProcessorOptions()[0]).toEqual({
315
- exporter: expect.anything(),
316
- maxQueueSize: 2048,
317
- maxExportBatchSize: 512,
318
- exportTimeoutMillis: 30000,
319
- scheduledDelayMillis: 60000,
320
- });
321
- await logger.shutdown();
322
- });
323
-
324
- it.each([0, -5, 0.5])(
325
- "clamps the log export interval of %p seconds to one second",
326
- async (interval) => {
327
- const logger = makeLogger();
328
- await logger.initOTel({
329
- ...collectorConfig("http://collector/v1/logs"),
330
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS: interval,
331
- });
332
-
333
- expect(
334
- (batchProcessorOptions()[0] as { scheduledDelayMillis: number })
335
- .scheduledDelayMillis,
336
- ).toBe(1000);
337
- await logger.shutdown();
338
- },
339
- );
340
-
341
- it("falls back to the default delay for a NaN interval", async () => {
342
- const logger = makeLogger();
343
- await logger.initOTel({
344
- ...collectorConfig("http://collector/v1/logs"),
345
- OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS: NaN,
346
- });
347
-
348
- expect(
349
- (batchProcessorOptions()[0] as { scheduledDelayMillis: number })
350
- .scheduledDelayMillis,
351
- ).toBe(60000);
352
- await logger.shutdown();
353
- });
354
- });
355
-
356
- describe("service identity validation", () => {
357
- it("rejects an empty SERVICE_ID without creating an exporter", async () => {
358
- const logger = makeLogger();
359
-
360
- await expect(
361
- logger.initOTel({
362
- SERVICE_ID: " ",
363
- VERSION: "1.0.0",
364
- OPENTELEMETRY_COLLECTOR_HTTP_LOGS: "http://collector/v1/logs",
365
- }),
366
- ).rejects.toThrow("[otel-utils] SERVICE_ID must be a non-empty string");
367
-
368
- expect(mockExporterConstructor).not.toHaveBeenCalled();
369
- expect(logger.getLogger()).toBeUndefined();
370
- await expect(logger.shutdown()).resolves.toBeUndefined();
371
- });
372
-
373
- it("rejects an empty VERSION without creating an exporter", async () => {
374
- const logger = makeLogger();
375
-
376
- await expect(
377
- logger.initOTel({
378
- SERVICE_ID: "log-service",
379
- VERSION: "",
380
- OPENTELEMETRY_COLLECTOR_HTTP_LOGS: "http://collector/v1/logs",
381
- }),
382
- ).rejects.toThrow("[otel-utils] VERSION must be a non-empty string");
383
-
384
- expect(mockExporterConstructor).not.toHaveBeenCalled();
385
- await expect(logger.shutdown()).resolves.toBeUndefined();
386
- });
387
-
388
- it("keeps the previous provider when a re-initialisation is invalid", async () => {
389
- const logger = makeLogger();
390
- await logger.initOTel(collectorConfig("http://collector-1/v1/logs"));
391
- logger.createModuleLogger("billing").info("before-invalid-reinit");
392
-
393
- await expect(
394
- logger.initOTel({
395
- SERVICE_ID: "",
396
- VERSION: "1.0.0",
397
- OPENTELEMETRY_COLLECTOR_HTTP_LOGS: "http://collector-2/v1/logs",
398
- }),
399
- ).rejects.toThrow("[otel-utils] SERVICE_ID must be a non-empty string");
400
-
401
- expect(logger.getLogger()).toBeDefined();
402
- expect(logs.getLoggerProvider()).toBeInstanceOf(LoggerProvider);
403
- logger.createModuleLogger("billing").info("after-invalid-reinit");
404
- await logger.shutdown();
405
-
406
- expect(mockExporterConstructor).toHaveBeenCalledTimes(1);
407
- expect(exportedBodies(exporterAt(0))).toEqual(
408
- expect.arrayContaining([
409
- "[billing] before-invalid-reinit",
410
- "[billing] after-invalid-reinit",
411
- ]),
412
- );
413
- });
414
- });
415
-
416
- describe("console log modes", () => {
417
- it("mirrors through console.log by default", async () => {
418
- const logger = makeLogger();
419
- await logger.initOTel(collectorConfig("http://collector/v1/logs"));
420
-
421
- logger.createModuleLogger("billing").info("mirrored");
422
-
423
- expect(logSpy).toHaveBeenCalledWith("[info] [billing] mirrored");
424
- await logger.shutdown();
425
- });
426
-
427
- it("never suppresses console output while records are still exported", async () => {
428
- const logger = makeLogger();
429
- await logger.initOTel({
430
- ...collectorConfig("http://collector/v1/logs"),
431
- OPENTELEMETRY_CONSOLE_LOG_MODE: "never",
432
- });
433
-
434
- logger.createModuleLogger("billing").info("silent");
435
-
436
- expect(logSpy).not.toHaveBeenCalled();
437
- await logger.shutdown();
438
- expect(exportedBodies(exporterAt(0))).toContain("[billing] silent");
439
- });
440
-
441
- it("warns once and behaves as always for an invalid mode", async () => {
442
- const logger = makeLogger();
443
- await logger.initOTel({
444
- ...collectorConfig("http://collector/v1/logs"),
445
- OPENTELEMETRY_CONSOLE_LOG_MODE:
446
- "sometimes" as unknown as ConsoleLogMode,
447
- });
448
-
449
- expect(warnSpy).toHaveBeenCalledWith(
450
- expect.stringContaining("OPENTELEMETRY_CONSOLE_LOG_MODE"),
451
- );
452
- logger.createModuleLogger("billing").info("still mirrored");
453
- expect(logSpy).toHaveBeenCalledWith("[info] [billing] still mirrored");
454
- await logger.shutdown();
455
- });
456
-
457
- it("fallback mirrors only when no logs endpoint is configured", async () => {
458
- const withEndpoint = makeLogger();
459
- await withEndpoint.initOTel({
460
- ...collectorConfig("http://collector/v1/logs"),
461
- OPENTELEMETRY_CONSOLE_LOG_MODE: "fallback",
462
- });
463
- withEndpoint.createModuleLogger("billing").info("not-mirrored");
464
- expect(logSpy).not.toHaveBeenCalled();
465
- await withEndpoint.shutdown();
466
- expect(exportedBodies(exporterAt(0))).toContain("[billing] not-mirrored");
467
-
468
- const withoutEndpoint = makeLogger();
469
- await withoutEndpoint.initOTel({
470
- SERVICE_ID: "log-service",
471
- VERSION: "1.0.0",
472
- OPENTELEMETRY_CONSOLE_LOG_MODE: "fallback",
473
- });
474
- withoutEndpoint.createModuleLogger("billing").warn("mirrored-fallback");
475
- expect(warnSpy).toHaveBeenCalledWith("[warn] [billing] mirrored-fallback");
476
- await withoutEndpoint.shutdown();
477
- });
478
- });
479
- });
@@ -1,149 +0,0 @@
1
- import { logs, type Logger as OTelLogger } from "@opentelemetry/api";
2
- import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
3
- import {
4
- BatchLogRecordProcessor,
5
- LoggerProvider,
6
- } from "@opentelemetry/sdk-logs";
7
- import type {
8
- ConfigOTelInterface,
9
- ConsoleLogMode,
10
- } from "./models/ConfigOTelInterface";
11
- import { createOTelResource } from "./utils/createResource";
12
- import {
13
- normalizeConsoleLogMode,
14
- normalizeExportIntervalSeconds,
15
- normalizePositiveInteger,
16
- validateServiceIdentity,
17
- } from "./utils/configValidation";
18
- import { ModuleLogger } from "./ModuleLogger";
19
-
20
- import type { StandardLoggerInterface } from "./models/StandardLoggerInterface";
21
-
22
- let globalLoggerProvider: LoggerProvider | undefined;
23
-
24
- const ALREADY_REGISTERED_WARNING =
25
- "[otel-utils] A global logger provider is already registered; StandardLogger will not replace it. This instance still logs through its own provider, but logs.getLogger() keeps using the existing provider.";
26
-
27
- export class StandardLogger implements StandardLoggerInterface {
28
- private logger?: OTelLogger;
29
- private loggerProvider?: LoggerProvider;
30
- private serviceVersion?: string;
31
- private serviceName?: string;
32
- private ownsGlobalProvider = false;
33
- private shutdownPromise?: Promise<void>;
34
- private consoleMode: ConsoleLogMode = "always";
35
-
36
- public async initOTel(config: ConfigOTelInterface): Promise<void> {
37
- // Validate before releasing the previous provider: a bad re-init must keep
38
- // the working provider in place.
39
- validateServiceIdentity(config);
40
- this.consoleMode = normalizeConsoleLogMode(
41
- config.OPENTELEMETRY_CONSOLE_LOG_MODE,
42
- );
43
- // Re-initialisation flushes and unregisters the previous provider first.
44
- if (this.loggerProvider) {
45
- await this.releaseProvider();
46
- }
47
- this.shutdownPromise = undefined;
48
- this.serviceName = config.SERVICE_ID;
49
- this.serviceVersion = config.VERSION;
50
-
51
- if (!config.OPENTELEMETRY_COLLECTOR_HTTP_LOGS) {
52
- return;
53
- }
54
-
55
- const exporterHeaders: Record<string, string> = {};
56
- if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
57
- exporterHeaders["Authorization"] =
58
- `Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
59
- }
60
- const exporter = new OTLPLogExporter({
61
- url: config.OPENTELEMETRY_COLLECTOR_HTTP_LOGS,
62
- headers: exporterHeaders,
63
- });
64
-
65
- this.loggerProvider = new LoggerProvider({
66
- processors: [
67
- new BatchLogRecordProcessor({
68
- exporter,
69
- maxQueueSize: normalizePositiveInteger(
70
- config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_MAX_QUEUE_SIZE,
71
- 2048,
72
- ),
73
- maxExportBatchSize: normalizePositiveInteger(
74
- config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_MAX_BATCH_SIZE,
75
- 512,
76
- ),
77
- exportTimeoutMillis: normalizePositiveInteger(
78
- config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_TIMEOUT_MILLIS,
79
- 30000,
80
- ),
81
- scheduledDelayMillis:
82
- normalizeExportIntervalSeconds(
83
- config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS,
84
- 60,
85
- ) * 1000,
86
- }),
87
- ],
88
- resource: createOTelResource(this.serviceName, this.serviceVersion),
89
- });
90
-
91
- this.logger = this.loggerProvider.getLogger(
92
- `${this.serviceName}:${this.serviceVersion}`,
93
- );
94
- this.registerGlobalProvider();
95
- }
96
-
97
- public shutdown(): Promise<void> {
98
- if (!this.shutdownPromise) {
99
- this.shutdownPromise = this.releaseProvider();
100
- }
101
- return this.shutdownPromise;
102
- }
103
-
104
- public getLogger(): OTelLogger | undefined {
105
- return this.logger;
106
- }
107
-
108
- public createModuleLogger(moduleName: string): ModuleLogger {
109
- return new ModuleLogger(moduleName, this, { consoleMode: this.consoleMode });
110
- }
111
-
112
- private registerGlobalProvider(): void {
113
- if (globalLoggerProvider) {
114
- if (globalLoggerProvider === logs.getLoggerProvider()) {
115
- console.warn(ALREADY_REGISTERED_WARNING);
116
- return;
117
- }
118
- // The previous provider is no longer registered (disabled elsewhere).
119
- globalLoggerProvider = undefined;
120
- }
121
- if (
122
- this.loggerProvider &&
123
- logs.setGlobalLoggerProvider(this.loggerProvider)
124
- ) {
125
- globalLoggerProvider = this.loggerProvider;
126
- this.ownsGlobalProvider = true;
127
- } else {
128
- console.warn(ALREADY_REGISTERED_WARNING);
129
- }
130
- }
131
-
132
- private async releaseProvider(): Promise<void> {
133
- const provider = this.loggerProvider;
134
- const ownedGlobalProvider = this.ownsGlobalProvider;
135
- this.logger = undefined;
136
- this.loggerProvider = undefined;
137
- this.ownsGlobalProvider = false;
138
- if (!provider) {
139
- return;
140
- }
141
- await provider.shutdown();
142
- if (ownedGlobalProvider && logs.getLoggerProvider() === provider) {
143
- logs.disable();
144
- }
145
- if (globalLoggerProvider === provider) {
146
- globalLoggerProvider = undefined;
147
- }
148
- }
149
- }