@hardlydifficult/logger 1.0.5 → 1.0.6

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.
Files changed (2) hide show
  1. package/README.md +112 -35
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/logger
2
2
 
3
- Plugin-based structured logger with Console, Discord, and File output plugins.
3
+ Plugin-based structured logger with configurable log levels and extensible output handlers for Console, File, and Discord.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,97 +8,160 @@ Plugin-based structured logger with Console, Discord, and File output plugins.
8
8
  npm install @hardlydifficult/logger
9
9
  ```
10
10
 
11
- ## Usage
11
+ ## Quick Start
12
12
 
13
13
  ```typescript
14
14
  import { Logger, ConsolePlugin, FilePlugin, DiscordPlugin } from "@hardlydifficult/logger";
15
15
 
16
- const discord = new DiscordPlugin();
17
-
18
16
  const logger = new Logger("info")
19
17
  .use(new ConsolePlugin())
20
- .use(new FilePlugin("/var/log/app.log"))
21
- .use(discord);
22
-
23
- // Wire up Discord sender once the bot is ready
24
- discord.setSender((msg) => channel.send(msg));
18
+ .use(new FilePlugin("./app.log"));
25
19
 
26
20
  logger.info("Server started", { port: 3000 });
27
21
  logger.warn("High memory usage", { usage: "85%" });
28
22
  logger.error("Request failed", { url: "/api/data", status: 500 });
29
-
30
- // Out-of-band notification (goes to plugins that support notify)
31
- logger.notify("Deployment complete");
32
23
  ```
33
24
 
34
- ## API
25
+ ## Core Logger
35
26
 
36
- ### `Logger`
27
+ The `Logger` class dispatches log entries to registered plugins based on a minimum log level.
37
28
 
38
29
  ```typescript
39
- new Logger(minLevel?: LogLevel) // default: "info"
30
+ import { Logger } from "@hardlydifficult/logger";
31
+
32
+ const logger = new Logger("info"); // default: "info"
40
33
  ```
41
34
 
35
+ ### Log Levels
36
+
37
+ Log levels in order of severity: `debug` < `info` < `warn` < `error`. Entries below the logger's `minLevel` are filtered out before reaching plugins.
38
+
39
+ ### Methods
40
+
42
41
  | Method | Description |
43
42
  |--------|-------------|
44
- | `use(plugin)` | Register a plugin (returns `this` for chaining) |
43
+ | `use(plugin, options?)` | Register a plugin; returns `this` for chaining. Optional `minLevel` filters entries per-plugin. |
45
44
  | `debug(message, context?)` | Log at debug level |
46
45
  | `info(message, context?)` | Log at info level |
47
46
  | `warn(message, context?)` | Log at warn level |
48
47
  | `error(message, context?)` | Log at error level |
49
48
  | `notify(message)` | Send out-of-band notification to plugins that support it |
50
49
 
51
- Log levels: `debug` < `info` < `warn` < `error`. Entries below `minLevel` are filtered out.
50
+ ### Plugin-Level Filtering
52
51
 
53
- ### Plugins
52
+ Each plugin can have its own minimum log level, independent of the logger's global level:
54
53
 
55
- #### `ConsolePlugin`
54
+ ```typescript
55
+ const logger = new Logger("debug")
56
+ .use(new ConsolePlugin()) // receives all levels
57
+ .use(new FilePlugin("./errors.log"), { minLevel: "error" }); // only errors
58
+
59
+ logger.debug("This goes to console only");
60
+ logger.error("This goes to both console and file");
61
+ ```
56
62
 
57
- Logs to `console.log`/`console.warn`/`console.error` with formatted timestamps.
63
+ ## Console Plugin
64
+
65
+ Outputs formatted log entries to the console, routing to `console.log`, `console.warn`, or `console.error` based on log level.
58
66
 
59
67
  ```typescript
60
- new ConsolePlugin()
68
+ import { Logger, ConsolePlugin } from "@hardlydifficult/logger";
69
+
70
+ const logger = new Logger("info").use(new ConsolePlugin());
71
+
72
+ logger.info("Server started", { port: 3000 });
73
+ // Output: [2025-01-15T10:30:00.000Z] INFO: Server started {"port":3000}
61
74
  ```
62
75
 
63
- #### `FilePlugin`
76
+ ### Format
64
77
 
65
- Appends JSON log entries to a file (one entry per line). Creates the directory if needed.
78
+ The `formatEntry` function is also exported for custom formatting:
66
79
 
67
80
  ```typescript
