Files
stats/packages/logger/index.ts
Carl-Gerhard Lindesvärd 11e9ecac1a feat: group analytics
* wip

* wip

* wip

* wip

* wip

* add buffer

* wip

* wip

* fixes

* fix

* wip

* group validation

* fix group issues

* docs: add groups
2026-03-20 10:46:09 +01:00

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;
}