loggily 0.3.0 → 0.4.0
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 +67 -22
- package/package.json +24 -11
- package/src/context.ts +26 -11
- package/src/core.ts +118 -72
- package/src/file-writer.ts +12 -6
- package/src/index.browser.ts +9 -1
- package/src/index.ts +9 -1
- package/src/tracing.ts +11 -3
- package/src/worker.ts +119 -132
- package/.github/workflows/docs.yml +0 -58
- package/.github/workflows/release.yml +0 -31
- package/.github/workflows/test.yml +0 -20
- package/CHANGELOG.md +0 -45
- package/CLAUDE.md +0 -299
- package/CONTRIBUTING.md +0 -58
- package/benchmarks/overhead.ts +0 -267
- package/bun.lock +0 -479
- package/docs/api-reference.md +0 -400
- package/docs/benchmarks.md +0 -106
- package/docs/comparison.md +0 -315
- package/docs/conditional-logging-research.md +0 -159
- package/docs/guide.md +0 -205
- package/docs/migration-from-debug.md +0 -310
- package/docs/migration-from-pino.md +0 -178
- package/docs/migration-from-winston.md +0 -179
- package/docs/site/.vitepress/config.ts +0 -67
- package/docs/site/api/configuration.md +0 -94
- package/docs/site/api/index.md +0 -61
- package/docs/site/api/logger.md +0 -99
- package/docs/site/api/worker.md +0 -120
- package/docs/site/api/writers.md +0 -69
- package/docs/site/guide/getting-started.md +0 -143
- package/docs/site/guide/journey.md +0 -203
- package/docs/site/guide/migration-from-debug.md +0 -24
- package/docs/site/guide/spans.md +0 -139
- package/docs/site/guide/why.md +0 -55
- package/docs/site/guide/workers.md +0 -113
- package/docs/site/guide/zero-overhead.md +0 -87
- package/docs/site/index.md +0 -54
- package/tests/features.test.ts +0 -552
- package/tests/logger.test.ts +0 -944
- package/tests/tracing.test.ts +0 -618
- package/tests/universal.test.ts +0 -107
- package/tests/worker.test.ts +0 -590
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -10
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
# Migration from debug
|
|
2
|
-
|
|
3
|
-
Step-by-step guide for migrating from the `debug` package to `loggily`.
|
|
4
|
-
|
|
5
|
-
## Why Migrate?
|
|
6
|
-
|
|
7
|
-
| Feature | debug | loggily |
|
|
8
|
-
| ------------------ | ------------------- | ------------------------------------------- |
|
|
9
|
-
| Log levels | No (namespace only) | Yes (trace, debug, info, warn, error) |
|
|
10
|
-
| Structured data | No (printf-style) | Yes (JSON objects) |
|
|
11
|
-
| Performance | Good | Better (conditional logging skips arg eval) |
|
|
12
|
-
| Timing/spans | No | Built-in spans with auto-timing |
|
|
13
|
-
| JSON output | No | Yes (production/TRACE_FORMAT=json) |
|
|
14
|
-
| Zero-cost disabled | No | Yes (optional chaining pattern) |
|
|
15
|
-
|
|
16
|
-
## Quick Migration
|
|
17
|
-
|
|
18
|
-
### Before (debug)
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
import createDebug from "debug"
|
|
22
|
-
|
|
23
|
-
const debug = createDebug("myapp")
|
|
24
|
-
const debugDb = createDebug("myapp:db")
|
|
25
|
-
|
|
26
|
-
debug("starting server on port %d", 3000)
|
|
27
|
-
debugDb("query: %s, params: %o", sql, params)
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### After (loggily)
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
import { createLogger } from "loggily"
|
|
34
|
-
|
|
35
|
-
const log = createLogger("myapp")
|
|
36
|
-
const dbLog = log.logger("db")
|
|
37
|
-
|
|
38
|
-
log.info("starting server", { port: 3000 })
|
|
39
|
-
dbLog.debug("query", { sql, params })
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Pattern Mapping
|
|
43
|
-
|
|
44
|
-
### Basic Logging
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
// debug
|
|
48
|
-
debug("message")
|
|
49
|
-
debug("message %s", value)
|
|
50
|
-
debug("message %d items", count)
|
|
51
|
-
debug("object: %o", obj)
|
|
52
|
-
debug("json: %j", data)
|
|
53
|
-
|
|
54
|
-
// loggily
|
|
55
|
-
log.debug("message")
|
|
56
|
-
log.debug(`message ${value}`)
|
|
57
|
-
log.debug("message", { items: count })
|
|
58
|
-
log.debug("object", { obj })
|
|
59
|
-
log.debug("data", { data })
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Namespaces
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
// debug - separate instances
|
|
66
|
-
const debug = createDebug("myapp")
|
|
67
|
-
const debugDb = createDebug("myapp:db")
|
|
68
|
-
const debugCache = createDebug("myapp:cache")
|
|
69
|
-
|
|
70
|
-
// loggily - hierarchy via .logger()
|
|
71
|
-
const log = createLogger("myapp")
|
|
72
|
-
const dbLog = log.logger("db") // myapp:db
|
|
73
|
-
const cacheLog = log.logger("cache") // myapp:cache
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Environment Variables
|
|
77
|
-
|
|
78
|
-
| debug | loggily | Effect |
|
|
79
|
-
| ---------------- | ----------------- | -------------------------------------- |
|
|
80
|
-
| `DEBUG=*` | `DEBUG=*` | Enable all debug output |
|
|
81
|
-
| `DEBUG=myapp*` | `DEBUG=myapp` | Enable debug for namespace |
|
|
82
|
-
| `DEBUG=myapp:db` | `DEBUG=myapp:db` | Enable specific namespace |
|
|
83
|
-
| `DEBUG=*,-noisy` | `DEBUG=*,-noisy` | Exclude specific namespace |
|
|
84
|
-
| N/A | `LOG_LEVEL=debug` | Set log level without namespace filter |
|
|
85
|
-
| N/A | `TRACE=1` | Enable span timing |
|
|
86
|
-
| N/A | `TRACE=myapp:db` | Enable spans for namespace |
|
|
87
|
-
|
|
88
|
-
### Conditional Enabling
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
// debug - checks if enabled
|
|
92
|
-
if (debug.enabled) {
|
|
93
|
-
debug("expensive: %o", computeExpensive())
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// loggily - optional chaining (cleaner, faster)
|
|
97
|
-
log.debug?.(`expensive: ${computeExpensive()}`)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Common Patterns
|
|
101
|
-
|
|
102
|
-
### Printf-style to Template Literals
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
// debug (printf-style)
|
|
106
|
-
debug("user %s logged in from %s", username, ip)
|
|
107
|
-
debug("processed %d items in %dms", count, duration)
|
|
108
|
-
|
|
109
|
-
// loggily (template literals or structured)
|
|
110
|
-
log.info(`user ${username} logged in from ${ip}`)
|
|
111
|
-
// or structured (preferred)
|
|
112
|
-
log.info("user logged in", { username, ip })
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Objects and JSON
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
// debug
|
|
119
|
-
debug("config: %O", config) // multi-line
|
|
120
|
-
debug("data: %o", data) // single-line
|
|
121
|
-
debug("json: %j", obj) // JSON
|
|
122
|
-
|
|
123
|
-
// loggily (always structured JSON)
|
|
124
|
-
log.debug("config", { config })
|
|
125
|
-
log.debug("data", { data })
|
|
126
|
-
log.debug("obj", { obj })
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Error Logging
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
// debug
|
|
133
|
-
debug("error: %s", err.message)
|
|
134
|
-
debug("stack: %s", err.stack)
|
|
135
|
-
|
|
136
|
-
// loggily (Error objects handled automatically)
|
|
137
|
-
log.error(err) // Extracts message, stack, code
|
|
138
|
-
log.error(err, { context: "additional info" })
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Timing Operations
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// debug (manual timing)
|
|
145
|
-
const start = Date.now()
|
|
146
|
-
await doWork()
|
|
147
|
-
debug("operation took %dms", Date.now() - start)
|
|
148
|
-
|
|
149
|
-
// loggily (built-in spans)
|
|
150
|
-
{
|
|
151
|
-
using span = log.span("operation")
|
|
152
|
-
await doWork()
|
|
153
|
-
}
|
|
154
|
-
// Automatic: SPAN myapp:operation (234ms)
|
|
155
|
-
|
|
156
|
-
// With data
|
|
157
|
-
{
|
|
158
|
-
using span = log.span("import", { file: "data.csv" })
|
|
159
|
-
span.spanData.rowCount = await importFile()
|
|
160
|
-
}
|
|
161
|
-
// SPAN myapp:import (1234ms) {rowCount: 500, file: "data.csv"}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Extending/Inheriting
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
// debug - new instance required
|
|
168
|
-
const debug = createDebug("myapp")
|
|
169
|
-
const debugReq = createDebug("myapp:request")
|
|
170
|
-
|
|
171
|
-
// loggily - props inherited
|
|
172
|
-
const log = createLogger("myapp", { version: "1.0" })
|
|
173
|
-
const reqLog = log.logger("request", { requestId: "abc" })
|
|
174
|
-
// reqLog has both version and requestId
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Migration Checklist
|
|
178
|
-
|
|
179
|
-
### 1. Update Dependencies
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
# Remove debug
|
|
183
|
-
bun remove debug @types/debug
|
|
184
|
-
|
|
185
|
-
# Add loggily
|
|
186
|
-
bun add loggily
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### 2. Update Imports
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
// Before
|
|
193
|
-
import createDebug from "debug"
|
|
194
|
-
|
|
195
|
-
// After
|
|
196
|
-
import { createLogger } from "loggily"
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### 3. Replace Debug Instances
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
// Before
|
|
203
|
-
const debug = createDebug("myapp")
|
|
204
|
-
|
|
205
|
-
// After
|
|
206
|
-
const log = createLogger("myapp")
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### 4. Update Log Calls
|
|
210
|
-
|
|
211
|
-
| Pattern | Before | After |
|
|
212
|
-
| ----------- | ---------------------------- | -------------------------- |
|
|
213
|
-
| Simple | `debug('msg')` | `log.debug('msg')` |
|
|
214
|
-
| With values | `debug('msg %s', v)` | `log.debug(\`msg ${v}\`)` |
|
|
215
|
-
| Structured | `debug('data %o', d)` | `log.debug('data', { d })` |
|
|
216
|
-
| Error | `debug('err %s', e.message)` | `log.error(e)` |
|
|
217
|
-
|
|
218
|
-
### 5. Update Environment
|
|
219
|
-
|
|
220
|
-
```bash
|
|
221
|
-
# Before
|
|
222
|
-
DEBUG=myapp* node app.js
|
|
223
|
-
|
|
224
|
-
# After (DEBUG env var still works)
|
|
225
|
-
DEBUG=myapp node app.js
|
|
226
|
-
# Or set level globally without namespace filter
|
|
227
|
-
LOG_LEVEL=debug node app.js
|
|
228
|
-
# Or for spans
|
|
229
|
-
TRACE=1 LOG_LEVEL=debug node app.js
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### 6. Add Log Levels
|
|
233
|
-
|
|
234
|
-
Debug package has only on/off. Add appropriate levels:
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
// Choose appropriate level based on purpose
|
|
238
|
-
log.trace("...") // Very verbose, hot paths
|
|
239
|
-
log.debug("...") // Development debugging
|
|
240
|
-
log.info("...") // Normal operation
|
|
241
|
-
log.warn("...") // Recoverable issues
|
|
242
|
-
log.error("...") // Failures
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### 7. Convert Timing to Spans
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
// Before
|
|
249
|
-
const start = Date.now()
|
|
250
|
-
await operation()
|
|
251
|
-
debug("done in %dms", Date.now() - start)
|
|
252
|
-
|
|
253
|
-
// After
|
|
254
|
-
{
|
|
255
|
-
using span = log.span("operation")
|
|
256
|
-
await operation()
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### 8. Use Optional Chaining (Recommended)
|
|
261
|
-
|
|
262
|
-
`createLogger()` returns `undefined` for disabled levels -- just use `?.`:
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
const log = createLogger("myapp")
|
|
266
|
-
|
|
267
|
-
// Optional chaining skips argument evaluation when level is disabled
|
|
268
|
-
log.debug?.(`expensive: ${computeState()}`)
|
|
269
|
-
log.trace?.(() => `very expensive: ${JSON.stringify(bigObj)}`)
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Verification
|
|
273
|
-
|
|
274
|
-
After migration, verify:
|
|
275
|
-
|
|
276
|
-
1. **Development output works**: `LOG_LEVEL=debug bun run app`
|
|
277
|
-
2. **Production JSON works**: `NODE_ENV=production bun run app`
|
|
278
|
-
3. **Spans work**: `TRACE=1 bun run app`
|
|
279
|
-
4. **Level filtering works**: `LOG_LEVEL=warn bun run app` (should hide info/debug)
|
|
280
|
-
|
|
281
|
-
## Gotchas
|
|
282
|
-
|
|
283
|
-
### Namespace Filtering
|
|
284
|
-
|
|
285
|
-
loggily supports `DEBUG=myapp` for namespace filtering (like the `debug` package). It also supports negative patterns: `DEBUG=myapp,-myapp:noisy`. For span-specific namespace filtering, use `TRACE=myapp:db`.
|
|
286
|
-
|
|
287
|
-
### Printf Format Strings
|
|
288
|
-
|
|
289
|
-
debug uses printf-style `%s`, `%d`, `%o`. loggily uses template literals or structured data. Search for `%s`, `%d`, `%o`, `%j`, `%O` to find calls that need conversion.
|
|
290
|
-
|
|
291
|
-
### No Automatic Coloring by Namespace
|
|
292
|
-
|
|
293
|
-
debug auto-assigns colors to namespaces. loggily uses level-based colors. If you need namespace distinction, include it in the log output or use the `name` property.
|
|
294
|
-
|
|
295
|
-
### enabled Property
|
|
296
|
-
|
|
297
|
-
debug has `.enabled` property. loggily uses level comparison:
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
// debug
|
|
301
|
-
if (debug.enabled) { ... }
|
|
302
|
-
|
|
303
|
-
// loggily
|
|
304
|
-
import { getLogLevel } from 'loggily'
|
|
305
|
-
const LEVELS = { trace: 0, debug: 1, info: 2, warn: 3, error: 4, silent: 5 }
|
|
306
|
-
if (LEVELS.debug >= LEVELS[getLogLevel()]) { ... }
|
|
307
|
-
|
|
308
|
-
// Or use conditional logger with optional chaining (preferred)
|
|
309
|
-
log.debug?.('msg')
|
|
310
|
-
```
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
# Migration from Pino
|
|
2
|
-
|
|
3
|
-
Step-by-step guide for migrating from Pino to loggily.
|
|
4
|
-
|
|
5
|
-
## Why Migrate?
|
|
6
|
-
|
|
7
|
-
| Feature | Pino | loggily |
|
|
8
|
-
| ------------------------- | ---------------------- | ----------------------------- |
|
|
9
|
-
| Log levels | Yes (7 levels) | Yes (5 levels + silent) |
|
|
10
|
-
| Structured data | Yes (JSON) | Yes (JSON + pretty console) |
|
|
11
|
-
| Disabled call overhead | ~0.5ns (noop) | ~2.5ns (?. proxy) |
|
|
12
|
-
| Disabled + expensive args | 129ns (args evaluated) | **3.6ns (args skipped)** |
|
|
13
|
-
| Built-in spans/tracing | No | Yes (with `using` keyword) |
|
|
14
|
-
| Child loggers | Yes | Yes |
|
|
15
|
-
| Pretty print | Via pino-pretty | Built-in |
|
|
16
|
-
| Bundle size | ~14KB + transports | ~3KB |
|
|
17
|
-
| Browser support | Via pino/browser | Built-in (conditional export) |
|
|
18
|
-
|
|
19
|
-
## Quick Migration
|
|
20
|
-
|
|
21
|
-
### Before (Pino)
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import pino from "pino"
|
|
25
|
-
|
|
26
|
-
const logger = pino({ level: "info" })
|
|
27
|
-
const child = logger.child({ module: "db" })
|
|
28
|
-
|
|
29
|
-
logger.info({ port: 3000 }, "server started")
|
|
30
|
-
child.debug({ query: sql, params }, "executing query")
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### After (loggily)
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
import { createLogger } from "loggily"
|
|
37
|
-
|
|
38
|
-
const log = createLogger("myapp")
|
|
39
|
-
const dbLog = log.logger("db")
|
|
40
|
-
|
|
41
|
-
log.info?.("server started", { port: 3000 })
|
|
42
|
-
dbLog.debug?.("executing query", { query: sql, params })
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Pattern Mapping
|
|
46
|
-
|
|
47
|
-
### Logger Creation
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
// Pino
|
|
51
|
-
const logger = pino()
|
|
52
|
-
const logger = pino({ level: "debug" })
|
|
53
|
-
const logger = pino({ name: "myapp" })
|
|
54
|
-
|
|
55
|
-
// loggily
|
|
56
|
-
const log = createLogger("myapp")
|
|
57
|
-
setLogLevel("debug") // Global level
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Log Calls
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
// Pino — data object first, then message
|
|
64
|
-
logger.info({ userId: 42 }, "user logged in")
|
|
65
|
-
logger.info("simple message")
|
|
66
|
-
logger.error({ err }, "request failed")
|
|
67
|
-
logger.error(err, "request failed") // Error serialization
|
|
68
|
-
|
|
69
|
-
// loggily — message first, then data
|
|
70
|
-
log.info?.("user logged in", { userId: 42 })
|
|
71
|
-
log.info?.("simple message")
|
|
72
|
-
log.error?.(err, { context: "request" }) // Error object handled
|
|
73
|
-
log.error?.(err) // Extracts message, stack, code
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Child Loggers
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
// Pino
|
|
80
|
-
const child = logger.child({ requestId: "abc" })
|
|
81
|
-
child.info("handling request")
|
|
82
|
-
|
|
83
|
-
// loggily — two patterns
|
|
84
|
-
// 1. Context fields (like Pino's child)
|
|
85
|
-
const child = log.child({ requestId: "abc" })
|
|
86
|
-
child.info?.("handling request") // includes requestId
|
|
87
|
-
|
|
88
|
-
// 2. Namespace (extends the logger name)
|
|
89
|
-
const dbLog = log.logger("db") // name: "myapp:db"
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Levels
|
|
93
|
-
|
|
94
|
-
| Pino Level | Value | loggily Level |
|
|
95
|
-
| ---------- | ----: | ------------------------- |
|
|
96
|
-
| trace | 10 | trace |
|
|
97
|
-
| debug | 20 | debug |
|
|
98
|
-
| info | 30 | info |
|
|
99
|
-
| warn | 40 | warn |
|
|
100
|
-
| error | 50 | error |
|
|
101
|
-
| fatal | 60 | error (no separate fatal) |
|
|
102
|
-
| silent | ∞ | silent |
|
|
103
|
-
|
|
104
|
-
### Transports / Writers
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
// Pino transports
|
|
108
|
-
const logger = pino({
|
|
109
|
-
transport: {
|
|
110
|
-
target: "pino/file",
|
|
111
|
-
options: { destination: "/tmp/app.log" },
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// loggily writers
|
|
116
|
-
import { addWriter, createFileWriter } from "loggily"
|
|
117
|
-
|
|
118
|
-
const writer = createFileWriter("/tmp/app.log")
|
|
119
|
-
addWriter((formatted) => writer.write(formatted))
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Serializers
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
// Pino serializers
|
|
126
|
-
const logger = pino({
|
|
127
|
-
serializers: {
|
|
128
|
-
req: pino.stdSerializers.req,
|
|
129
|
-
err: pino.stdSerializers.err,
|
|
130
|
-
},
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// loggily — handle in data parameter
|
|
134
|
-
log.info?.("request", {
|
|
135
|
-
method: req.method,
|
|
136
|
-
url: req.url,
|
|
137
|
-
statusCode: res.statusCode,
|
|
138
|
-
})
|
|
139
|
-
log.error?.(err) // Built-in Error serialization
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Timing
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
// Pino (manual)
|
|
146
|
-
const start = Date.now()
|
|
147
|
-
await operation()
|
|
148
|
-
logger.info({ duration: Date.now() - start }, "operation complete")
|
|
149
|
-
|
|
150
|
-
// loggily (built-in spans)
|
|
151
|
-
{
|
|
152
|
-
using span = log.span("operation")
|
|
153
|
-
await operation()
|
|
154
|
-
span.spanData.rowCount = 500
|
|
155
|
-
}
|
|
156
|
-
// Automatic: SPAN myapp:operation (234ms) {rowCount: 500}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Environment Variables
|
|
160
|
-
|
|
161
|
-
| Pino | loggily | Effect |
|
|
162
|
-
| --------------------- | --------------------- | ------------------------------------- |
|
|
163
|
-
| `LOG_LEVEL=debug` | `LOG_LEVEL=debug` | Set minimum level |
|
|
164
|
-
| N/A | `DEBUG=myapp` | Namespace filter (auto-enables debug) |
|
|
165
|
-
| N/A | `TRACE=1` | Enable span output |
|
|
166
|
-
| N/A | `LOG_FORMAT=json` | Force JSON output |
|
|
167
|
-
| `NODE_ENV=production` | `NODE_ENV=production` | Auto-enable JSON |
|
|
168
|
-
|
|
169
|
-
## Migration Checklist
|
|
170
|
-
|
|
171
|
-
1. **Update dependencies**: `bun remove pino pino-pretty && bun add loggily`
|
|
172
|
-
2. **Update imports**: `import pino from "pino"` → `import { createLogger } from "loggily"`
|
|
173
|
-
3. **Swap argument order**: Pino uses `(data, message)`, loggily uses `(message, data)`
|
|
174
|
-
4. **Replace `logger.child()`** with `.child()` (context) or `.logger()` (namespace)
|
|
175
|
-
5. **Convert transports** to writers via `addWriter()`
|
|
176
|
-
6. **Add `?.`** to all log calls for zero-overhead disabled logging
|
|
177
|
-
7. **Convert manual timing** to spans with `using`
|
|
178
|
-
8. **Replace `fatal`** with `error` (add a custom label in data if needed)
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
# Migration from Winston
|
|
2
|
-
|
|
3
|
-
Step-by-step guide for migrating from Winston to loggily.
|
|
4
|
-
|
|
5
|
-
## Why Migrate?
|
|
6
|
-
|
|
7
|
-
| Feature | Winston | loggily |
|
|
8
|
-
| ------------------------- | ----------------------- | ----------------------------- |
|
|
9
|
-
| Log levels | Customizable | 5 fixed levels + silent |
|
|
10
|
-
| Structured data | Yes (metadata) | Yes (data parameter) |
|
|
11
|
-
| Disabled call overhead | ~372ns | **~2.5ns** (?. pattern) |
|
|
12
|
-
| Disabled + expensive args | ~741ns (args evaluated) | **~3.6ns (args skipped)** |
|
|
13
|
-
| Built-in spans/tracing | No | Yes (with `using` keyword) |
|
|
14
|
-
| Transports | Rich ecosystem | Writers + file writer |
|
|
15
|
-
| Pretty print | Via formats | Built-in |
|
|
16
|
-
| Bundle size | ~60KB + transports | ~3KB |
|
|
17
|
-
| Browser support | Via browser transport | Built-in (conditional export) |
|
|
18
|
-
|
|
19
|
-
## Quick Migration
|
|
20
|
-
|
|
21
|
-
### Before (Winston)
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import winston from "winston"
|
|
25
|
-
|
|
26
|
-
const logger = winston.createLogger({
|
|
27
|
-
level: "info",
|
|
28
|
-
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
|
|
29
|
-
transports: [new winston.transports.Console()],
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
logger.info("server started", { port: 3000 })
|
|
33
|
-
logger.error("request failed", { error: err.message })
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### After (loggily)
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
import { createLogger } from "loggily"
|
|
40
|
-
|
|
41
|
-
const log = createLogger("myapp")
|
|
42
|
-
|
|
43
|
-
log.info?.("server started", { port: 3000 })
|
|
44
|
-
log.error?.(err) // Automatic Error handling
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Pattern Mapping
|
|
48
|
-
|
|
49
|
-
### Logger Creation
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
// Winston
|
|
53
|
-
const logger = winston.createLogger({
|
|
54
|
-
level: "info",
|
|
55
|
-
format: winston.format.json(),
|
|
56
|
-
transports: [new winston.transports.Console()],
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// loggily
|
|
60
|
-
const log = createLogger("myapp")
|
|
61
|
-
// Level, format, and output configured via env vars or API:
|
|
62
|
-
// LOG_LEVEL=info, LOG_FORMAT=json, NODE_ENV=production
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Log Calls
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
// Winston — message first, metadata spread or second arg
|
|
69
|
-
logger.info("starting", { port: 3000 })
|
|
70
|
-
logger.info({ message: "starting", port: 3000 })
|
|
71
|
-
logger.error("failed", { error: err.message, stack: err.stack })
|
|
72
|
-
|
|
73
|
-
// loggily — message + optional data
|
|
74
|
-
log.info?.("starting", { port: 3000 })
|
|
75
|
-
log.error?.(err) // Error: auto-extracts message, stack, code
|
|
76
|
-
log.error?.(err, { context: "startup" }) // With extra context
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Levels
|
|
80
|
-
|
|
81
|
-
| Winston Level | loggily Level |
|
|
82
|
-
| ------------- | ----------------------- |
|
|
83
|
-
| error | error |
|
|
84
|
-
| warn | warn |
|
|
85
|
-
| info | info |
|
|
86
|
-
| http | info (no separate http) |
|
|
87
|
-
| verbose | debug |
|
|
88
|
-
| debug | debug |
|
|
89
|
-
| silly | trace |
|
|
90
|
-
|
|
91
|
-
### Child Loggers
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
// Winston — child loggers via defaultMeta
|
|
95
|
-
const childLogger = logger.child({ requestId: "abc" })
|
|
96
|
-
childLogger.info("processing")
|
|
97
|
-
|
|
98
|
-
// loggily — two patterns
|
|
99
|
-
const child = log.child({ requestId: "abc" }) // Context fields
|
|
100
|
-
const dbLog = log.logger("db") // Namespace: myapp:db
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Transports / Writers
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
// Winston transports
|
|
107
|
-
const logger = winston.createLogger({
|
|
108
|
-
transports: [new winston.transports.Console(), new winston.transports.File({ filename: "app.log" })],
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
// loggily writers
|
|
112
|
-
import { addWriter, createFileWriter } from "loggily"
|
|
113
|
-
|
|
114
|
-
// Console output is built-in (default)
|
|
115
|
-
// File output via createFileWriter
|
|
116
|
-
const writer = createFileWriter("/tmp/app.log")
|
|
117
|
-
const unsub = addWriter((formatted) => writer.write(formatted))
|
|
118
|
-
|
|
119
|
-
// Custom writer (e.g., send to external service)
|
|
120
|
-
addWriter((formatted, level) => {
|
|
121
|
-
if (level === "error") sendToAlertService(formatted)
|
|
122
|
-
})
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Formats
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
// Winston — format combinators
|
|
129
|
-
const logger = winston.createLogger({
|
|
130
|
-
format: winston.format.combine(
|
|
131
|
-
winston.format.timestamp(),
|
|
132
|
-
winston.format.colorize(),
|
|
133
|
-
winston.format.printf(({ timestamp, level, message }) => `${timestamp} ${level}: ${message}`),
|
|
134
|
-
),
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
// loggily — built-in formats
|
|
138
|
-
// Development: colorized console with timestamp (default)
|
|
139
|
-
// Production: JSON (NODE_ENV=production or LOG_FORMAT=json)
|
|
140
|
-
// No configuration needed
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Timing
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
// Winston (manual profiling)
|
|
147
|
-
logger.profile("operation")
|
|
148
|
-
await doWork()
|
|
149
|
-
logger.profile("operation") // logs duration
|
|
150
|
-
|
|
151
|
-
// loggily (built-in spans)
|
|
152
|
-
{
|
|
153
|
-
using span = log.span("operation")
|
|
154
|
-
await doWork()
|
|
155
|
-
}
|
|
156
|
-
// Automatic: SPAN myapp:operation (234ms)
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Environment Variables
|
|
160
|
-
|
|
161
|
-
| Winston | loggily | Effect |
|
|
162
|
-
| ------------------------ | --------------------- | ------------------ |
|
|
163
|
-
| N/A (configured in code) | `LOG_LEVEL=debug` | Set minimum level |
|
|
164
|
-
| N/A | `DEBUG=myapp` | Namespace filter |
|
|
165
|
-
| N/A | `TRACE=1` | Enable span output |
|
|
166
|
-
| N/A | `LOG_FORMAT=json` | Force JSON output |
|
|
167
|
-
| `NODE_ENV=production` | `NODE_ENV=production` | Auto-enable JSON |
|
|
168
|
-
|
|
169
|
-
## Migration Checklist
|
|
170
|
-
|
|
171
|
-
1. **Update dependencies**: `bun remove winston` and `bun add loggily`
|
|
172
|
-
2. **Update imports**: `import winston from "winston"` → `import { createLogger } from "loggily"`
|
|
173
|
-
3. **Replace `createLogger()`**: Winston's options → `createLogger("name")` + env vars
|
|
174
|
-
4. **Convert transports** to `addWriter()` + optional `createFileWriter()`
|
|
175
|
-
5. **Remove format configuration** — built-in formats handle dev/prod automatically
|
|
176
|
-
6. **Add `?.`** to all log calls for zero-overhead disabled logging
|
|
177
|
-
7. **Map custom levels**: http→info, verbose→debug, silly→trace
|
|
178
|
-
8. **Convert `logger.profile()`** to spans with `using`
|
|
179
|
-
9. **Replace `logger.child()`** with `.child()` (context) or `.logger()` (namespace)
|