feat(logging): add structured server diagnostics
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "@minecraft-account-manager/logging",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": { ".": "./src/index.ts" },
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"pino": "^10.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.0.3",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import pino, { type DestinationStream, type Logger } from "pino";
|
||||
|
||||
const redactedPaths = [
|
||||
"apiKey",
|
||||
"authorization",
|
||||
"password",
|
||||
"token",
|
||||
"*.apiKey",
|
||||
"*.authorization",
|
||||
"*.password",
|
||||
"*.token",
|
||||
"headers.authorization",
|
||||
"req.headers.authorization",
|
||||
];
|
||||
|
||||
export function createLogger(
|
||||
service: string,
|
||||
options: { destination?: DestinationStream } = {},
|
||||
): Logger {
|
||||
return pino(
|
||||
{
|
||||
level: process.env.LOG_LEVEL?.trim() || "info",
|
||||
base: {
|
||||
service,
|
||||
environment: process.env.NODE_ENV ?? "development",
|
||||
version: process.env.APP_VERSION ?? "development",
|
||||
},
|
||||
redact: {
|
||||
paths: redactedPaths,
|
||||
censor: "[Redacted]",
|
||||
},
|
||||
},
|
||||
options.destination,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Writable } from "node:stream";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createLogger } from "../src/index";
|
||||
|
||||
function captureLog() {
|
||||
let output = "";
|
||||
const destination = new Writable({
|
||||
write(chunk, _encoding, callback) {
|
||||
output += chunk.toString();
|
||||
callback();
|
||||
},
|
||||
});
|
||||
return { destination, read: () => JSON.parse(output.trim()) as Record<string, unknown> };
|
||||
}
|
||||
|
||||
describe("structured application logging", () => {
|
||||
it("emits service metadata and redacts credential fields", () => {
|
||||
const capture = captureLog();
|
||||
const logger = createLogger("account-manager-test", { destination: capture.destination });
|
||||
|
||||
logger.info({ token: "secret-token", apiKey: "secret-key", operation: "test" }, "Test event");
|
||||
|
||||
expect(capture.read()).toMatchObject({
|
||||
service: "account-manager-test",
|
||||
token: "[Redacted]",
|
||||
apiKey: "[Redacted]",
|
||||
operation: "test",
|
||||
msg: "Test event",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": { "types": ["node", "vitest/globals"] },
|
||||
"include": ["src/**/*.ts", "test/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user