enabled logging as well 👌😪

This commit is contained in:
user
2026-02-28 19:50:55 +02:00
parent cf8d72cac3
commit 9914218b81
5 changed files with 50 additions and 128 deletions

View File

@@ -18,9 +18,11 @@
"dependencies": { "dependencies": {
"@opentelemetry/api": "^1.9.0", "@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.70.1", "@opentelemetry/auto-instrumentations-node": "^0.70.1",
"@opentelemetry/exporter-logs-otlp-proto": "^0.212.0",
"@opentelemetry/exporter-metrics-otlp-proto": "^0.212.0", "@opentelemetry/exporter-metrics-otlp-proto": "^0.212.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.212.0", "@opentelemetry/exporter-trace-otlp-proto": "^0.212.0",
"@opentelemetry/sdk-node": "^0.212.0", "@opentelemetry/sdk-node": "^0.212.0",
"@opentelemetry/sdk-logs": "^0.212.0",
"@pkg/db": "workspace:*", "@pkg/db": "workspace:*",
"@pkg/logger": "workspace:*", "@pkg/logger": "workspace:*",
"@pkg/logic": "workspace:*", "@pkg/logic": "workspace:*",

View File

@@ -1,6 +1,8 @@
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node"; import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-proto";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto"; import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { createAddHookMessageChannel } from "import-in-the-middle"; import { createAddHookMessageChannel } from "import-in-the-middle";
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
import { NodeSDK } from "@opentelemetry/sdk-node"; import { NodeSDK } from "@opentelemetry/sdk-node";
import { settings } from "@pkg/settings"; import { settings } from "@pkg/settings";
import { register } from "node:module"; import { register } from "node:module";
@@ -9,11 +11,17 @@ const { registerOptions } = createAddHookMessageChannel();
register("import-in-the-middle/hook.mjs", import.meta.url, registerOptions); register("import-in-the-middle/hook.mjs", import.meta.url, registerOptions);
const sdk = new NodeSDK({ const sdk = new NodeSDK({
serviceName: settings.appName, serviceName: settings.otelServiceName || settings.appName,
traceExporter: new OTLPTraceExporter({ traceExporter: new OTLPTraceExporter(),
// url: settings.otelExporterOtlpHttpEndpoint, logRecordProcessors: [new BatchLogRecordProcessor(new OTLPLogExporter())],
instrumentations: [
getNodeAutoInstrumentations({
"@opentelemetry/instrumentation-winston": {
// We add OpenTelemetryTransportV3 explicitly in @pkg/logger.
disableLogSending: true,
},
}), }),
instrumentations: [getNodeAutoInstrumentations()], ],
}); });
sdk.start(); sdk.start();

View File

@@ -1,15 +1,13 @@
import DailyRotateFile from "winston-daily-rotate-file"; import { OpenTelemetryTransportV3 } from "@opentelemetry/winston-transport";
import { settings } from "@pkg/settings"; import { settings } from "@pkg/settings";
import type { Err } from "@pkg/result"; import type { Err } from "@pkg/result";
import winston from "winston"; import winston from "winston";
import util from "util"; import util from "util";
import path from "path";
process.on("warning", (warning) => { process.on("warning", (warning) => {
const msg = String(warning?.message || ""); const msg = String(warning?.message || "");
const name = String((warning as any)?.name || ""); const name = String((warning as any)?.name || "");
// Ignore the noisy timer warning from Node/kafkajs interplay
if ( if (
name === "TimeoutNegativeWarning" || name === "TimeoutNegativeWarning" ||
msg.includes("TimeoutNegativeWarning") || msg.includes("TimeoutNegativeWarning") ||
@@ -18,7 +16,6 @@ process.on("warning", (warning) => {
return; return;
} }
// Keep other warnings visible
console.warn(warning); console.warn(warning);
}); });
@@ -28,7 +25,7 @@ const levels = {
info: 2, info: 2,
http: 3, http: 3,
debug: 4, debug: 4,
}; } as const;
const colors = { const colors = {
error: "red", error: "red",
@@ -40,13 +37,12 @@ const colors = {
const level = () => { const level = () => {
const envLevel = process.env.LOG_LEVEL?.toLowerCase(); const envLevel = process.env.LOG_LEVEL?.toLowerCase();
if (envLevel && envLevel in Object.keys(levels)) { if (envLevel && Object.prototype.hasOwnProperty.call(levels, envLevel)) {
return envLevel; return envLevel as keyof typeof levels;
} }
return settings.isDevelopment ? "debug" : "warn"; return settings.isDevelopment ? "debug" : "warn";
}; };
// Console format with colors
const consoleFormat = winston.format.combine( const consoleFormat = winston.format.combine(
winston.format.errors({ stack: true }), winston.format.errors({ stack: true }),
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }), winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }),
@@ -54,19 +50,13 @@ const consoleFormat = winston.format.combine(
winston.format.printf((info) => { winston.format.printf((info) => {
const { level, message, timestamp, ...extra } = info; const { level, message, timestamp, ...extra } = info;
let formattedMessage = ""; const formattedMessage =
if (message instanceof Error) { message instanceof Error
formattedMessage = message.stack || message.message; ? message.stack || message.message
} else if (typeof message === "object") { : typeof message === "object"
formattedMessage = util.inspect(message, { ? util.inspect(message, { depth: null, colors: true })
depth: null, : String(message);
colors: true,
});
} else {
formattedMessage = message as any as string;
}
// Handle extra fields (if any)
const formattedExtra = const formattedExtra =
Object.keys(extra).length > 0 Object.keys(extra).length > 0
? `\n${util.inspect(extra, { depth: null, colors: true })}` ? `\n${util.inspect(extra, { depth: null, colors: true })}`
@@ -76,53 +66,18 @@ const consoleFormat = winston.format.combine(
}), }),
); );
// JSON format for file logging
const fileFormat = winston.format.combine(
winston.format.errors({ stack: true }),
winston.format.timestamp(),
winston.format.json(),
);
// File transport with daily rotation
const fileTransport = new DailyRotateFile({
filename: path.join("logs", "app-%DATE%.log"),
datePattern: "YYYY-MM-DD",
maxSize: "20m",
maxFiles: "14d",
format: fileFormat,
});
// Error file transport with daily rotation
const errorFileTransport = new DailyRotateFile({
filename: path.join("logs", "error-%DATE%.log"),
datePattern: "YYYY-MM-DD",
maxSize: "20m",
maxFiles: "14d",
level: "error",
format: fileFormat,
});
const transports: winston.transport[] = [
new winston.transports.Console({ format: consoleFormat }),
fileTransport,
errorFileTransport,
];
winston.addColors(colors); winston.addColors(colors);
const logger = winston.createLogger({ const logger = winston.createLogger({
level: level(), level: level(),
levels, levels,
transports, format: consoleFormat,
format: fileFormat, transports: [
exceptionHandlers: [
new winston.transports.Console({ format: consoleFormat }), new winston.transports.Console({ format: consoleFormat }),
fileTransport, new OpenTelemetryTransportV3(),
],
rejectionHandlers: [
new winston.transports.Console({ format: consoleFormat }),
fileTransport,
], ],
exceptionHandlers: [new winston.transports.Console({ format: consoleFormat })],
rejectionHandlers: [new winston.transports.Console({ format: consoleFormat })],
}); });
const stream = { write: (message: string) => logger.http(message.trim()) }; const stream = { write: (message: string) => logger.http(message.trim()) };

View File

@@ -9,10 +9,9 @@
"typescript": "^5.9.3" "typescript": "^5.9.3"
}, },
"dependencies": { "dependencies": {
"@axiomhq/winston": "^1.3.1", "@opentelemetry/winston-transport": "^0.22.0",
"@pkg/result": "workspace:*", "@pkg/result": "workspace:*",
"@pkg/settings": "workspace:*", "@pkg/settings": "workspace:*",
"winston": "^3.17.0", "winston": "^3.17.0"
"winston-daily-rotate-file": "^5.0.0"
} }
} }

