@hardlydifficult/logger 1.0.10 → 1.0.12
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.
- package/README.md +136 -28
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/logger
|
|
2
2
|
|
|
3
|
-
Plugin-based structured logger with configurable log levels and extensible output handlers for Console, File, and
|
|
3
|
+
Plugin-based structured logger with configurable log levels and extensible output handlers for Console, File, Discord, and Session-based JSONL tracking.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -60,6 +60,15 @@ logger.debug("This goes to console only");
|
|
|
60
60
|
logger.error("This goes to both console and file");
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### Notifications
|
|
64
|
+
|
|
65
|
+
Out-of-band notifications are sent to plugins that implement `notify()`.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
logger.notify("Deployment complete");
|
|
69
|
+
// DiscordPlugin will send this as a standalone message; other plugins ignore it.
|
|
70
|
+
```
|
|
71
|
+
|
|
63
72
|
## Console Plugin
|
|
64
73
|
|
|
65
74
|
Outputs formatted log entries to the console, routing to `console.log`, `console.warn`, or `console.error` based on log level.
|
|
@@ -106,39 +115,130 @@ logger.info("Request processed", { method: "GET", path: "/api/users" });
|
|
|
106
115
|
|
|
107
116
|
## Discord Plugin
|
|
108
117
|
|
|
109
|
-
Forwards warn
|
|
118
|
+
Forwards `warn` and `error` log entries and notifications to Discord via a configurable sender function. Useful for alerting on critical issues.
|
|
119
|
+
|
|
120
|
+
### Setup
|
|
121
|
+
|
|
122
|
+
1. Create a Discord webhook for your channel.
|
|
123
|
+
2. Configure the sender to POST to the webhook URL.
|
|
110
124
|
|
|
111
125
|
```typescript
|
|
112
126
|
import { Logger, DiscordPlugin } from "@hardlydifficult/logger";
|
|
113
127
|
|
|
128
|
+
const logger = new Logger("warn");
|
|
114
129
|
const discord = new DiscordPlugin();
|
|
115
|
-
const logger = new Logger("info").use(discord);
|
|
116
130
|
|
|
117
|
-
|
|
118
|
-
|
|
131
|
+
discord.setSender((message) => {
|
|
132
|
+
// Example: use node:fetch or your preferred HTTP client
|
|
133
|
+
// fetch("https://discord.com/api/webhooks/...", {
|
|
134
|
+
// method: "POST",
|
|
135
|
+
// headers: { "Content-Type": "application/json" },
|
|
136
|
+
// body: JSON.stringify({ content: message })
|
|
137
|
+
// });
|
|
138
|
+
});
|
|
119
139
|
|
|
120
|
-
logger.
|
|
121
|
-
// Sends to Discord: ⚠️ **WARN**: High memory usage
|
|
122
|
-
// ```json
|
|
123
|
-
// {
|
|
124
|
-
// "usage": "85%"
|
|
125
|
-
// }
|
|
126
|
-
// ```
|
|
127
|
-
|
|
128
|
-
logger.notify("Deployment complete");
|
|
129
|
-
// Sends to Discord: Deployment complete
|
|
140
|
+
logger.use(discord);
|
|
130
141
|
```
|
|
131
142
|
|
|
132
143
|
### Behavior
|
|
133
144
|
|
|
134
145
|
| Behavior | Description |
|
|
135
|
-
|
|
146
|
+
|--------|-------------|
|
|
136
147
|
| Only `warn` and `error` log entries are sent (debug/info are filtered) | |
|
|
137
148
|
| Warn entries use ⚠️ emoji; error entries use 🚨 emoji | |
|
|
138
149
|
| Context is formatted as a JSON code block when present | |
|
|
139
150
|
| `notify()` sends messages directly without level filtering | |
|
|
140
151
|
| If `setSender` is not called, entries are silently dropped | |
|
|
141
152
|
|
|
153
|
+
### Formatting
|
|
154
|
+
|
|
155
|
+
Error entries include a siren emoji and JSON context in a code block; warnings use a warning emoji.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
logger.error("Database unavailable", { host: "db.example.com", retry: 3 });
|
|
159
|
+
// ➡️ Sends to Discord:
|
|
160
|
+
// 🚨 **ERROR**: Database unavailable
|
|
161
|
+
// ```json
|
|
162
|
+
// {
|
|
163
|
+
// "host": "db.example.com",
|
|
164
|
+
// "retry": 3
|
|
165
|
+
// }
|
|
166
|
+
// ```
|
|
167
|
+
|
|
168
|
+
logger.warn("Slow query detected", { durationMs: 2500 });
|
|
169
|
+
// ➡️ Sends to Discord:
|
|
170
|
+
// ⚠️ **WARN**: Slow query detected
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Session Tracking
|
|
174
|
+
|
|
175
|
+
The `SessionTracker` class persists structured session logs as JSONL files for debugging and analysis.
|
|
176
|
+
|
|
177
|
+
### SessionTracker
|
|
178
|
+
|
|
179
|
+
Create a tracker pointing to a writable state directory.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { SessionTracker } from "@hardlydifficult/logger";
|
|
183
|
+
|
|
184
|
+
const tracker = new SessionTracker({
|
|
185
|
+
stateDirectory: "/var/log", // Required
|
|
186
|
+
subdirectory: "ai-sessions", // Optional, defaults to "sessions"
|
|
187
|
+
maxAgeMs: 7 * 24 * 60 * 60 * 1000, // Optional, defaults to 7 days
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Append Entries
|
|
192
|
+
|
|
193
|
+
Each entry includes a type discriminator and arbitrary data.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
tracker.append("sess-abc123", {
|
|
197
|
+
type: "session_start",
|
|
198
|
+
data: { userId: 456, prompt: "Hello" },
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
tracker.append("sess-abc123", {
|
|
202
|
+
type: "ai_response",
|
|
203
|
+
data: { response: "Hi there!", model: "gpt-4" },
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
tracker.append("sess-abc123", {
|
|
207
|
+
type: "tool_call",
|
|
208
|
+
data: { name: "Search", input: { query: "weather" } },
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Read & List Sessions
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// Read all entries for a session
|
|
216
|
+
const entries = tracker.read("sess-abc123");
|
|
217
|
+
// Returns SessionEntry[] in chronological order
|
|
218
|
+
|
|
219
|
+
// List all tracked sessions with metadata
|
|
220
|
+
const sessions = tracker.list();
|
|
221
|
+
// Returns SessionInfo[] sorted by lastModifiedAt descending
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Session Metadata
|
|
225
|
+
|
|
226
|
+
| Field | Type | Description |
|
|
227
|
+
|-------|------|-------------|
|
|
228
|
+
| `sessionId` | string | Name of the `.jsonl` file (without extension) |
|
|
229
|
+
| `sizeBytes` | number | File size on disk |
|
|
230
|
+
| `startedAt` | string | ISO timestamp (first entry or file creation time) |
|
|
231
|
+
| `lastModifiedAt` | string | ISO timestamp of file’s last write |
|
|
232
|
+
| `entryCount` | number | Number of JSONL lines in the file |
|
|
233
|
+
|
|
234
|
+
### Session Operations
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
tracker.has("sess-abc123"); // true/false
|
|
238
|
+
tracker.delete("sess-abc123"); // true if deleted, false if missing
|
|
239
|
+
tracker.cleanup(); // Deletes files older than maxAgeMs, returns count deleted
|
|
240
|
+
```
|
|
241
|
+
|
|
142
242
|
## Custom Plugins
|
|
143
243
|
|
|
144
244
|
Implement the `LoggerPlugin` interface to create custom output handlers:
|
|
@@ -165,20 +265,28 @@ const logger = new Logger("info").use(new SlackPlugin());
|
|
|
165
265
|
## Types
|
|
166
266
|
|
|
167
267
|
```typescript
|
|
168
|
-
type
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
268
|
+
import type {
|
|
269
|
+
LogLevel,
|
|
270
|
+
LogEntry,
|
|
271
|
+
LoggerPlugin,
|
|
272
|
+
SessionEntry,
|
|
273
|
+
SessionEntryType,
|
|
274
|
+
SessionInfo,
|
|
275
|
+
SessionTrackerOptions,
|
|
276
|
+
} from "@hardlydifficult/logger";
|
|
277
|
+
```
|
|
176
278
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
279
|
+
| Type | Description |
|
|
280
|
+
|------|-------------|
|
|
281
|
+
| `LogLevel` | `"debug" \| "info" \| "warn" \| "error"` |
|
|
282
|
+
| `LogEntry` | `{ level, message, timestamp, context? }` |
|
|
283
|
+
| `LoggerPlugin` | `{ log(entry): void; notify?(message): void }` |
|
|
284
|
+
| `SessionEntryType` | `"session_start" \| "ai_request" \| "ai_response" \| "tool_call" \| "tool_result" \| "error" \| "session_end" \| "metadata"` |
|
|
285
|
+
| `SessionEntry` | `{ type, timestamp, data }` |
|
|
286
|
+
| `SessionInfo` | Metadata about persisted session files |
|
|
287
|
+
| `SessionTrackerOptions` | `stateDirectory` (required), `subdirectory?`, `maxAgeMs?` |
|
|
181
288
|
|
|
289
|
+
```typescript
|
|
182
290
|
type DiscordSender = (message: string) => void;
|
|
183
291
|
```
|
|
184
292
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardlydifficult/logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"vitest": "4.0.18"
|
|
21
21
|
},
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
23
|
+
"node": ">=20.19.0"
|
|
24
24
|
},
|
|
25
25
|
"type": "commonjs",
|
|
26
26
|
"exports": {
|