@fimbul-works/logger 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,77 @@
1
+ import pino, { type Logger as Pino } from "pino";
2
+ /**
3
+ * Log level.
4
+ */
5
+ export type LogLevel = "info" | "error" | "warn" | "debug";
6
+ /**
7
+ * Configuration options for the Logger.
8
+ */
9
+ export interface LoggerOptions extends pino.LoggerOptions {
10
+ /**
11
+ * Optional name label (e.g., "http")
12
+ */
13
+ name?: string;
14
+ /**
15
+ * Optional log level (e.g., "info"), default: "info"
16
+ */
17
+ level?: string;
18
+ /**
19
+ * Optional targets, default: STDOUT & STDERR, disabled when NODE_ENV="test"
20
+ */
21
+ targets?: pino.TransportTargetOptions[];
22
+ }
23
+ /**
24
+ * A wrapper around Pino to provide a consistent logging interface.
25
+ */
26
+ export declare class Logger {
27
+ /**
28
+ * pino instance.
29
+ *
30
+ * @private
31
+ * @type {Pino}
32
+ */
33
+ private logger;
34
+ /**
35
+ * Creates a new Logger instance.
36
+ *
37
+ * @param {LoggerOptions} options - Optional configuration options for the logger
38
+ */
39
+ constructor(options?: pino.LoggerOptions);
40
+ /**
41
+ * Logs a message at the specified level.
42
+ *
43
+ * @param {LogLevel} level - The log level.
44
+ */
45
+ log(level: LogLevel, ...args: any[]): void;
46
+ /**
47
+ * Logs a message at the `info` level.
48
+ */
49
+ info(...args: any[]): void;
50
+ /**
51
+ * Logs a message at the `error` level.
52
+ */
53
+ error(...args: any[]): void;
54
+ /**
55
+ * Logs a message at the `warn` level.
56
+ */
57
+ warn(...args: any[]): void;
58
+ /**
59
+ * Logs a message at the `debug` level.
60
+ */
61
+ debug(...args: any[]): void;
62
+ /**
63
+ * Returns the underlying Pino logger instance.
64
+ *
65
+ * @returns {Pino} The Pino logger instance.
66
+ */
67
+ getRawLogger(): Pino;
68
+ /**
69
+ * Handles logging by parsing arguments and calling the appropriate Pino method.
70
+ *
71
+ * @private
72
+ * @param {LogLevel} level
73
+ * @param {any[]} args
74
+ */
75
+ private handleLog;
76
+ }
77
+ export default Logger;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Logger = void 0;
7
+ const pino_1 = __importDefault(require("pino"));
8
+ /**
9
+ * A wrapper around Pino to provide a consistent logging interface.
10
+ */
11
+ class Logger {
12
+ /**
13
+ * Creates a new Logger instance.
14
+ *
15
+ * @param {LoggerOptions} options - Optional configuration options for the logger
16
+ */
17
+ constructor(options = {}) {
18
+ this.logger = (0, pino_1.default)({
19
+ level: "info",
20
+ ...options,
21
+ transport: {
22
+ targets: process.env.NODE_ENV !== "test"
23
+ ? [
24
+ {
25
+ target: "pino/file",
26
+ options: { destination: 1 }, // STDOUT
27
+ level: options.level || "info",
28
+ },
29
+ {
30
+ target: "pino/file",
31
+ options: { destination: 2 }, // STDERR
32
+ level: "error",
33
+ },
34
+ ]
35
+ : [],
36
+ ...options.transport,
37
+ },
38
+ });
39
+ }
40
+ /**
41
+ * Logs a message at the specified level.
42
+ *
43
+ * @param {LogLevel} level - The log level.
44
+ */
45
+ log(level, ...args) {
46
+ this.handleLog(level, args);
47
+ }
48
+ /**
49
+ * Logs a message at the `info` level.
50
+ */
51
+ info(...args) {
52
+ this.handleLog("info", args);
53
+ }
54
+ /**
55
+ * Logs a message at the `error` level.
56
+ */
57
+ error(...args) {
58
+ this.handleLog("error", args);
59
+ }
60
+ /**
61
+ * Logs a message at the `warn` level.
62
+ */
63
+ warn(...args) {
64
+ this.handleLog("warn", args);
65
+ }
66
+ /**
67
+ * Logs a message at the `debug` level.
68
+ */
69
+ debug(...args) {
70
+ this.handleLog("debug", args);
71
+ }
72
+ /**
73
+ * Returns the underlying Pino logger instance.
74
+ *
75
+ * @returns {Pino} The Pino logger instance.
76
+ */
77
+ getRawLogger() {
78
+ return this.logger;
79
+ }
80
+ /**
81
+ * Handles logging by parsing arguments and calling the appropriate Pino method.
82
+ *
83
+ * @private
84
+ * @param {LogLevel} level
85
+ * @param {any[]} args
86
+ */
87
+ handleLog(level, args) {
88
+ if (args.length === 0) {
89
+ this.logger[level]("");
90
+ return;
91
+ }
92
+ const [first, ...rest] = args;
93
+ // Case 1: Object first -> Pass through (Standard Pino)
94
+ // logger.info({ id: 1 }, "msg")
95
+ if (typeof first === "object" && first !== null) {
96
+ this.logger[level](first, ...rest);
97
+ return;
98
+ }
99
+ // Case 2: String first
100
+ if (typeof first === "string") {
101
+ // Check for printf-style formatting
102
+ // Simple heuristic: if string contains %, treat as printf and pass through
103
+ if (first.includes("%") && rest.length > 0) {
104
+ this.logger[level](first, ...rest);
105
+ return;
106
+ }
107
+ // Check for (msg, obj) pattern -> Swap to (obj, msg) (Console style)
108
+ if (rest.length === 1 && typeof rest[0] === "object" && rest[0] !== null) {
109
+ this.logger[level](rest[0], first);
110
+ return;
111
+ }
112
+ // Check for (msg, ...vars) pattern -> Wrap in payload
113
+ if (rest.length > 0) {
114
+ this.logger[level]({ args: rest }, first);
115
+ return;
116
+ }
117
+ // Just a single string message
118
+ this.logger[level](first);
119
+ return;
120
+ }
121
+ // Case 3: Primitive first (non-string output) -> Wrap in payload
122
+ // logger.info(1, true)
123
+ this.logger[level]({ args }, "Log event");
124
+ }
125
+ }
126
+ exports.Logger = Logger;
127
+ exports.default = Logger;
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,77 @@
1
+ import pino, { type Logger as Pino } from "pino";
2
+ /**
3
+ * Log level.
4
+ */
5
+ export type LogLevel = "info" | "error" | "warn" | "debug";
6
+ /**
7
+ * Configuration options for the Logger.
8
+ */
9
+ export interface LoggerOptions extends pino.LoggerOptions {
10
+ /**
11
+ * Optional name label (e.g., "http")
12
+ */
13
+ name?: string;
14
+ /**
15
+ * Optional log level (e.g., "info"), default: "info"
16
+ */
17
+ level?: string;
18
+ /**
19
+ * Optional targets, default: STDOUT & STDERR, disabled when NODE_ENV="test"
20
+ */
21
+ targets?: pino.TransportTargetOptions[];
22
+ }
23
+ /**
24
+ * A wrapper around Pino to provide a consistent logging interface.
25
+ */
26
+ export declare class Logger {
27
+ /**
28
+ * pino instance.
29
+ *
30
+ * @private
31
+ * @type {Pino}
32
+ */
33
+ private logger;
34
+ /**
35
+ * Creates a new Logger instance.
36
+ *
37
+ * @param {LoggerOptions} options - Optional configuration options for the logger
38
+ */
39
+ constructor(options?: pino.LoggerOptions);
40
+ /**
41
+ * Logs a message at the specified level.
42
+ *
43
+ * @param {LogLevel} level - The log level.
44
+ */
45
+ log(level: LogLevel, ...args: any[]): void;
46
+ /**
47
+ * Logs a message at the `info` level.
48
+ */
49
+ info(...args: any[]): void;
50
+ /**
51
+ * Logs a message at the `error` level.
52
+ */
53
+ error(...args: any[]): void;
54
+ /**
55
+ * Logs a message at the `warn` level.
56
+ */
57
+ warn(...args: any[]): void;
58
+ /**
59
+ * Logs a message at the `debug` level.
60
+ */
61
+ debug(...args: any[]): void;
62
+ /**
63
+ * Returns the underlying Pino logger instance.
64
+ *
65
+ * @returns {Pino} The Pino logger instance.
66
+ */
67
+ getRawLogger(): Pino;
68
+ /**
69
+ * Handles logging by parsing arguments and calling the appropriate Pino method.
70
+ *
71
+ * @private
72
+ * @param {LogLevel} level
73
+ * @param {any[]} args
74
+ */
75
+ private handleLog;
76
+ }
77
+ export default Logger;
@@ -0,0 +1,120 @@
1
+ import pino from "pino";
2
+ /**
3
+ * A wrapper around Pino to provide a consistent logging interface.
4
+ */
5
+ export class Logger {
6
+ /**
7
+ * Creates a new Logger instance.
8
+ *
9
+ * @param {LoggerOptions} options - Optional configuration options for the logger
10
+ */
11
+ constructor(options = {}) {
12
+ this.logger = pino({
13
+ level: "info",
14
+ ...options,
15
+ transport: {
16
+ targets: process.env.NODE_ENV !== "test"
17
+ ? [
18
+ {
19
+ target: "pino/file",
20
+ options: { destination: 1 }, // STDOUT
21
+ level: options.level || "info",
22
+ },
23
+ {
24
+ target: "pino/file",
25
+ options: { destination: 2 }, // STDERR
26
+ level: "error",
27
+ },
28
+ ]
29
+ : [],
30
+ ...options.transport,
31
+ },
32
+ });
33
+ }
34
+ /**
35
+ * Logs a message at the specified level.
36
+ *
37
+ * @param {LogLevel} level - The log level.
38
+ */
39
+ log(level, ...args) {
40
+ this.handleLog(level, args);
41
+ }
42
+ /**
43
+ * Logs a message at the `info` level.
44
+ */
45
+ info(...args) {
46
+ this.handleLog("info", args);
47
+ }
48
+ /**
49
+ * Logs a message at the `error` level.
50
+ */
51
+ error(...args) {
52
+ this.handleLog("error", args);
53
+ }
54
+ /**
55
+ * Logs a message at the `warn` level.
56
+ */
57
+ warn(...args) {
58
+ this.handleLog("warn", args);
59
+ }
60
+ /**
61
+ * Logs a message at the `debug` level.
62
+ */
63
+ debug(...args) {
64
+ this.handleLog("debug", args);
65
+ }
66
+ /**
67
+ * Returns the underlying Pino logger instance.
68
+ *
69
+ * @returns {Pino} The Pino logger instance.
70
+ */
71
+ getRawLogger() {
72
+ return this.logger;
73
+ }
74
+ /**
75
+ * Handles logging by parsing arguments and calling the appropriate Pino method.
76
+ *
77
+ * @private
78
+ * @param {LogLevel} level
79
+ * @param {any[]} args
80
+ */
81
+ handleLog(level, args) {
82
+ if (args.length === 0) {
83
+ this.logger[level]("");
84
+ return;
85
+ }
86
+ const [first, ...rest] = args;
87
+ // Case 1: Object first -> Pass through (Standard Pino)
88
+ // logger.info({ id: 1 }, "msg")
89
+ if (typeof first === "object" && first !== null) {
90
+ this.logger[level](first, ...rest);
91
+ return;
92
+ }
93
+ // Case 2: String first
94
+ if (typeof first === "string") {
95
+ // Check for printf-style formatting
96
+ // Simple heuristic: if string contains %, treat as printf and pass through
97
+ if (first.includes("%") && rest.length > 0) {
98
+ this.logger[level](first, ...rest);
99
+ return;
100
+ }
101
+ // Check for (msg, obj) pattern -> Swap to (obj, msg) (Console style)
102
+ if (rest.length === 1 && typeof rest[0] === "object" && rest[0] !== null) {
103
+ this.logger[level](rest[0], first);
104
+ return;
105
+ }
106
+ // Check for (msg, ...vars) pattern -> Wrap in payload
107
+ if (rest.length > 0) {
108
+ this.logger[level]({ args: rest }, first);
109
+ return;
110
+ }
111
+ // Just a single string message
112
+ this.logger[level](first);
113
+ return;
114
+ }
115
+ // Case 3: Primitive first (non-string output) -> Wrap in payload
116
+ // logger.info(1, true)
117
+ this.logger[level]({ args }, "Log event");
118
+ }
119
+ }
120
+ export default Logger;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fimbul-works/logger",
3
- "description": "Simple wrapper for Pino",
4
- "version": "1.0.0",
3
+ "description": "A lightweight, TypeScript-friendly wrapper around Pino that provides flexible logging patterns with automatic argument handling",
4
+ "version": "1.0.1",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "MIT",
@@ -19,14 +19,22 @@
19
19
  "logger",
