hazo_logs 1.1.0 → 2.0.1
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 +198 -4
- package/config/hazo_logs_config.ini.sample +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/alert-triggers.d.ts +54 -0
- package/dist/lib/alert-triggers.d.ts.map +1 -0
- package/dist/lib/alert-triggers.js +96 -0
- package/dist/lib/alert-triggers.js.map +1 -0
- package/dist/lib/config_loader.d.ts.map +1 -1
- package/dist/lib/config_loader.js +1 -7
- package/dist/lib/config_loader.js.map +1 -1
- package/dist/lib/console-logger.d.ts +17 -1
- package/dist/lib/console-logger.d.ts.map +1 -1
- package/dist/lib/console-logger.js +47 -4
- package/dist/lib/console-logger.js.map +1 -1
- package/dist/lib/context/log-context.d.ts.map +1 -1
- package/dist/lib/context/log-context.js +4 -0
- package/dist/lib/context/log-context.js.map +1 -1
- package/dist/lib/eslint_plugin/index.d.ts +109 -0
- package/dist/lib/eslint_plugin/index.d.ts.map +1 -0
- package/dist/lib/eslint_plugin/index.js +168 -0
- package/dist/lib/eslint_plugin/index.js.map +1 -0
- package/dist/lib/global-error-handlers.d.ts +23 -0
- package/dist/lib/global-error-handlers.d.ts.map +1 -0
- package/dist/lib/global-error-handlers.js +46 -0
- package/dist/lib/global-error-handlers.js.map +1 -0
- package/dist/lib/hazo_logger.d.ts +9 -0
- package/dist/lib/hazo_logger.d.ts.map +1 -1
- package/dist/lib/hazo_logger.js +32 -0
- package/dist/lib/hazo_logger.js.map +1 -1
- package/dist/lib/level_resolver.d.ts +26 -0
- package/dist/lib/level_resolver.d.ts.map +1 -0
- package/dist/lib/level_resolver.js +65 -0
- package/dist/lib/level_resolver.js.map +1 -0
- package/dist/lib/log-reader.d.ts.map +1 -1
- package/dist/lib/log-reader.js +6 -4
- package/dist/lib/log-reader.js.map +1 -1
- package/dist/lib/package_logger.d.ts +47 -3
- package/dist/lib/package_logger.d.ts.map +1 -1
- package/dist/lib/package_logger.js +196 -10
- package/dist/lib/package_logger.js.map +1 -1
- package/dist/lib/ring_buffer.d.ts +51 -0
- package/dist/lib/ring_buffer.d.ts.map +1 -0
- package/dist/lib/ring_buffer.js +107 -0
- package/dist/lib/ring_buffer.js.map +1 -0
- package/dist/lib/types.d.ts +57 -24
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/universal-logger.d.ts.map +1 -1
- package/dist/lib/universal-logger.js +18 -0
- package/dist/lib/universal-logger.js.map +1 -1
- package/dist/lib/utils/caller_info.d.ts +25 -1
- package/dist/lib/utils/caller_info.d.ts.map +1 -1
- package/dist/lib/utils/caller_info.js +62 -1
- package/dist/lib/utils/caller_info.js.map +1 -1
- package/dist/lib/with-error-handler.d.ts +19 -0
- package/dist/lib/with-error-handler.d.ts.map +1 -0
- package/dist/lib/with-error-handler.js +77 -0
- package/dist/lib/with-error-handler.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -0
- package/dist/server.js.map +1 -1
- package/dist/ui/components/ErrorBoundary.d.ts +44 -0
- package/dist/ui/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/ui/components/ErrorBoundary.js +57 -0
- package/dist/ui/components/ErrorBoundary.js.map +1 -0
- package/dist/ui/components/LogLevelBadge.d.ts.map +1 -1
- package/dist/ui/components/LogLevelBadge.js +1 -0
- package/dist/ui/components/LogLevelBadge.js.map +1 -1
- package/dist/ui/hooks/useErrorReporter.d.ts +16 -0
- package/dist/ui/hooks/useErrorReporter.d.ts.map +1 -0
- package/dist/ui/hooks/useErrorReporter.js +56 -0
- package/dist/ui/hooks/useErrorReporter.js.map +1 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +3 -0
- package/dist/ui/index.js.map +1 -1
- package/package.json +19 -7
package/README.md
CHANGED
|
@@ -5,12 +5,88 @@ A Winston-based logging library for Node.js/Next.js applications with a built-in
|
|
|
5
5
|
[](https://www.npmjs.com/package/hazo_logs)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
+
## Log Level Convention
|
|
9
|
+
|
|
10
|
+
hazo_logs uses a 5-level system (from design spec D-015). Each level has a defined purpose — use the narrowest one that fits.
|
|
11
|
+
|
|
12
|
+
| Level | When to use |
|
|
13
|
+
|-------|-------------|
|
|
14
|
+
| `TRACE` | High-frequency operational noise: polling ticks, cache hits, ping responses. Off in production. |
|
|
15
|
+
| `DEBUG` | Operational detail useful when actively debugging a problem. Off in production. |
|
|
16
|
+
| `INFO` | State changes and user-facing events (login, job started, order placed). Default level in dev. |
|
|
17
|
+
| `WARN` | Recoverable problems: rate-limited, retrying, degraded-mode fallback. Default level in production. |
|
|
18
|
+
| `ERROR` | Unrecovered failures that require attention: unhandled exception, data loss, external service down. |
|
|
19
|
+
|
|
20
|
+
### Default levels
|
|
21
|
+
|
|
22
|
+
| Environment | Default level |
|
|
23
|
+
|-------------|--------------|
|
|
24
|
+
| `development` / `test` (`NODE_ENV`) | `info` |
|
|
25
|
+
| `production` / `staging` (`HAZO_ENV` or `NODE_ENV`) | `warn` |
|
|
26
|
+
|
|
27
|
+
The resolver checks `HAZO_ENV` first, then `NODE_ENV`, then falls back to `development`.
|
|
28
|
+
|
|
29
|
+
### Per-namespace overrides (INI config)
|
|
30
|
+
|
|
31
|
+
Fine-tune the level for a specific package or sub-namespace in `config/hazo_logs_config.ini`:
|
|
32
|
+
|
|
33
|
+
```ini
|
|
34
|
+
[log.overrides]
|
|
35
|
+
; Package-level — matches hazo_chat and any hazo_chat/* sub-namespace
|
|
36
|
+
hazo_chat = warn
|
|
37
|
+
|
|
38
|
+
; Sub-namespace — more specific, takes precedence over the package-level override
|
|
39
|
+
hazo_chat/poll = error
|
|
40
|
+
|
|
41
|
+
; Prefix match — matches any hazo_files/* sub-namespace
|
|
42
|
+
hazo_files/ = debug
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Precedence (highest wins): exact match > prefix match > package-level > global default.
|
|
46
|
+
|
|
47
|
+
You can also use environment variables to override INI config at runtime:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
HAZO_LOGS_LOG_OVERRIDES_hazo_files=debug node server.js
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Smart logging helpers
|
|
54
|
+
|
|
55
|
+
Use these instead of raw `log.info` loops to reduce noise without losing signal:
|
|
56
|
+
|
|
57
|
+
**`log.heartbeat(name, { status, ...fields }, opts?)`**
|
|
58
|
+
Emits only on state change. Silent on repeated same-status calls. Use for "is it still working?" checks on polled resources (DB connectivity, external API, queue depth).
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Emits once when connected, once on disconnect, once when it reconnects
|
|
62
|
+
log.heartbeat('db.primary', { status: connected ? 'ok' : 'down', latencyMs });
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**`log.sampled(level, msg, fields?, { sample })`**
|
|
66
|
+
Emits with the given probability. Default sample rate is 0.1 (10%). Use for high-frequency paths where you want occasional visibility without flooding logs.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Logs roughly 1 in 10 cache hits
|
|
70
|
+
log.sampled('debug', 'cache.hit', { key }, { sample: 0.1 });
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**`log.dedupe(level, msg, fields?, { window, key? })`**
|
|
74
|
+
Collapses identical-keyed messages within a time window. The first occurrence emits immediately; at window end, if more than one occurred, emits a summary `"msg (×N over Xs)"`. Use when the same warning fires rapidly (e.g. validation errors on bulk import).
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// First occurrence emits; subsequent in the same minute are collapsed
|
|
78
|
+
log.dedupe('warn', 'validation.failed', { field }, { window: '1m' });
|
|
79
|
+
```
|
|
80
|
+
|
|
8
81
|
## Features
|
|
9
82
|
|
|
10
83
|
- **Structured Logging**: Winston wrapper with singleton pattern for consistent logging across your app
|
|
11
84
|
- **Package Tagging**: Automatically tag logs by package/module name
|
|
12
85
|
- **Daily Rotation**: Automatic log file rotation with configurable retention
|
|
13
86
|
- **Session Tracking**: Track logs across async operations with sessionId and reference
|
|
87
|
+
- **Fatal Level**: `logger.fatal()` for process-critical events, above `error` in severity
|
|
88
|
+
- **Context Fields**: Attach `scope` (dotted operation path) and `userId` to all logs via ALS context
|
|
89
|
+
- **Error Handling Surface**: `withErrorHandler`, `installGlobalErrorHandlers`, `registerAlertTrigger`, `<ErrorBoundary />`, `useErrorReporter` — structured error capture with correlationId tracking
|
|
14
90
|
- **Built-in UI**: React-based log viewer with filtering, sorting, and pagination
|
|
15
91
|
- **Zero Config**: Works out of the box with sensible defaults
|
|
16
92
|
- **Minimal Integration**: Add log viewer to your app with just 2 files (~6 lines of code)
|
|
@@ -249,22 +325,27 @@ import { createLogger, runWithLogContext } from 'hazo_logs/server';
|
|
|
249
325
|
|
|
250
326
|
const logger = createLogger('auth');
|
|
251
327
|
|
|
252
|
-
async function
|
|
328
|
+
async function handle_request(req) {
|
|
253
329
|
await runWithLogContext(
|
|
254
330
|
{
|
|
255
331
|
sessionId: req.sessionId,
|
|
256
332
|
reference: `user-${req.userId}`,
|
|
257
333
|
depth: 0,
|
|
334
|
+
scope: 'auth.login', // Fine-grained operation scope (dotted notation)
|
|
335
|
+
userId: req.userId, // User ID propagated to all log entries
|
|
258
336
|
},
|
|
259
337
|
async () => {
|
|
260
|
-
logger.info('Request started'); // Automatically includes
|
|
261
|
-
await
|
|
338
|
+
logger.info('Request started'); // Automatically includes all context fields
|
|
339
|
+
await process_request(req);
|
|
262
340
|
logger.info('Request completed');
|
|
263
341
|
}
|
|
264
342
|
);
|
|
265
343
|
}
|
|
266
344
|
```
|
|
267
345
|
|
|
346
|
+
Available context fields: `sessionId`, `reference`, `depth`, `scope`, `userId`. All fields present in the ALS context are automatically written to every `LogEntry` produced within the callback.
|
|
347
|
+
```
|
|
348
|
+
|
|
268
349
|
### Embedded Log Viewer
|
|
269
350
|
|
|
270
351
|
Use the log viewer as a sidebar component:
|
|
@@ -450,6 +531,7 @@ logger.info('Hello world');
|
|
|
450
531
|
|
|
451
532
|
```typescript
|
|
452
533
|
interface Logger {
|
|
534
|
+
fatal(message: string, data?: Record<string, unknown>): void;
|
|
453
535
|
error(message: string, data?: Record<string, unknown>): void;
|
|
454
536
|
warn(message: string, data?: Record<string, unknown>): void;
|
|
455
537
|
info(message: string, data?: Record<string, unknown>): void;
|
|
@@ -501,6 +583,52 @@ const logger = createClientLogger({
|
|
|
501
583
|
});
|
|
502
584
|
```
|
|
503
585
|
|
|
586
|
+
#### `ErrorBoundary`
|
|
587
|
+
|
|
588
|
+
React class component that catches render errors, generates a `correlationId`, and logs to the server via the client logger pipeline. The `fallback` render prop receives `{ error, correlationId, retry }`.
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
import { ErrorBoundary } from 'hazo_logs/ui';
|
|
592
|
+
|
|
593
|
+
<ErrorBoundary
|
|
594
|
+
fallback={({ error, correlationId, retry }) => (
|
|
595
|
+
<div>
|
|
596
|
+
<p>Something went wrong. Reference: {correlationId}</p>
|
|
597
|
+
<button onClick={retry}>Retry</button>
|
|
598
|
+
</div>
|
|
599
|
+
)}
|
|
600
|
+
>
|
|
601
|
+
<MyComponent />
|
|
602
|
+
</ErrorBoundary>
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
Props: `fallback` (required), `onError?: (error, correlationId) => void`, `apiBasePath?: string`, `packageName?: string`.
|
|
606
|
+
|
|
607
|
+
**React 19 + Next.js 16 note:** Wrap state changes that may cause throws inside `startTransition()` to prevent the dev overlay from covering the error fallback. React 19 dev mode re-reports caught errors globally; transitions suppress this.
|
|
608
|
+
|
|
609
|
+
#### `useErrorReporter(options?)`
|
|
610
|
+
|
|
611
|
+
React hook for manual error reporting. Each method returns a correlationId string. Auto-attaches `route_path` (window.location.pathname) and `user_agent` to every entry.
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
import { useErrorReporter } from 'hazo_logs/ui';
|
|
615
|
+
|
|
616
|
+
function MyComponent() {
|
|
617
|
+
const { reportError } = useErrorReporter({ userId: session?.user?.id });
|
|
618
|
+
|
|
619
|
+
const handle_action = async () => {
|
|
620
|
+
try {
|
|
621
|
+
await risky_operation();
|
|
622
|
+
} catch (err) {
|
|
623
|
+
const id = reportError(err, { component: 'MyComponent' });
|
|
624
|
+
show_toast(`Something went wrong. Reference: ${id}`);
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Methods: `reportError(error, context?)`, `reportWarning(message, context?)`, `reportInfo(message, context?)`. Pass `options.userId` to attach `user_id` to all entries — no `hazo_auth` import required.
|
|
631
|
+
|
|
504
632
|
#### `LogViewerPage`
|
|
505
633
|
|
|
506
634
|
Main log viewer component.
|
|
@@ -562,6 +690,70 @@ const authHandler = withLogAuth(handler, async (request) => {
|
|
|
562
690
|
});
|
|
563
691
|
```
|
|
564
692
|
|
|
693
|
+
### Error Handling Surface (`hazo_logs/server`)
|
|
694
|
+
|
|
695
|
+
#### `withErrorHandler(handler)`
|
|
696
|
+
|
|
697
|
+
Wraps a Next.js App Router handler with structured error handling. Generates a `correlationId` (UUID), sets `X-Correlation-Id` on error responses, catches `HandledError` duck-typed throws returning structured JSON with the correct HTTP status, and catches generic `Error` logging at `fatal` and returning 500 (internal message never reaches the client).
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
import { withErrorHandler } from 'hazo_logs/server';
|
|
701
|
+
|
|
702
|
+
export const GET = withErrorHandler(async (req: Request) => {
|
|
703
|
+
// Throw HandledError for structured 4xx/5xx responses:
|
|
704
|
+
throw { code: 'not_found', statusCode: 404, userMessage: 'Resource not found' };
|
|
705
|
+
// Throw Error for 500 — message never reaches client:
|
|
706
|
+
throw new Error('db connection failed');
|
|
707
|
+
});
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
Error response shape:
|
|
711
|
+
```json
|
|
712
|
+
{ "error": "Resource not found", "code": "not_found", "correlationId": "uuid" }
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Level routing: 5xx throws → `error`, 4xx throws → `warn`, generic `Error` → `fatal`.
|
|
716
|
+
|
|
717
|
+
#### `installGlobalErrorHandlers(options?)`
|
|
718
|
+
|
|
719
|
+
Installs `process.on('unhandledRejection')` and `process.on('uncaughtException')`. Both log at `fatal` with a correlationId, call optional `onFatal`, then wait 500ms and call `process.exit(1)`. Call once at process startup (e.g. `instrumentation.ts`).
|
|
720
|
+
|
|
721
|
+
```typescript
|
|
722
|
+
import { installGlobalErrorHandlers } from 'hazo_logs/server';
|
|
723
|
+
|
|
724
|
+
installGlobalErrorHandlers({
|
|
725
|
+
onFatal: async (err) => {
|
|
726
|
+
await alertOpsTeam(err);
|
|
727
|
+
},
|
|
728
|
+
exitOnUncaught: true, // default
|
|
729
|
+
});
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
Options: `onFatal?: (err: Error) => void | Promise<void>`, `exitOnUncaught?: boolean`.
|
|
733
|
+
|
|
734
|
+
#### `registerAlertTrigger(config)`
|
|
735
|
+
|
|
736
|
+
Sliding-window alert trigger via `hazo_notify` (optional peer dep). Hooks into `HazoLogger.addLogHook` and fires when a match threshold is crossed within a time window. Returns an unregister function.
|
|
737
|
+
|
|
738
|
+
```typescript
|
|
739
|
+
import { registerAlertTrigger } from 'hazo_logs/server';
|
|
740
|
+
|
|
741
|
+
const unregister = registerAlertTrigger({
|
|
742
|
+
id: 'payment_errors',
|
|
743
|
+
match: { level: 'error', scopePrefix: 'payment.' },
|
|
744
|
+
threshold: { count: 3, windowMs: 60_000 },
|
|
745
|
+
notify: {
|
|
746
|
+
kind: 'ops.payment_error',
|
|
747
|
+
scopeId: 'my_app',
|
|
748
|
+
recipientUserIds: ['ops-user-uuid'],
|
|
749
|
+
surfaces: ['email'],
|
|
750
|
+
},
|
|
751
|
+
});
|
|
752
|
+
// Call unregister() to stop listening
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
`match` supports: `level`, `scopePrefix`, `message_contains`. Set `threshold.count` to `0` to fire on every match. `recipientUserIds` can be a static array or `(entry) => string[]`.
|
|
756
|
+
|
|
565
757
|
## Live tail (v1.1+)
|
|
566
758
|
|
|
567
759
|
`tailLogs` watches the active rotating log file and emits new entries as they are written. Filters mirror `readLogs`. Use it directly for in-process consumers:
|
|
@@ -597,7 +789,7 @@ Logs are stored as newline-delimited JSON:
|
|
|
597
789
|
|
|
598
790
|
**Fields:**
|
|
599
791
|
- `timestamp` - ISO 8601 timestamp
|
|
600
|
-
- `level` - Log level (error, warn, info, debug)
|
|
792
|
+
- `level` - Log level (fatal, error, warn, info, debug)
|
|
601
793
|
- `package` - Package name from createLogger
|
|
602
794
|
- `message` - Log message
|
|
603
795
|
- `filename` - Source file name
|
|
@@ -606,6 +798,8 @@ Logs are stored as newline-delimited JSON:
|
|
|
606
798
|
- `sessionId` - Optional session ID from context
|
|
607
799
|
- `reference` - Optional reference from context
|
|
608
800
|
- `depth` - Optional call depth from context
|
|
801
|
+
- `scope` - Optional operation scope from context (dotted notation, e.g. `"payment.checkout.refund"`)
|
|
802
|
+
- `userId` - Optional user ID from ALS context
|
|
609
803
|
- `data` - Optional additional data
|
|
610
804
|
|
|
611
805
|
## UI Screenshots
|
package/dist/index.d.ts
CHANGED
|
@@ -33,5 +33,10 @@
|
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
export { createLogger, createLoggerAsync, preloadServerLogger, ConsoleLogger, } from './lib/universal-logger.js';
|
|
36
|
-
export
|
|
36
|
+
export { getRingBuffer, RingBuffer, RingBufferRegistry, ringBufferRegistry } from './lib/ring_buffer.js';
|
|
37
|
+
export { getCallerInfo, get_filename, get_line_number } from './lib/utils/caller_info.js';
|
|
38
|
+
export type { CallerInfo } from './lib/utils/caller_info.js';
|
|
39
|
+
export { LevelResolver } from './lib/level_resolver.js';
|
|
40
|
+
export type { OverrideMap } from './lib/level_resolver.js';
|
|
41
|
+
export type { Logger, LogLevel, LogData, LogEntry, LogContext, HazoLogConfig, PackageLoggerOptions, LogSource, LogOrigin, RingBufferEntry, } from './lib/types.js';
|
|
37
42
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,MAAM,EACN,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAGzG,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC1F,YAAY,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,YAAY,EACV,MAAM,EACN,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,SAAS,EACT,eAAe,GAChB,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -34,4 +34,10 @@
|
|
|
34
34
|
*/
|
|
35
35
|
// Universal logger - works on both server and client
|
|
36
36
|
export { createLogger, createLoggerAsync, preloadServerLogger, ConsoleLogger, } from './lib/universal-logger.js';
|
|
37
|
+
// Ring buffer — safe for server; no-ops on client
|
|
38
|
+
export { getRingBuffer, RingBuffer, RingBufferRegistry, ringBufferRegistry } from './lib/ring_buffer.js';
|
|
39
|
+
// Caller-info utilities — server-side stack-trace helpers
|
|
40
|
+
export { getCallerInfo, get_filename, get_line_number } from './lib/utils/caller_info.js';
|
|
41
|
+
// LevelResolver — pure logic, no Node.js deps, safe for universal use
|
|
42
|
+
export { LevelResolver } from './lib/level_resolver.js';
|
|
37
43
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,qDAAqD;AACrD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,qDAAqD;AACrD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,2BAA2B,CAAC;AAEnC,kDAAkD;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEzG,0DAA0D;AAC1D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAG1F,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registerAlertTrigger — fires hazo_notify dispatch when log volume crosses a threshold.
|
|
3
|
+
*
|
|
4
|
+
* Requires hazo_notify to be installed (optional peer dep).
|
|
5
|
+
* Sliding window state is in-memory — resets on process restart.
|
|
6
|
+
*/
|
|
7
|
+
import type { LogEntry, LogLevel } from './types.js';
|
|
8
|
+
export interface AlertTriggerMatch {
|
|
9
|
+
/** Only match entries at this level or above */
|
|
10
|
+
level?: LogLevel;
|
|
11
|
+
/** Only match entries whose `scope` starts with this prefix */
|
|
12
|
+
scopePrefix?: string;
|
|
13
|
+
/** Only match entries whose message contains this substring */
|
|
14
|
+
message_contains?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface AlertTriggerNotify {
|
|
17
|
+
/** hazo_notify event_type */
|
|
18
|
+
kind: string;
|
|
19
|
+
/** hazo_notify scope_id */
|
|
20
|
+
scopeId: string;
|
|
21
|
+
/** Static list OR function returning IDs from the triggering log entry */
|
|
22
|
+
recipientUserIds: string[] | ((entry: LogEntry) => string[]);
|
|
23
|
+
/** hazo_notify surfaces (e.g. ['email', 'bell']) */
|
|
24
|
+
surfaces?: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface AlertTriggerConfig {
|
|
27
|
+
id: string;
|
|
28
|
+
match: AlertTriggerMatch;
|
|
29
|
+
threshold: {
|
|
30
|
+
/** Number of matching events required to fire */
|
|
31
|
+
count: number;
|
|
32
|
+
/** Sliding window duration in ms. 0 = fire on every match (no window) */
|
|
33
|
+
windowMs: number;
|
|
34
|
+
};
|
|
35
|
+
notify: AlertTriggerNotify;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register an alert trigger. Returns an unregister function.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* const unregister = registerAlertTrigger({
|
|
42
|
+
* id: 'payment_errors',
|
|
43
|
+
* match: { level: 'error', scopePrefix: 'payment.' },
|
|
44
|
+
* threshold: { count: 1, windowMs: 0 },
|
|
45
|
+
* notify: {
|
|
46
|
+
* kind: 'ops.payment_error',
|
|
47
|
+
* scopeId: 'my_app',
|
|
48
|
+
* recipientUserIds: ['ops-user-uuid'],
|
|
49
|
+
* surfaces: ['email'],
|
|
50
|
+
* },
|
|
51
|
+
* });
|
|
52
|
+
*/
|
|
53
|
+
export declare function registerAlertTrigger(config: AlertTriggerConfig): () => void;
|
|
54
|
+
//# sourceMappingURL=alert-triggers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-triggers.d.ts","sourceRoot":"","sources":["../../src/lib/alert-triggers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,gBAAgB,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC;IAC7D,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,iBAAiB,CAAC;IACzB,SAAS,EAAE;QACT,iDAAiD;QACjD,KAAK,EAAE,MAAM,CAAC;QACd,yEAAyE;QACzE,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AA2DD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,IAAI,CA2B3E"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registerAlertTrigger — fires hazo_notify dispatch when log volume crosses a threshold.
|
|
3
|
+
*
|
|
4
|
+
* Requires hazo_notify to be installed (optional peer dep).
|
|
5
|
+
* Sliding window state is in-memory — resets on process restart.
|
|
6
|
+
*/
|
|
7
|
+
import { optional_import } from 'hazo_core';
|
|
8
|
+
import { HazoLogger } from './hazo_logger.js';
|
|
9
|
+
const HAZO_LOG_LEVEL_PRIORITY = {
|
|
10
|
+
fatal: 0,
|
|
11
|
+
error: 1,
|
|
12
|
+
warn: 2,
|
|
13
|
+
info: 3,
|
|
14
|
+
debug: 4,
|
|
15
|
+
trace: 5,
|
|
16
|
+
};
|
|
17
|
+
function matchesTrigger(entry, match) {
|
|
18
|
+
if (match.level) {
|
|
19
|
+
// Entry level must be at least as severe as the match level
|
|
20
|
+
if (HAZO_LOG_LEVEL_PRIORITY[entry.level] > HAZO_LOG_LEVEL_PRIORITY[match.level]) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (match.scopePrefix && !entry.scope?.startsWith(match.scopePrefix)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (match.message_contains && !entry.message.includes(match.message_contains)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
async function fireNotification(config, entry) {
|
|
33
|
+
const dispatcher = await optional_import('hazo_notify/dispatcher');
|
|
34
|
+
if (!dispatcher) {
|
|
35
|
+
console.error(`[hazo_logs] Alert trigger "${config.id}" fired but hazo_notify is not installed. ` +
|
|
36
|
+
'Add hazo_notify as a dependency to receive alert notifications.');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const recipientUserIds = Array.isArray(config.notify.recipientUserIds)
|
|
40
|
+
? config.notify.recipientUserIds
|
|
41
|
+
: config.notify.recipientUserIds(entry);
|
|
42
|
+
await dispatcher.dispatch({
|
|
43
|
+
scope_id: config.notify.scopeId,
|
|
44
|
+
event_type: config.notify.kind,
|
|
45
|
+
subject_id: entry.timestamp,
|
|
46
|
+
recipient_user_ids: recipientUserIds,
|
|
47
|
+
surfaces: config.notify.surfaces,
|
|
48
|
+
payloads: {
|
|
49
|
+
log_level: entry.level,
|
|
50
|
+
log_package: entry.package,
|
|
51
|
+
log_message: entry.message,
|
|
52
|
+
log_scope: entry.scope,
|
|
53
|
+
log_timestamp: entry.timestamp,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Register an alert trigger. Returns an unregister function.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const unregister = registerAlertTrigger({
|
|
62
|
+
* id: 'payment_errors',
|
|
63
|
+
* match: { level: 'error', scopePrefix: 'payment.' },
|
|
64
|
+
* threshold: { count: 1, windowMs: 0 },
|
|
65
|
+
* notify: {
|
|
66
|
+
* kind: 'ops.payment_error',
|
|
67
|
+
* scopeId: 'my_app',
|
|
68
|
+
* recipientUserIds: ['ops-user-uuid'],
|
|
69
|
+
* surfaces: ['email'],
|
|
70
|
+
* },
|
|
71
|
+
* });
|
|
72
|
+
*/
|
|
73
|
+
export function registerAlertTrigger(config) {
|
|
74
|
+
// Per-trigger sliding window: array of event timestamps
|
|
75
|
+
const eventTimestamps = [];
|
|
76
|
+
const unregister = HazoLogger.addLogHook((entry) => {
|
|
77
|
+
if (!matchesTrigger(entry, config.match))
|
|
78
|
+
return;
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
// Prune events outside the window (skip for windowMs = 0)
|
|
81
|
+
if (config.threshold.windowMs > 0) {
|
|
82
|
+
const cutoff = now - config.threshold.windowMs;
|
|
83
|
+
while (eventTimestamps.length > 0 && eventTimestamps[0] < cutoff) {
|
|
84
|
+
eventTimestamps.shift();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
eventTimestamps.push(now);
|
|
88
|
+
if (eventTimestamps.length >= config.threshold.count) {
|
|
89
|
+
// Reset window before async fire so re-entrant logs don't double-fire
|
|
90
|
+
eventTimestamps.length = 0;
|
|
91
|
+
void fireNotification(config, entry);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return unregister;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=alert-triggers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-triggers.js","sourceRoot":"","sources":["../../src/lib/alert-triggers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config_loader.d.ts","sourceRoot":"","sources":["../../src/lib/config_loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"config_loader.d.ts","sourceRoot":"","sources":["../../src/lib/config_loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,YAAY,CAAC;AAKhE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CA6B7D"}
|
|
@@ -7,8 +7,6 @@ import path from 'path';
|
|
|
7
7
|
import ini from 'ini';
|
|
8
8
|
import { DEFAULT_CONFIG } from './utils/constants.js';
|
|
9
9
|
const CONFIG_FILENAME = 'config/hazo_logs_config.ini';
|
|
10
|
-
// Track whether the missing config warning has been shown
|
|
11
|
-
let _config_warning_shown = false;
|
|
12
10
|
/**
|
|
13
11
|
* Load configuration from INI file
|
|
14
12
|
* @param configPath - Optional explicit path to config file
|
|
@@ -17,10 +15,6 @@ let _config_warning_shown = false;
|
|
|
17
15
|
export function loadConfig(configPath) {
|
|
18
16
|
const resolvedPath = configPath || findConfigFile();
|
|
19
17
|
if (!resolvedPath || !fs.existsSync(resolvedPath)) {
|
|
20
|
-
if (!_config_warning_shown) {
|
|
21
|
-
_config_warning_shown = true;
|
|
22
|
-
console.warn(`[HazoLog] No config found, using defaults. Create ${CONFIG_FILENAME} to customize.`);
|
|
23
|
-
}
|
|
24
18
|
return { ...DEFAULT_CONFIG };
|
|
25
19
|
}
|
|
26
20
|
try {
|
|
@@ -71,7 +65,7 @@ function findConfigFile() {
|
|
|
71
65
|
return null;
|
|
72
66
|
}
|
|
73
67
|
/**
|
|
74
|
-
* Validate and return a valid log level
|
|
68
|
+
* Validate and return a valid config log level (fatal excluded — not a valid min-level)
|
|
75
69
|
*/
|
|
76
70
|
function validateLogLevel(level) {
|
|
77
71
|
const validLevels = ['error', 'warn', 'info', 'debug'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config_loader.js","sourceRoot":"","sources":["../../src/lib/config_loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,eAAe,GAAG,6BAA6B,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"config_loader.js","sourceRoot":"","sources":["../../src/lib/config_loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This module imports ONLY from types.ts (pure type definitions)
|
|
6
6
|
* so it is safe for both server and client environments.
|
|
7
7
|
*/
|
|
8
|
-
import type { Logger, LogData, LogLevel } from './types.js';
|
|
8
|
+
import type { Logger, LogData, LogLevel, RingBufferEntry } from './types.js';
|
|
9
9
|
export declare const LOG_LEVEL_PRIORITY: Record<LogLevel, number>;
|
|
10
10
|
/**
|
|
11
11
|
* Console-based logger for client-side use
|
|
@@ -18,9 +18,25 @@ export declare class ConsoleLogger implements Logger {
|
|
|
18
18
|
constructor(packageName: string, minLevel?: LogLevel, on_log?: (level: string, message: string, data?: Record<string, unknown>) => void);
|
|
19
19
|
private shouldLog;
|
|
20
20
|
private formatMessage;
|
|
21
|
+
fatal(message: string, data?: LogData): void;
|
|
21
22
|
error(message: string, data?: LogData): void;
|
|
22
23
|
warn(message: string, data?: LogData): void;
|
|
23
24
|
info(message: string, data?: LogData): void;
|
|
24
25
|
debug(message: string, data?: LogData): void;
|
|
26
|
+
trace(message: string, data?: LogData): void;
|
|
27
|
+
heartbeat(_name: string, _fields: {
|
|
28
|
+
status: string;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}, _opts?: {
|
|
31
|
+
trigger?: (prev: Record<string, unknown>, curr: Record<string, unknown>) => boolean;
|
|
32
|
+
}): void;
|
|
33
|
+
sampled(level: 'trace' | 'debug' | 'info' | 'warn', msg: string, fields?: Record<string, unknown>, opts?: {
|
|
34
|
+
sample: number;
|
|
35
|
+
}): void;
|
|
36
|
+
dedupe(level: 'trace' | 'debug' | 'info' | 'warn', msg: string, fields?: Record<string, unknown>, _opts?: {
|
|
37
|
+
window: string;
|
|
38
|
+
key?: string;
|
|
39
|
+
}): void;
|
|
40
|
+
getRingBuffer(_correlationId: string, _n?: number): RingBufferEntry[];
|
|
25
41
|
}
|
|
26
42
|
//# sourceMappingURL=console-logger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-logger.d.ts","sourceRoot":"","sources":["../../src/lib/console-logger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"console-logger.d.ts","sourceRoot":"","sources":["../../src/lib/console-logger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7E,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAOvD,CAAC;AAEF;;;GAGG;AACH,qBAAa,aAAc,YAAW,MAAM;IAC1C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,MAAM,CAAC,CAA2E;gBAE9E,WAAW,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAkB,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;IAMhJ,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,aAAa;IAKrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAO5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAO5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAO3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAO3C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAO5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAU5C,SAAS,CACP,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,EACnD,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAA;KAAE,GAC9F,IAAI;IAOP,OAAO,CACL,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,EAC1C,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GACxB,IAAI;IAUP,MAAM,CACJ,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,EAC1C,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACvC,IAAI;IASP,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,eAAe,EAAE;CAItE"}
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* so it is safe for both server and client environments.
|
|
7
7
|
*/
|
|
8
8
|
export const LOG_LEVEL_PRIORITY = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
fatal: 0,
|
|
10
|
+
error: 1,
|
|
11
|
+
warn: 2,
|
|
12
|
+
info: 3,
|
|
13
|
+
debug: 4,
|
|
14
|
+
trace: 5,
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* Console-based logger for client-side use
|
|
@@ -31,6 +33,12 @@ export class ConsoleLogger {
|
|
|
31
33
|
const timestamp = new Date().toISOString();
|
|
32
34
|
return `[${timestamp}] [${level.toUpperCase()}] [${this.packageName}] ${message}`;
|
|
33
35
|
}
|
|
36
|
+
fatal(message, data) {
|
|
37
|
+
if (this.shouldLog('fatal')) {
|
|
38
|
+
console.error(this.formatMessage('fatal', message), data ?? '');
|
|
39
|
+
this.on_log?.('fatal', message, data);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
34
42
|
error(message, data) {
|
|
35
43
|
if (this.shouldLog('error')) {
|
|
36
44
|
console.error(this.formatMessage('error', message), data ?? '');
|
|
@@ -55,5 +63,40 @@ export class ConsoleLogger {
|
|
|
55
63
|
this.on_log?.('debug', message, data);
|
|
56
64
|
}
|
|
57
65
|
}
|
|
66
|
+
trace(message, data) {
|
|
67
|
+
if (this.shouldLog('trace')) {
|
|
68
|
+
// Use console.debug for trace — console.trace prints a stack trace
|
|
69
|
+
console.debug(this.formatMessage('trace', message), data ?? '');
|
|
70
|
+
this.on_log?.('trace', message, data);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ─── Smart helpers (no-ops on client — server-side state would be meaningless) ─
|
|
74
|
+
heartbeat(_name, _fields, _opts) {
|
|
75
|
+
// Client-side: emit at debug level so it is at least visible when debugging
|
|
76
|
+
if (this.shouldLog('debug')) {
|
|
77
|
+
console.debug(this.formatMessage('debug', `heartbeat: ${_name}`), _fields);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
sampled(level, msg, fields, opts) {
|
|
81
|
+
const sample = opts?.sample ?? 0.1;
|
|
82
|
+
if (Math.random() < sample && this.shouldLog(level)) {
|
|
83
|
+
const sampleLabel = `(sampled ~1/${Math.round(1 / sample)})`;
|
|
84
|
+
const method = level === 'warn' ? 'warn' : level === 'info' ? 'info' : 'debug';
|
|
85
|
+
console[method](this.formatMessage(level, `${msg} ${sampleLabel}`), fields ?? '');
|
|
86
|
+
this.on_log?.(level, `${msg} ${sampleLabel}`, fields);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
dedupe(level, msg, fields, _opts) {
|
|
90
|
+
// Client-side: no deduplication state — just emit
|
|
91
|
+
if (this.shouldLog(level)) {
|
|
92
|
+
const method = level === 'warn' ? 'warn' : level === 'info' ? 'info' : 'debug';
|
|
93
|
+
console[method](this.formatMessage(level, msg), fields ?? '');
|
|
94
|
+
this.on_log?.(level, msg, fields);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
getRingBuffer(_correlationId, _n) {
|
|
98
|
+
// Client-side: no ring buffer
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
58
101
|
}
|
|
59
102
|
//# sourceMappingURL=console-logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-logger.js","sourceRoot":"","sources":["../../src/lib/console-logger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,kBAAkB,GAA6B;IAC1D,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,aAAa;IAChB,WAAW,CAAS;IACpB,QAAQ,CAAW;IACnB,MAAM,CAA4E;IAE1F,YAAY,WAAmB,EAAE,WAAqB,OAAO,EAAE,MAAiF;QAC9I,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,SAAS,CAAC,KAAe;QAC/B,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxE,CAAC;IAEO,aAAa,CAAC,KAAe,EAAE,OAAe;QACpD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,OAAO,IAAI,SAAS,MAAM,KAAK,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,WAAW,KAAK,OAAO,EAAE,CAAC;IACpF,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAc;QACnC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAAc;QAClC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC9D,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAAc;QAClC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC9D,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAc;QACnC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"console-logger.js","sourceRoot":"","sources":["../../src/lib/console-logger.ts"],"names":[],"mappings":"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"}
|