Files
2026-04-23 13:10:38 +02:00

151 lines
4.8 KiB
JavaScript

'use strict';
const util = require('util');
const colors = require('colors');
const Sentry = require('@sentry/node');
colors.enable(); // colors.disable();
const LOGS_DEBUG = process.env.LOGS_DEBUG !== undefined ? process.env.LOGS_DEBUG === 'true' : true;
const LOGS_JSON = process.env.LOGS_JSON ? process.env.LOGS_JSON === 'true' : false;
const LOGS_JSON_PRETTY = process.env.LOGS_JSON_PRETTY ? process.env.LOGS_JSON_PRETTY === 'true' : false;
const SENTRY_ENABLED = process.env.SENTRY_ENABLED === 'true';
const SENTRY_DSN = process.env.SENTRY_DSN;
const SENTRY_LOG_LEVELS = process.env.SENTRY_LOG_LEVELS
? process.env.SENTRY_LOG_LEVELS.split(',').map((l) => l.trim())
: ['error'];
function sentryCapture(level, msg, op) {
if (!SENTRY_ENABLED || !SENTRY_DSN || SENTRY_DSN === '') return;
if (!SENTRY_LOG_LEVELS.includes(level)) return;
if (level === 'error') {
const err = op instanceof Error ? op : new Error(String(msg));
Sentry.captureException(err, { extra: { message: msg, data: op } });
} else {
const sentryLevel = level === 'warn' ? 'warning' : level;
Sentry.captureMessage(String(msg), { level: sentryLevel, extra: { data: op } });
}
}
const options = {
depth: null,
colors: true,
};
module.exports = class Logs {
constructor(appName = 'call-me') {
this.appName = colors.yellow(appName);
this.debugOn = LOGS_DEBUG;
this.timeStart = Date.now();
this.timeEnd = null;
this.timeElapsedMs = null;
this.tzOptions = {
timeZone: process.env.TZ || 'UTC',
hour12: false,
};
}
debug(msg, op = '') {
if (this.debugOn) {
this.timeEnd = Date.now();
this.timeElapsedMs = this.getFormatTime(Math.floor(this.timeEnd - this.timeStart));
if (LOGS_JSON) {
this.jsonLog('debug', this.appName, msg, op, { elapsed: this.timeElapsedMs });
} else {
console.debug(
'[' + this.getDateTime() + '] [' + this.appName + '] ' + msg,
util.inspect(op, options),
this.timeElapsedMs
);
}
this.timeStart = Date.now();
}
sentryCapture('debug', msg, op);
}
log(msg, op = '') {
if (LOGS_JSON) {
this.jsonLog('log', this.appName, msg, op);
} else {
console.log('[' + this.getDateTime() + '] [' + this.appName + '] ' + msg, util.inspect(op, options));
}
sentryCapture('log', msg, op);
}
info(msg, op = '') {
if (LOGS_JSON) {
this.jsonLog('info', this.appName, msg, op);
} else {
console.info(
'[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.green(msg),
util.inspect(op, options)
);
}
sentryCapture('info', msg, op);
}
warn(msg, op = '') {
if (LOGS_JSON) {
this.jsonLog('warn', this.appName, msg, op);
} else {
console.info(
'[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.yellow(msg),
util.inspect(op, options)
);
}
sentryCapture('warn', msg, op);
}
error(msg, op = '') {
if (LOGS_JSON) {
this.jsonLog('error', this.appName, msg, op);
} else {
console.info(
'[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.red(msg),
util.inspect(op, options)
);
}
sentryCapture('error', msg, op);
}
jsonLog(level, appName, msg, op, extra = {}) {
const logObj = {
timestamp: new Date().toISOString(),
level,
app: appName,
message: msg,
...extra,
};
if (op && typeof op === 'object' && Object.keys(op).length > 0) {
logObj.data = op;
}
LOGS_JSON_PRETTY ? console.log(JSON.stringify(logObj, null, 2)) : console.log(JSON.stringify(logObj));
}
getDateTime() {
const currentTime = new Date().toLocaleString('en-US', this.tzOptions);
const milliseconds = String(new Date().getMilliseconds()).padStart(3, '0');
return colors.cyan(`${currentTime}:${milliseconds}`);
}
getFormatTime(ms) {
let time = Math.floor(ms);
let type = 'ms';
if (ms >= 1000) {
time = Math.floor((ms / 1000) % 60);
type = 's';
}
if (ms >= 60000) {
time = Math.floor((ms / 1000 / 60) % 60);
type = 'm';
}
if (ms >= (3, 6e6)) {
time = Math.floor((ms / 1000 / 60 / 60) % 24);
type = 'h';
}
return colors.magenta('+' + time + type);
}
};