* wip * wip * wip * wip * wip * add buffer * wip * wip * fixes * fix * wip * group validation * fix group issues * docs: add groups
136 lines
3.1 KiB
TypeScript
136 lines
3.1 KiB
TypeScript
import * as HyperDX from '@hyperdx/node-opentelemetry';
|
|
import winston from 'winston';
|
|
|
|
export { winston };
|
|
|
|
export type ILogger = winston.Logger;
|
|
|
|
const logLevel = process.env.LOG_LEVEL ?? 'info';
|
|
const silent = process.env.LOG_SILENT === 'true';
|
|
|
|
const customLevels = {
|
|
fatal: 0,
|
|
warn: 4,
|
|
trace: 7,
|
|
};
|
|
|
|
// naming all darn levels to make sure we never get any errors with the logger
|
|
winston.addColors({
|
|
emerg: 'red',
|
|
alert: 'red',
|
|
crit: 'red',
|
|
error: 'red',
|
|
warning: 'yellow',
|
|
notice: 'cyan',
|
|
info: 'green',
|
|
debug: 'blue',
|
|
fatal: 'red',
|
|
warn: 'yellow',
|
|
trace: 'gray',
|
|
});
|
|
|
|
export function createLogger({ name }: { name: string }): ILogger {
|
|
const service = [process.env.LOG_PREFIX, name, process.env.NODE_ENV ?? 'dev']
|
|
.filter(Boolean)
|
|
.join('-');
|
|
|
|
const prettyError = (error: Error) => ({
|
|
...error,
|
|
stack: error.stack,
|
|
message: error.message,
|
|
});
|
|
|
|
const errorFormatter = winston.format((info) => {
|
|
if (info.error instanceof Error) {
|
|
return {
|
|
...info,
|
|
error: prettyError(info.error),
|
|
};
|
|
}
|
|
if (info instanceof Error) {
|
|
return {
|
|
...info,
|
|
...prettyError(info),
|
|
};
|
|
}
|
|
return info;
|
|
});
|
|
|
|
const sensitiveKeys = [
|
|
'password',
|
|
'token',
|
|
'secret',
|
|
'authorization',
|
|
'apiKey',
|
|
];
|
|
|
|
const redactSensitiveInfo = winston.format((info) => {
|
|
const redactObject = (obj: any): any => {
|
|
if (!obj || typeof obj !== 'object') {
|
|
return obj;
|
|
}
|
|
|
|
return Object.keys(obj).reduce((acc, key) => {
|
|
const lowerKey = key.toLowerCase();
|
|
if (sensitiveKeys.some((k) => lowerKey.includes(k))) {
|
|
acc[key] = '[REDACTED]';
|
|
} else if (typeof obj[key] === 'object') {
|
|
if (obj[key] instanceof Date) {
|
|
acc[key] = obj[key].toISOString();
|
|
} else {
|
|
acc[key] = redactObject(obj[key]);
|
|
}
|
|
} else {
|
|
acc[key] = obj[key];
|
|
}
|
|
return acc;
|
|
}, {} as any);
|
|
};
|
|
|
|
return { ...info, ...redactObject(info) };
|
|
});
|
|
|
|
const transports: winston.transport[] = [];
|
|
let format: winston.Logform.Format;
|
|
|
|
if (process.env.HYPERDX_API_KEY) {
|
|
transports.push(
|
|
HyperDX.getWinstonTransport(logLevel, {
|
|
detectResources: true,
|
|
service,
|
|
})
|
|
);
|
|
format = winston.format.combine(
|
|
errorFormatter(),
|
|
redactSensitiveInfo(),
|
|
winston.format.json()
|
|
);
|
|
} else {
|
|
transports.push(new winston.transports.Console());
|
|
format = winston.format.combine(
|
|
errorFormatter(),
|
|
redactSensitiveInfo(),
|
|
winston.format.colorize({
|
|
all: true,
|
|
}),
|
|
winston.format.printf((info) => {
|
|
const { level, message, service, ...meta } = info;
|
|
const metaStr =
|
|
Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';
|
|
return `${level} ${message}${metaStr}`;
|
|
})
|
|
);
|
|
}
|
|
|
|
const logger = winston.createLogger({
|
|
defaultMeta: { service },
|
|
level: logLevel,
|
|
format,
|
|
transports,
|
|
silent,
|
|
levels: { ...customLevels, ...winston.config.syslog.levels },
|
|
});
|
|
|
|
return logger;
|
|
}
|