fix(api): deduplicating objects in logs (#60319)

This commit is contained in:
Mrugesh Mohapatra
2025-05-13 20:40:49 +05:30
committed by GitHub
parent 75712748dd
commit eeeeb034ec

View File

@@ -1,40 +1,22 @@
import pino, { TransportTargetOptions } from 'pino';
import { Transform, TransformCallback, TransformOptions } from 'stream';
import { FastifyRequest, FastifyReply } from 'fastify';
import { isEmpty } from 'lodash';
import pino, {
TransportTargetOptions,
DestinationStream,
LoggerOptions
} from 'pino';
import { FCC_API_LOG_LEVEL, FCC_API_LOG_TRANSPORT } from './env';
const transportOptionsPretty: TransportTargetOptions = {
target: 'pino-pretty',
options: {
singleLine: true,
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
colorize: true
}
};
const serializersPretty = {
req: (req: FastifyRequest) => {
return {
REQ_METHOD: req.method,
REQ_URL: req.url
};
},
res: (res: FastifyReply) => {
return {
RES_STATUS_CODE: res.statusCode,
RES_ELAPSED_TIME: res.elapsedTime
};
}
};
const serializersDefault = {
const serializers = {
req: (req: FastifyRequest) => {
const id = req.id || 'ID not found';
const method = req.method || 'METHOD not found';
const url = req.url || 'URL not found';
const xForwardedFor = Array.isArray(req.headers['x-forwarded-for'])
? req.headers['x-forwarded-for'][0]
? req.headers['x-forwarded-for'][0]
: req.headers['x-forwarded-for']
: req.headers['x-forwarded-for'];
const ip =
req.headers['cf-connecting-ip'] ||
@@ -64,19 +46,70 @@ const serializersDefault = {
}
};
const prettyTarget: TransportTargetOptions = {
target: 'pino-pretty',
options: {
singleLine: true,
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
colorize: true
}
};
class DeduplicatingTransform extends Transform {
constructor(options?: TransformOptions) {
super({ ...options, objectMode: false });
}
_transform(
chunk: Buffer | string,
encoding: BufferEncoding,
callback: TransformCallback
): void {
try {
const logString = Buffer.isBuffer(chunk) ? chunk.toString() : chunk;
logString.split('\n').forEach(line => {
if (line.trim() === '') return;
const logObject = JSON.parse(line);
const processedLog = JSON.parse(JSON.stringify(logObject));
this.push(JSON.stringify(processedLog) + '\n');
});
callback();
} catch (_err) {
// If parsing or processing fails, pass the original chunk through
// In a production scenario, you might want to log this internal error
// to a different stream or use a fallback mechanism.
this.push(chunk);
callback();
}
}
}
/**
* Get a logger instance with the default options.
* Get a logger instance.
*
* @returns A logger instance with the default options.
* @returns A logger instance.
*/
export const getLogger = () => {
const isPretty = FCC_API_LOG_TRANSPORT === 'pretty';
const options = {
const options: LoggerOptions = {
level: FCC_API_LOG_LEVEL || 'info',
serializers: isPretty ? serializersPretty : serializersDefault
serializers
};
return isPretty
? pino({ ...options, transport: transportOptionsPretty })
: pino(options);
if (isPretty) {
const transport = pino.transport({ targets: [prettyTarget] }) as
| DestinationStream
| undefined;
return pino(options, transport);
} else {
// For non-pretty, use the custom de-duplicating transform stream
// This logger will write to a stream that then pipes to our de-duplicator
const deduplicator = new DeduplicatingTransform();
// Pino writes NDJSON, so our transform needs to handle that.
// The pino instance itself doesn't need a complex transport, it writes to the stream.
const logger = pino(options, deduplicator);
deduplicator.pipe(process.stdout);
return logger;
}
};