-
Notifications
You must be signed in to change notification settings - Fork 253
Expand file tree
/
Copy pathlog.ts
More file actions
89 lines (78 loc) · 2.59 KB
/
log.ts
File metadata and controls
89 lines (78 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
//
// SPDX-License-Identifier: Apache-2.0
import { Writable } from 'node:stream';
import type { DestinationStream, Logger } from 'pino';
import { multistream, pino } from 'pino';
import { build as pinoPretty } from 'pino-pretty';
import { type PinoLogObject, emitToOtel } from './telemetry/pino_otel_transport.js';
/** @internal */
export type LoggerOptions = {
pretty: boolean;
level?: string;
};
/** @internal */
export let loggerOptions: LoggerOptions;
/** @internal */
let logger: Logger | undefined = undefined;
/** @internal */
let otelEnabled = false;
/** @internal */
export const log = () => {
if (!logger) {
throw new TypeError('logger not initialized. did you forget to run initializeLogger()?');
}
return logger;
};
/** @internal */
export const initializeLogger = ({ pretty, level }: LoggerOptions) => {
loggerOptions = { pretty, level };
logger = pino(
{ level: level || 'info' },
pretty ? pinoPretty({ colorize: true }) : process.stdout,
);
};
/**
* Custom Pino destination that parses JSON logs and emits to OTEL.
* This receives the FULL serialized log including msg, level, time, etc.
*/
class OtelDestination extends Writable {
_write(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void {
try {
const line = chunk.toString().trim();
if (line) {
const logObj = JSON.parse(line) as PinoLogObject;
emitToOtel(logObj);
}
} catch {
// Ignore parse errors (e.g., non-JSON lines)
}
callback();
}
}
/**
* Enable OTEL logging by reconfiguring the logger with multistream.
* Uses a custom destination that receives full JSON logs (with msg, level, time).
*
* The base logger level is set to 'debug' so all logs are generated,
* while each stream filters to its own level:
* - Terminal: user-specified level (default: 'info')
* - OTEL/Cloud: always 'debug' to capture all logs for observability
*
* @internal
*/
export const enableOtelLogging = () => {
if (otelEnabled || !logger) {
console.warn('OTEL logging already enabled or logger not initialized');
return;
}
otelEnabled = true;
const { pretty, level } = loggerOptions;
const terminalLevel = level || 'info';
const streams: { stream: DestinationStream; level: string }[] = [
{ stream: pretty ? pinoPretty({ colorize: true }) : process.stdout, level: terminalLevel },
{ stream: new OtelDestination(), level: 'debug' },
];
// Base level must be 'debug' to generate all logs; each stream filters independently
logger = pino({ level: 'debug' }, multistream(streams));
};