20
20
  "typescript"
21
21
  ],
22
- "scripts": {
23
- "build": "rm -rf dist && pnpm build:esm && pnpm build:cjs",
24
- "build:esm": "tsc -p tsconfig.json",
25
- "build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
26
- "format": "biome format --write",
27
- "test": "NODE_ENV=test vitest run",
28
- "prepublishOnly": "npm run build"
22
+ "main": "./dist/cjs/index.js",
23
+ "module": "./dist/esm/index.js",
24
+ "types": "./dist/esm/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/esm/index.d.ts",
28
+ "import": "./dist/esm/index.js",
29
+ "require": "./dist/cjs/index.js"
30
+ }
29
31
  },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "sideEffects": false,
30
38
  "dependencies": {
31
39
  "pino": "^10.3.0"
32
40
  },
@@ -35,5 +43,12 @@
35
43
  "@types/node": "^25.2.1",
36
44
  "typescript": "^5.9.3",
37
45
  "vitest": "^4.0.18"
46
+ },
47
+ "scripts": {
48
+ "build": "rm -rf dist && pnpm build:esm && pnpm build:cjs",
49
+ "build:esm": "tsc -p tsconfig.json",
50
+ "build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
51
+ "format": "biome format --write",
52
+ "test": "NODE_ENV=test vitest run"
38
53
  }