78
pnpm-lock.yaml generated
View File

@@ -35,12 +35,18 @@ importers:
'@opentelemetry/auto-instrumentations-node': '@opentelemetry/auto-instrumentations-node':
specifier: ^0.70.1 specifier: ^0.70.1
version: 0.70.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0)) version: 0.70.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))
'@opentelemetry/exporter-logs-otlp-proto':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-metrics-otlp-proto': '@opentelemetry/exporter-metrics-otlp-proto':
specifier: ^0.212.0 specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0) version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-trace-otlp-proto': '@opentelemetry/exporter-trace-otlp-proto':
specifier: ^0.212.0 specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0) version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-logs':
specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-node': '@opentelemetry/sdk-node':
specifier: ^0.212.0 specifier: ^0.212.0
version: 0.212.0(@opentelemetry/api@1.9.0) version: 0.212.0(@opentelemetry/api@1.9.0)
@@ -261,9 +267,9 @@ importers:
packages/logger: packages/logger:
dependencies: dependencies:
'@axiomhq/winston': '@opentelemetry/winston-transport':
specifier: ^1.3.1 specifier: ^0.22.0
version: 1.4.0 version: 0.22.0
'@pkg/result': '@pkg/result':
specifier: workspace:* specifier: workspace:*
version: link:../result version: link:../result
@@ -276,9 +282,6 @@ importers:
winston: winston:
specifier: ^3.17.0 specifier: ^3.17.0
version: 3.19.0 version: 3.19.0
winston-daily-rotate-file:
specifier: ^5.0.0
version: 5.0.0(winston@3.19.0)
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
@@ -415,14 +418,6 @@ packages:
'@ark/util@0.56.0': '@ark/util@0.56.0':
resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==}
'@axiomhq/js@1.4.0':
resolution: {integrity: sha512-wC5x1ud/QJMstrjpicATkyY8+ZVWEl4WlXMtA5EZf7hkj0+b191yv4yynLxLEfr/MveXora9m6CWdJq4DsbcAg==}
engines: {node: '>=20'}
'@axiomhq/winston@1.4.0':
resolution: {integrity: sha512-fVHwkWROOOyCuzVSXanMMkw5EVYwwKMal7zk87l6R9Zn69RBvIWVIFC8iSYM9Ea3Cg7t1sJHaDdeKvO9O4NXUw==}
engines: {node: '>=20'}
'@babel/runtime@7.28.6': '@babel/runtime@7.28.6':
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -1462,6 +1457,10 @@ packages:
peerDependencies: peerDependencies:
'@opentelemetry/api': ^1.1.0 '@opentelemetry/api': ^1.1.0
'@opentelemetry/winston-transport@0.22.0':
resolution: {integrity: sha512-VuiSjTxfAk5GNuTtBPbvPEDPFV8U9qWgn4DyGHuBNfuJrBcz21mmRyQxpOR+ueG6oA7Nrx7MmTFJ4JiWDvF2Vw==}
engines: {node: ^18.19.0 || >=20.6.0}
'@otplib/core@13.3.0': '@otplib/core@13.3.0':
resolution: {integrity: sha512-pnQDOuCmFVeF/XnboJq9TOJgLoo2idNPJKMymOF8vGqJJ+ReKRYM9bUGjNPRWC0tHjMwu1TXbnzyBp494JgRag==} resolution: {integrity: sha512-pnQDOuCmFVeF/XnboJq9TOJgLoo2idNPJKMymOF8vGqJJ+ReKRYM9bUGjNPRWC0tHjMwu1TXbnzyBp494JgRag==}
@@ -2683,12 +2682,6 @@ packages:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13} engines: {node: ^12.20 || >= 14.13}
fetch-retry@6.0.0:
resolution: {integrity: sha512-BUFj1aMubgib37I3v4q78fYo63Po7t4HUPTpQ6/QE6yK6cIQrP+W43FYToeTEyg5m2Y7eFUtijUuAv/PDlWuag==}
file-stream-rotator@0.6.1:
resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==}
find-up@4.1.0: find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -3059,9 +3052,6 @@ packages:
module-details-from-path@1.0.4: module-details-from-path@1.0.4:
resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
mri@1.2.0: mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -3120,10 +3110,6 @@ packages:
resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==} resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==}
engines: {node: '>=14.16'} engines: {node: '>=14.16'}
object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
obug@2.1.1: obug@2.1.1:
resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
@@ -3917,12 +3903,6 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
hasBin: true hasBin: true
winston-daily-rotate-file@5.0.0:
resolution: {integrity: sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==}
engines: {node: '>=8'}
peerDependencies:
winston: ^3
winston-transport@4.9.0: winston-transport@4.9.0:
resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
@@ -4017,15 +3997,6 @@ snapshots:
'@ark/util@0.56.0': '@ark/util@0.56.0':
optional: true optional: true
'@axiomhq/js@1.4.0':
dependencies:
fetch-retry: 6.0.0
'@axiomhq/winston@1.4.0':
dependencies:
'@axiomhq/js': 1.4.0
winston-transport: 4.9.0
'@babel/runtime@7.28.6': '@babel/runtime@7.28.6':
optional: true optional: true
@@ -5097,6 +5068,11 @@ snapshots:
'@opentelemetry/api': 1.9.0 '@opentelemetry/api': 1.9.0
'@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0) '@opentelemetry/core': 2.5.1(@opentelemetry/api@1.9.0)
'@opentelemetry/winston-transport@0.22.0':
dependencies:
'@opentelemetry/api-logs': 0.212.0
winston-transport: 4.9.0
'@otplib/core@13.3.0': {} '@otplib/core@13.3.0': {}
'@otplib/hotp@13.3.0': '@otplib/hotp@13.3.0':
@@ -6140,12 +6116,6 @@ snapshots:
node-domexception: 1.0.0 node-domexception: 1.0.0
web-streams-polyfill: 3.3.3 web-streams-polyfill: 3.3.3
fetch-retry@6.0.0: {}
file-stream-rotator@0.6.1:
dependencies:
moment: 2.30.1
find-up@4.1.0: find-up@4.1.0:
dependencies: dependencies:
locate-path: 5.0.0 locate-path: 5.0.0
@@ -6560,8 +6530,6 @@ snapshots:
module-details-from-path@1.0.4: {} module-details-from-path@1.0.4: {}
moment@2.30.1: {}
mri@1.2.0: {} mri@1.2.0: {}
mrmime@2.0.1: {} mrmime@2.0.1: {}
@@ -6597,8 +6565,6 @@ snapshots:
normalize-url@8.1.1: normalize-url@8.1.1:
optional: true optional: true
object-hash@3.0.0: {}
obug@2.1.1: {} obug@2.1.1: {}
on-exit-leak-free@2.1.2: {} on-exit-leak-free@2.1.2: {}
@@ -7339,14 +7305,6 @@ snapshots:
siginfo: 2.0.0 siginfo: 2.0.0
stackback: 0.0.2 stackback: 0.0.2
winston-daily-rotate-file@5.0.0(winston@3.19.0):
dependencies:
file-stream-rotator: 0.6.1
object-hash: 3.0.0
triple-beam: 1.4.1
winston: 3.19.0
winston-transport: 4.9.0
winston-transport@4.9.0: winston-transport@4.9.0:
dependencies: dependencies:
logform: 2.7.0 logform: 2.7.0