Skip to content

Commit 557a9a9

Browse files
authored
Merge pull request #18 from chaqchase/custom-logger-support
Custom logger support release
2 parents 6608734 + 9e3fa9f commit 557a9a9

File tree

8 files changed

+216
-29
lines changed

8 files changed

+216
-29
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# cronbake
22

3+
## 0.4.0
4+
5+
### Features
6+
7+
- **Custom Logger Support**: Add pluggable logger interface allowing integration with any logging library (pino, winston, bunyan, logtape, etc.)
8+
- New `Logger` interface exported from package API
9+
- Pass `logger` option to `Baker.create()` to set a global logger for all jobs
10+
- Override logger per job via `logger` option in `baker.add()` or `Cron.create()`
11+
- Default behavior unchanged (falls back to `console`)
12+
- Thanks to [@nemvince](https://github.com/nemvince) for the work in [PR #17](https://github.com/chaqchase/cronbake/pull/17)
13+
14+
### Examples
15+
16+
- Added `examples/logging.ts` demonstrating custom logger usage with colored output, global logger, per-job overrides, and error logging
17+
18+
### Documentation
19+
20+
- Updated README with comprehensive custom logger documentation and examples
21+
322
## 0.3.2
423

524
### Fixes

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,14 +332,41 @@ await baker.restoreState();
332332
You can provide a custom logger that implements the `Logger` interface to log messages from Cronbake:
333333

334334
```typescript
335+
import { Baker, Logger } from 'cronbake';
336+
337+
// Using a logging library like logtape
335338
import { getLogger } from '@logtape/logtape';
336-
import { Baker, FilePersistenceProvider } from 'cronbake';
337339

338-
const logger = getLogger(['mirar', 'cron']);
340+
const logger = getLogger(['myapp', 'cron']);
339341

340342
export const baker = Baker.create({
341343
logger
342344
});
345+
346+
// Or create a custom logger
347+
const customLogger: Logger = {
348+
info: (msg, ...args) => console.log(`[INFO] ${msg}`, ...args),
349+
warn: (msg, ...args) => console.warn(`[WARN] ${msg}`, ...args),
350+
error: (msg, ...args) => console.error(`[ERROR] ${msg}`, ...args),
351+
debug: (msg, ...args) => console.debug(`[DEBUG] ${msg}`, ...args),
352+
};
353+
354+
export const bakerWithCustomLogger = Baker.create({
355+
logger: customLogger
356+
});
357+
```
358+
359+
You can also override the logger per job:
360+
361+
```typescript
362+
const baker = Baker.create({ logger: defaultLogger });
363+
364+
baker.add({
365+
name: 'special-job',
366+
cron: '@daily',
367+
logger: specialLogger, // This job uses a different logger
368+
callback: () => console.log('Hello!'),
369+
});
343370
```
344371

345372
#### Persistence Providers (File and Redis)

examples/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,17 @@ bun run examples/persistence.ts
2626

2727
The script writes state to `./.cronbake-state.json`, demonstrating `persist: true` vs. `persist: false` jobs and `await baker.ready()`.
2828

29+
## Run the logging example
30+
31+
```bash
32+
bun run examples/logging.ts
33+
```
34+
35+
This demonstrates custom logger support:
36+
37+
- Creating a custom logger with colored output
38+
- Using a global logger for all jobs via Baker
39+
- Overriding the logger per job
40+
- Error logging when jobs fail
41+
2942
Feel free to copy these files or adapt them into your own app bootstrap logic.

examples/logging.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import Baker, { Logger } from "../lib/index";
2+
3+
/**
4+
* Custom logger with colored output and timestamps.
5+
* You can replace this with any logger that implements the Logger interface,
6+
* such as pino, winston, bunyan, or logtape.
7+
*/
8+
const createColoredLogger = (prefix: string): Logger => {
9+
const colors = {
10+
reset: "\x1b[0m",
11+
dim: "\x1b[2m",
12+
blue: "\x1b[34m",
13+
yellow: "\x1b[33m",
14+
red: "\x1b[31m",
15+
cyan: "\x1b[36m",
16+
};
17+
18+
const timestamp = () => new Date().toISOString();
19+
20+
return {
21+
info: (message, ...args) => {
22+
console.log(
23+
`${colors.dim}${timestamp()}${colors.reset} ${colors.blue}[INFO]${
24+
colors.reset
25+
} ${colors.cyan}[${prefix}]${colors.reset}`,
26+
message,
27+
...args
28+
);
29+
},
30+
warn: (message, ...args) => {
31+
console.warn(
32+
`${colors.dim}${timestamp()}${colors.reset} ${colors.yellow}[WARN]${
33+
colors.reset
34+
} ${colors.cyan}[${prefix}]${colors.reset}`,
35+
message,
36+
...args
37+
);
38+
},
39+
error: (message, ...args) => {
40+
console.error(
41+
`${colors.dim}${timestamp()}${colors.reset} ${colors.red}[ERROR]${
42+
colors.reset
43+
} ${colors.cyan}[${prefix}]${colors.reset}`,
44+
message,
45+
...args
46+
);
47+
},
48+
debug: (message, ...args) => {
49+
console.debug(
50+
`${colors.dim}${timestamp()}${colors.reset} ${colors.dim}[DEBUG]${
51+
colors.reset
52+
} ${colors.cyan}[${prefix}]${colors.reset}`,
53+
message,
54+
...args
55+
);
56+
},
57+
};
58+
};
59+
60+
async function main() {
61+
// Create a custom logger for the Baker instance
62+
const bakerLogger = createColoredLogger("cronbake");
63+
64+
const baker = Baker.create({
65+
autoStart: true,
66+
logger: bakerLogger,
67+
});
68+
69+
// This job uses the Baker's logger (bakerLogger)
70+
baker.add({
71+
name: "heartbeat",
72+
cron: "@every_5_seconds",
73+
immediate: true,
74+
callback: () => {
75+
console.log("💓 Heartbeat job executed successfully");
76+
},
77+
});
78+
79+
// This job has its own dedicated logger
80+
const paymentLogger = createColoredLogger("payments");
81+
baker.add({
82+
name: "process-payments",
83+
cron: "@every_10_seconds",
84+
logger: paymentLogger, // Override with job-specific logger
85+
immediate: true,
86+
callback: () => {
87+
console.log("💰 Processing payments...");
88+
},
89+
});
90+
91+
// This job will fail, demonstrating error logging
92+
baker.add({
93+
name: "flaky-job",
94+
cron: "@every_15_seconds",
95+
immediate: true,
96+
delay: "2s",
97+
callback: () => {
98+
// Simulate a random failure
99+
if (Math.random() > 0.5) {
100+
throw new Error("Random failure occurred!");
101+
}
102+
console.log("🎲 Flaky job succeeded this time!");
103+
},
104+
});
105+
106+
console.log("\n🚀 Logging example started!");
107+
console.log(" - heartbeat: runs every 5 seconds (uses Baker logger)");
108+
console.log(
109+
" - process-payments: runs every 10 seconds (uses custom payments logger)"
110+
);
111+
console.log(
112+
" - flaky-job: runs every 15 seconds, fails randomly to demo error logging"
113+
);
114+
console.log("\nPress Ctrl+C to stop.\n");
115+
116+
const shutdown = () => {
117+
console.log("\n👋 Stopping all jobs...");
118+
baker.destroyAll();
119+
process.exit(0);
120+
};
121+
122+
process.once("SIGINT", shutdown);
123+
process.once("SIGTERM", shutdown);
124+
}
125+
126+
main().catch((error) => {
127+
console.error("Logging example failed:", error);
128+
process.exit(1);
129+
});

index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export {
1717
type OnDayStrType,
1818
type day,
1919
type unit,
20+
type Logger,
2021
} from "./lib";
2122

2223
export { Cron, Baker, CronParser } from "./lib";

lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export {
2121
type OnDayStrType,
2222
type day,
2323
type unit,
24+
type Logger,
2425
} from "./types";
2526

2627
export { Cron, Baker, CronParser, FilePersistenceProvider, RedisPersistenceProvider };

lib/types.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,36 +42,36 @@ interface ICronParser {
4242
}
4343

4444
type unit =
45-
| 'seconds'
46-
| 'minutes'
47-
| 'hours'
48-
| 'dayOfMonth'
49-
| 'months'
50-
| 'dayOfWeek';
45+
| "seconds"
46+
| "minutes"
47+
| "hours"
48+
| "dayOfMonth"
49+
| "months"
50+
| "dayOfWeek";
5151

5252
type day =
53-
| 'sunday'
54-
| 'monday'
55-
| 'tuesday'
56-
| 'wednesday'
57-
| 'thursday'
58-
| 'friday'
59-
| 'saturday';
53+
| "sunday"
54+
| "monday"
55+
| "tuesday"
56+
| "wednesday"
57+
| "thursday"
58+
| "friday"
59+
| "saturday";
6060

6161
type EveryStrType<U extends unit = unit> = `@every_${string}_${U}`;
6262
type AtHourStrType = `@at_${number}:${number}`;
6363
type OnDayStrType<D extends day = day> = `@on_${D}`;
6464
type BetweenStrType = `@between_${number}_${number}`;
6565

6666
type CronExprs =
67-
| '@every_second'
68-
| '@every_minute'
69-
| '@yearly'
70-
| '@annually'
71-
| '@monthly'
72-
| '@weekly'
73-
| '@daily'
74-
| '@hourly'
67+
| "@every_second"
68+
| "@every_minute"
69+
| "@yearly"
70+
| "@annually"
71+
| "@monthly"
72+
| "@weekly"
73+
| "@daily"
74+
| "@hourly"
7575
| EveryStrType
7676
| AtHourStrType
7777
| OnDayStrType
@@ -275,9 +275,6 @@ type CronOptions<T extends string = string> = {
275275
* Defaults to true for safety.
276276
*/
277277
overrunProtection?: boolean;
278-
/**
279-
* If true, run the first callback immediately on start (before schedule)
280-
*/
281278
/**
282279
* If true, run the first callback immediately on start (before schedule)
283280
*/
@@ -293,7 +290,7 @@ type CronOptions<T extends string = string> = {
293290
delay?: number | string;
294291
};
295292

296-
type Status = 'running' | 'stopped' | 'paused' | 'error';
293+
type Status = "running" | "stopped" | "paused" | "error";
297294

298295
/**
299296
* Execution history entry for a cron job
@@ -323,7 +320,7 @@ type JobMetrics = {
323320
*/
324321
import type { PersistenceProvider } from "./persistence/types";
325322

326-
type PersistenceStrategy = 'file' | 'redis' | 'custom';
323+
type PersistenceStrategy = "file" | "redis" | "custom";
327324

328325
type RedisPersistenceOptions = {
329326
key?: string;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "cronbake",
33
"description": "A powerful and flexible cron job manager built with TypeScript",
44
"module": "dist/index.js",
5-
"version": "0.3.2",
5+
"version": "0.4.0",
66
"publishConfig": {
77
"access": "public"
88
},

0 commit comments

Comments
 (0)