39
- }
54
+ }
package/biome.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "formatter": {
3
- "indentStyle": "space",
4
- "indentWidth": 2,
5
- "lineWidth": 120,
6
- "lineEnding": "lf"
7
- },
8
- "linter": {
9
- "rules": {
10
- "suspicious": {
11
- "noExplicitAny": "off"
12
- }
13
- }
14
- }
15
- }
package/src/index.test.ts DELETED
@@ -1,87 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { Logger } from "./index";
3
-
4
- // Mock Pino
5
- vi.mock("pino", () => {
6
- const info = vi.fn();
7
- const error = vi.fn();
8
- const warn = vi.fn();
9
- const debug = vi.fn();
10
- const logger = { info, error, warn, debug };
11
- return {
12
- default: vi.fn(() => logger),
13
- };
14
- });
15
-
16
- describe("Logger", () => {
17
- it("should log info messages", () => {
18
- const logger = new Logger();
19
- logger.info("Hello world");
20
-
21
- const rawLogger = logger.getRawLogger();
22
- expect(rawLogger.info).toHaveBeenCalledWith("Hello world");
23
- });
24
-
25
- it("should log error messages", () => {
26
- const logger = new Logger();
27
- const err = new Error("Test error");
28
-
29
- logger.error("Something went wrong", err);
30
-
31
- const rawLogger = logger.getRawLogger();
32
- expect(rawLogger.error).toHaveBeenCalledWith(err, "Something went wrong");
33
- });
34
-
35
- describe("Smart Argument Handling", () => {
36
- it("should swap args when calling (msg, obj)", () => {
37
- const logger = new Logger();
38
- const rawLogger = logger.getRawLogger();
39
- const obj = { id: 123 };
40
-
41
- logger.info("User login", obj);
42
-
43
- // Expect swap: (obj, msg)
44
- expect(rawLogger.info).toHaveBeenCalledWith(obj, "User login");
45
- });
46
-
47
- it("should wrap multiple args in payload object", () => {
48
- const logger = new Logger();
49
- const rawLogger = logger.getRawLogger();
50
-
51
- logger.info("Values", 1, true, "extra");
52
-
53
- // Expect wrap: ({ args: [1, true, "extra"] }, msg)
54
- expect(rawLogger.info).toHaveBeenCalledWith({ args: [1, true, "extra"] }, "Values");
55
- });
56
-
57
- it("should respect printf style formatting", () => {
58
- const logger = new Logger();
59
- const rawLogger = logger.getRawLogger();
60
-
61
- logger.info("User %s logged in", "Alice");
62
-
63
- // Expect pass-through: (msg, ...args)
64
- expect(rawLogger.info).toHaveBeenCalledWith("User %s logged in", "Alice");
65
- });
66
-
67
- it("should handle mixed printf and extra args (best effort)", () => {
68
- const logger = new Logger();
69
- const rawLogger = logger.getRawLogger();
70
-
71
- // If user mixes printf with too many args, we just pass through and let Pino handle/ignore
72
- logger.info("User %s", "Alice", "ExtraIgnored");
73
-
74
- expect(rawLogger.info).toHaveBeenCalledWith("User %s", "Alice", "ExtraIgnored");
75
- });
76
-
77
- it("should pass through (obj, msg) as is", () => {
78
- const logger = new Logger();
79
- const rawLogger = logger.getRawLogger();
80
- const obj = { id: 1 };
81
-
82
- logger.info(obj, "Message");
83
-
84
- expect(rawLogger.info).toHaveBeenCalledWith(obj, "Message");
85
- });
86
- });
87
- });
package/src/index.ts DELETED
@@ -1,170 +0,0 @@
1
- import pino, { type Logger as Pino } from "pino";
2
-
3
- /**
4
- * Log level.
5
- */
6
- export type LogLevel = "info" | "error" | "warn" | "debug";
7
-
8
- /**
9
- * Configuration options for the Logger.
10
- */
11
- export interface LoggerOptions extends pino.LoggerOptions {
12
- /**
13
- * Optional name label (e.g., "http")
14
- */
15
- name?: string;
16
-
17
- /**
18
- * Optional log level (e.g., "info"), default: "info"
19
- */
20
- level?: string;
21
-
22
- /**
23
- * Optional targets, default: STDOUT & STDERR, disabled when NODE_ENV="test"
24
- */
25
- targets?: pino.TransportTargetOptions[];
26
- }
27
-
28
- /**
29
- * A wrapper around Pino to provide a consistent logging interface.
30
- */
31
- export class Logger {
32
- /**
33
- * pino instance.
34
- *
35
- * @private
36
- * @type {Pino}
37
- */
38
- private logger: Pino;
39
-
40
- /**
41
- * Creates a new Logger instance.
42
- *
43
- * @param {LoggerOptions} options - Optional configuration options for the logger
44
- */
45
- constructor(options: pino.LoggerOptions = {}) {
46
- this.logger = pino({
47
- level: "info",
48
- ...options,
49
- transport: {
50
- targets:
51
- process.env.NODE_ENV !== "test"
52
- ? [
53
- {
54
- target: "pino/file",
55
- options: { destination: 1 }, // STDOUT
56
- level: options.level || "info",
57
- },
58
- {
59
- target: "pino/file",
60
- options: { destination: 2 }, // STDERR
61
- level: "error",
62
- },
63
- ]
64
- : [],
65
- ...options.transport,
66
- },
67
- });
68
- }
69
-
70
- /**
71
- * Logs a message at the specified level.
72
- *
73
- * @param {LogLevel} level - The log level.
74
- */
75
- public log(level: LogLevel, ...args: any[]): void {
76
- this.handleLog(level, args);
77
- }
78
-
79
- /**
80
- * Logs a message at the `info` level.
81
- */
82
- public info(...args: any[]): void {
83
- this.handleLog("info", args);
84
- }
85
-
86
- /**
87
- * Logs a message at the `error` level.
88
- */
89
- public error(...args: any[]): void {
90
- this.handleLog("error", args);
91
- }
92
-
93
- /**
94
- * Logs a message at the `warn` level.
95
- */
96
- public warn(...args: any[]): void {
97
- this.handleLog("warn", args);
98
- }
99
-
100
- /**
101
- * Logs a message at the `debug` level.
102
- */
103
- public debug(...args: any[]): void {
104
- this.handleLog("debug", args);
105
- }
106
-
107
- /**
108
- * Returns the underlying Pino logger instance.
109
- *
110
- * @returns {Pino} The Pino logger instance.
111
- */
112
- public getRawLogger(): Pino {
113
- return this.logger;
114
- }
115
-
116
- /**
117
- * Handles logging by parsing arguments and calling the appropriate Pino method.
118
- *
119
- * @private
120
- * @param {LogLevel} level
121
- * @param {any[]} args
122
- */
123
- private handleLog(level: LogLevel, args: any[]): void {
124
- if (args.length === 0) {
125
- this.logger[level]("");
126
- return;
127
- }
128
-
129
- const [first, ...rest] = args;
130
-
131
- // Case 1: Object first -> Pass through (Standard Pino)
132
- // logger.info({ id: 1 }, "msg")
133
- if (typeof first === "object" && first !== null) {
134
- this.logger[level](first, ...rest);
135
- return;
136
- }
137
-
138
- // Case 2: String first
139
- if (typeof first === "string") {
140
- // Check for printf-style formatting
141
- // Simple heuristic: if string contains %, treat as printf and pass through
142
- if (first.includes("%") && rest.length > 0) {
143
- this.logger[level](first, ...rest);
144
- return;
145
- }
146
-
147
- // Check for (msg, obj) pattern -> Swap to (obj, msg) (Console style)
148
- if (rest.length === 1 && typeof rest[0] === "object" && rest[0] !== null) {
149
- this.logger[level](rest[0], first);
150
- return;
151
- }
152
-
153
- // Check for (msg, ...vars) pattern -> Wrap in payload
154
- if (rest.length > 0) {
155
- this.logger[level]({ args: rest }, first);
156
- return;
157
- }
158
-
159
- // Just a single string message
160
- this.logger[level](first);
161
- return;
162
- }
163
-
164
- // Case 3: Primitive first (non-string output) -> Wrap in payload
165
- // logger.info(1, true)
166
- this.logger[level]({ args }, "Log event");
167
- }
168
- }
169
-
170
- export default Logger;
package/tsconfig.cjs.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "module": "CommonJS",
5
- "moduleResolution": "node",
6
- "outDir": "dist/cjs",
7
- "verbatimModuleSyntax": false
8
- }
9
- }
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ES2020",
5
- "lib": ["ES2020"],
6
- "moduleResolution": "Bundler",
7
- "declaration": true,
8
- "allowJs": true,
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "outDir": "./dist/esm/"
14
- },
15
- "include": ["src"],
16
- "exclude": ["src/**/*.test.ts", "node_modules"]
17
- }