logroller 1.0.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/LICENSE +5 -0
- package/README.md +147 -0
- package/dist/index.cjs +875 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.esm.js +872 -0
- package/package.json +59 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# logroller
|
|
2
|
+
|
|
3
|
+
Zero-dependency rotating file stream for Node.js. Daily or interval rotation,
|
|
4
|
+
size limits, gzip archives, retention policies, timezone-aware naming and a
|
|
5
|
+
crash-safe resume — in one small Writable stream you can `pipe()` into or hand
|
|
6
|
+
to pino.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install logroller
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
### ESM
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
import { createStream } from "logroller";
|
|
18
|
+
|
|
19
|
+
const log = createStream({
|
|
20
|
+
filename: "logs/app-%DATE%.log",
|
|
21
|
+
datePattern: "YYYY-MM-DD",
|
|
22
|
+
zippedArchive: true,
|
|
23
|
+
maxSize: "20m",
|
|
24
|
+
maxFiles: "90d",
|
|
25
|
+
tz: "UTC",
|
|
26
|
+
frequency: "daily",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
log.write("hello\n");
|
|
30
|
+
log.on("rotated", (r) => console.log("rotated:", r));
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### CommonJS
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
const { createStream } = require("logroller");
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Pipe anything into it
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
source.pipe(createStream({ filename: "logs/data-%DATE%.log" }));
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### With pino
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import pino from "pino";
|
|
49
|
+
import { createStream } from "logroller";
|
|
50
|
+
|
|
51
|
+
const stream = createStream({
|
|
52
|
+
filename: "logs/general-%DATE%.log",
|
|
53
|
+
zippedArchive: true,
|
|
54
|
+
maxSize: "20m",
|
|
55
|
+
maxFiles: "90d",
|
|
56
|
+
tz: "Asia/Kolkata",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const logger = pino(pino.multistream([
|
|
60
|
+
{ level: "info", stream: pino.transport({ target: "./pretty.js" }) },
|
|
61
|
+
{ level: "info", stream },
|
|
62
|
+
]));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Options
|
|
66
|
+
|
|
67
|
+
| Option | Values | Default |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `filename` | must contain `%DATE%` | required |
|
|
70
|
+
| `datePattern` | `YYYY YY MM DD HH mm ss` | `YYYY-MM-DD` |
|
|
71
|
+
| `zippedArchive` | boolean | `false` |
|
|
72
|
+
| `maxSize` | `20m`, `1k`, `5g`, number of bytes, `0` = off | off |
|
|
73
|
+
| `maxFiles` | `"90d"` (age), `500` (count), unset = never delete | off |
|
|
74
|
+
| `frequency` | `"daily"`, `"1s"`, `"5m"`, `"2h"`, ms number | `"daily"` |
|
|
75
|
+
| `tz` | any IANA zone (`Intl`-based) | `"UTC"` |
|
|
76
|
+
| `audit` | write `<stem>_audit.json` manifest | `true` |
|
|
77
|
+
| `auditFile` | custom manifest name | `<stem>_audit.json` |
|
|
78
|
+
| `unrefTimers` | don't hold the process open | `false` |
|
|
79
|
+
| `addHours` | static clock shift (`"-6h"`) — **test only** | off |
|
|
80
|
+
| `addHoursEveryMin` | hours added per step (`"24h"`) — **test only** | off |
|
|
81
|
+
| `clockStepIntervalMs` | step interval for `addHoursEveryMin` | `60000` |
|
|
82
|
+
|
|
83
|
+
## File naming
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
app-2026-08-27.log ← active
|
|
87
|
+
app-2026-08-27.log.gz ← hit maxSize → gzipped
|
|
88
|
+
app-2026-08-27.1.log ← next segment, writing…
|
|
89
|
+
app-2026-08-27.1.log.gz ← that one sealed too
|
|
90
|
+
app-2026-08-28.log ← new day (in tz), fresh series
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Restart behaviour
|
|
94
|
+
|
|
95
|
+
| Disk at crash | Resumes into |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `app-D.log` | `app-D.log` (append) |
|
|
98
|
+
| `app-D.log.gz` + `app-D.1.log` | `app-D.1.log` (append) |
|
|
99
|
+
| `app-D.1.log.gz` only | `app-D.2.log` |
|
|
100
|
+
| crossed midnight while down | new day base file on first write |
|
|
101
|
+
| killed mid-gzip | boot finishes the interrupted gzip |
|
|
102
|
+
|
|
103
|
+
## Events
|
|
104
|
+
|
|
105
|
+
| Event | Payload |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `open` | `(file: string)` |
|
|
108
|
+
| `rotated` | `({ reason, oldFile, archive, newFile })` |
|
|
109
|
+
| `archive` | `(gzFile: string)` |
|
|
110
|
+
| `deleted` | `(file: string)` — retention |
|
|
111
|
+
| `period` | `(stamp: string)` — new period, nothing to archive |
|
|
112
|
+
| `clock` | `({ addHours, addHoursEveryMin, offsetMs })` — test clock active |
|
|
113
|
+
| `warn` | `(err: Error)` — non-fatal (gzip failure, concurrent writer, …) |
|
|
114
|
+
|
|
115
|
+
Always attach an `error` handler — this is a real Writable stream.
|
|
116
|
+
|
|
117
|
+
## Audit manifest
|
|
118
|
+
|
|
119
|
+
Each stream family keeps a `*_audit.json` beside the logs (library-owned —
|
|
120
|
+
treat it as read-only). It records every file's lifecycle with a capped,
|
|
121
|
+
uuid-tagged event journal, restores the series index across restarts, repairs
|
|
122
|
+
gzip interrupted by a crash, and demotes records left behind by dead
|
|
123
|
+
processes. Writes are atomic (tmp + rename); a corrupt/foreign file is
|
|
124
|
+
quarantined as `*.corrupt` and logging continues via disk scan.
|
|
125
|
+
|
|
126
|
+
## Testing rotation without waiting
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
const s = createStream({
|
|
130
|
+
filename: "logs/test-%DATE%.log",
|
|
131
|
+
zippedArchive: true,
|
|
132
|
+
addHoursEveryMin: "24h", // a day passes every minute
|
|
133
|
+
clockStepIntervalMs: 1000, // optional: step every second instead
|
|
134
|
+
tz: "UTC",
|
|
135
|
+
});
|
|
136
|
+
await s.advanceClock(); // or trigger one step manually
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Retention
|
|
140
|
+
|
|
141
|
+
- `maxFiles: "90d"` — delete family files older than 90 days (mtime)
|
|
142
|
+
- `maxFiles: 500` — keep newest 500 archives
|
|
143
|
+
- unset — never auto-delete; remove manually
|
|
144
|
+
|
|
145
|
+
## License
|
|
146
|
+
|
|
147
|
+
MIT
|