68
- new FilePlugin(filePath: string)
81
+ import { formatEntry } from "@hardlydifficult/logger";
82
+ import type { LogEntry } from "@hardlydifficult/logger";
83
+
84
+ const entry: LogEntry = {
85
+ level: "warn",
86
+ message: "High memory",
87
+ timestamp: "2025-01-15T10:30:00.000Z",
88
+ context: { usage: "85%" },
89
+ };
90
+
91
+ console.log(formatEntry(entry));
92
+ // Output: [2025-01-15T10:30:00.000Z] WARN: High memory {"usage":"85%"}
69
93
  ```
70
94
 
71
- #### `DiscordPlugin`
95
+ ## File Plugin
72
96
 
73
- Sends warn/error logs and notifications to Discord. The sender is set lazily since the Discord connection may not be ready at logger creation time.
97
+ Appends JSON-serialized log entries to a file (one entry per line, JSONL format). Creates parent directories automatically.
74
98
 
75
99
  ```typescript
100
+ import { Logger, FilePlugin } from "@hardlydifficult/logger";
101
+
102
+ const logger = new Logger("info").use(new FilePlugin("./logs/app.log"));
103
+
104
+ logger.info("Request processed", { method: "GET", path: "/api/users" });
105
+ // Appends: {"level":"info","message":"Request processed","timestamp":"2025-01-15T10:30:00.000Z","context":{"method":"GET","path":"/api/users"}}
106
+ ```
107
+
108
+ ## Discord Plugin
109
+
110
+ Forwards warn/error log entries and notifications to Discord via a configurable sender function. Useful for alerting on critical issues.
111
+
112
+ ```typescript
113
+ import { Logger, DiscordPlugin } from "@hardlydifficult/logger";
114
+
76
115
  const discord = new DiscordPlugin();
116
+ const logger = new Logger("info").use(discord);
117
+
118
+ // Set the sender once your Discord bot is ready
77
119
  discord.setSender((msg) => channel.send(msg));
120
+
121
+ logger.warn("High memory usage", { usage: "85%" });
122
+ // Sends to Discord: ⚠️ **WARN**: High memory usage
123
+ // ```json
124
+ // {
125
+ // "usage": "85%"
126
+ // }
127
+ // ```
128
+
129
+ logger.notify("Deployment complete");
130
+ // Sends to Discord: Deployment complete
78
131
  ```
79
132
 
80
- ### Custom Plugins
133
+ ### Behavior
81
134
 
82
- Implement the `LoggerPlugin` interface:
135
+ - Only `warn` and `error` log entries are sent (debug/info are filtered)
136
+ - Warn entries use ⚠️ emoji; error entries use 🚨 emoji
137
+ - Context is formatted as a JSON code block when present
138
+ - `notify()` sends messages directly without level filtering
139
+ - If `setSender` is not called, entries are silently dropped
140
+
141
+ ## Custom Plugins
142
+
143
+ Implement the `LoggerPlugin` interface to create custom output handlers:
83
144
 
84
145
  ```typescript
85
146
  import type { LoggerPlugin, LogEntry } from "@hardlydifficult/logger";
147
+ import { Logger } from "@hardlydifficult/logger";
86
148
 
87
- class MyPlugin implements LoggerPlugin {
149
+ class SlackPlugin implements LoggerPlugin {
88
150
  log(entry: LogEntry): void {
89
- // Handle log entry
151
+ if (entry.level === "error") {
152
+ // Send to Slack
153
+ }
90
154
  }
91
155
 
92
- // Optional: handle notify() calls
93
156
  notify?(message: string): void {
94
- // Handle notification
157
+ // Send notification to Slack
95
158
  }
96
159
  }
97
160
 
98
- logger.use(new MyPlugin());
161
+ const logger = new Logger("info").use(new SlackPlugin());
99
162
  ```
100
163
 
101
- ### Types
164
+ ## Types
102
165
 
103
166
  ```typescript
104
167
  type LogLevel = "debug" | "info" | "warn" | "error";
@@ -106,7 +169,7 @@ type LogLevel = "debug" | "info" | "warn" | "error";
106
169
  interface LogEntry {
107
170
  readonly level: LogLevel;
108
171
  readonly message: string;
109
- readonly timestamp: string;
172
+ readonly timestamp: string; // ISO 8601 format
110
173
  readonly context?: Readonly<Record<string, unknown>>;
111
174
  }
112
175
 
@@ -114,4 +177,18 @@ interface LoggerPlugin {
114
177
  log(entry: LogEntry): void;
115
178
  notify?(message: string): void;
116
179
  }
180
+
181
+ type DiscordSender = (message: string) => void;
117
182
  ```
183
+
184
+ ## Error Handling
185
+
186
+ All plugins are isolated—if one plugin throws an error, it does not affect other plugins or the logger itself. Errors are silently swallowed to ensure logging never crashes your application.
187
+
188
+ ```typescript
189
+ const logger = new Logger("info")
190
+ .use(new ConsolePlugin()) // works fine
191
+ .use(brokenPlugin); // throws, but doesn't break the logger
192
+
193
+ logger.info("This still works"); // ConsolePlugin receives it
194
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/logger",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [