@steve31415/log-logger-ts 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/README.md +128 -0
- package/dist/adapters/browser.d.ts +14 -0
- package/dist/adapters/browser.d.ts.map +1 -0
- package/dist/adapters/browser.js +52 -0
- package/dist/adapters/browser.js.map +1 -0
- package/dist/adapters/fetch.d.ts +10 -0
- package/dist/adapters/fetch.d.ts.map +1 -0
- package/dist/adapters/fetch.js +34 -0
- package/dist/adapters/fetch.js.map +1 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +72 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +251 -0
- package/dist/logger.js.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# @steve31415/log-logger-ts
|
|
2
|
+
|
|
3
|
+
Lightweight logging library for Cloudflare Workers and browsers with automatic batching and dual logging (console + backend).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @steve31415/log-logger-ts
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Dual logging**: Logs to console immediately and batches for backend delivery
|
|
14
|
+
- **Automatic batching**: Flushes on 10 events, 1 second timeout, or any ERROR (whichever first)
|
|
15
|
+
- **Timeout-based flush**: `flushWithTimeout(ms)` for Workers with `ctx.waitUntil`
|
|
16
|
+
- **Best-effort delivery**: `flushSync()` uses `sendBeacon` for browser page unload
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Cloudflare Workers (fetch handler)
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { Logger, FetchDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
24
|
+
|
|
25
|
+
const INGEST_ENDPOINT = 'https://log-ingest.example.com/v1/logs:ingest';
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
async fetch(request, env, ctx) {
|
|
29
|
+
const logger = new Logger(
|
|
30
|
+
{ app: 'my-app', context: 'worker_http' },
|
|
31
|
+
new FetchDeliveryAdapter(INGEST_ENDPOINT)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
logger.info('Request received', { url: request.url });
|
|
36
|
+
// ... handle request
|
|
37
|
+
return new Response('OK');
|
|
38
|
+
} finally {
|
|
39
|
+
ctx.waitUntil(logger.flushWithTimeout(3000));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Cloudflare Workers (cron/queue)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { Logger, FetchDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
49
|
+
|
|
50
|
+
const INGEST_ENDPOINT = 'https://log-ingest.example.com/v1/logs:ingest';
|
|
51
|
+
|
|
52
|
+
async scheduled(event, env, ctx) {
|
|
53
|
+
const logger = new Logger(
|
|
54
|
+
{ app: 'my-app', context: 'worker_cron', runId: crypto.randomUUID() },
|
|
55
|
+
new FetchDeliveryAdapter(INGEST_ENDPOINT)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
logger.info('Cron started');
|
|
60
|
+
// ... do work
|
|
61
|
+
logger.info('Cron completed');
|
|
62
|
+
} finally {
|
|
63
|
+
await logger.flushWithTimeout(3000);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Browser
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { Logger, BrowserDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
72
|
+
|
|
73
|
+
const logger = new Logger(
|
|
74
|
+
{ app: 'my-app', context: 'web_frontend' },
|
|
75
|
+
new BrowserDeliveryAdapter('/api/logs')
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Flush on page visibility change (uses sendBeacon for reliability)
|
|
79
|
+
document.addEventListener('visibilitychange', () => {
|
|
80
|
+
if (document.visibilityState === 'hidden') {
|
|
81
|
+
logger.flushSync();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
### Logger Options
|
|
89
|
+
|
|
90
|
+
| Option | Type | Default | Description |
|
|
91
|
+
|--------|------|---------|-------------|
|
|
92
|
+
| `app` | string | required | Application name |
|
|
93
|
+
| `context` | string | required | Execution context (e.g., `worker_http`, `web_frontend`) |
|
|
94
|
+
| `runId` | string | optional | Correlation ID for invocation/session |
|
|
95
|
+
| `logger` | string | optional | Module/subsystem name |
|
|
96
|
+
| `batchSize` | number | 10 | Max events before flush |
|
|
97
|
+
| `batchTimeoutMs` | number | 1000 | Max time before flush (ms) |
|
|
98
|
+
| `consoleLog` | boolean | true | Enable console logging |
|
|
99
|
+
| `minLevel` | LogLevel | 'DEBUG' | Minimum level to log |
|
|
100
|
+
|
|
101
|
+
### Log Levels
|
|
102
|
+
|
|
103
|
+
- `logger.debug(message, meta?)` - DEBUG level
|
|
104
|
+
- `logger.info(message, meta?)` - INFO level
|
|
105
|
+
- `logger.warn(message, meta?)` - WARN level
|
|
106
|
+
- `logger.error(message, meta?)` - ERROR level (triggers immediate flush)
|
|
107
|
+
|
|
108
|
+
### Child Loggers
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const logger = new Logger({ app: 'my-app', context: 'worker_http' }, adapter);
|
|
112
|
+
const dbLogger = logger.child('database');
|
|
113
|
+
const authLogger = logger.child('auth');
|
|
114
|
+
|
|
115
|
+
dbLogger.info('Query executed'); // Logs as [my-app:database]
|
|
116
|
+
authLogger.warn('Token expired'); // Logs as [my-app:auth]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Flush Methods
|
|
120
|
+
|
|
121
|
+
- `flush()` - Async flush of buffered events
|
|
122
|
+
- `flushWithTimeout(ms)` - Flush with timeout, falls back to `sendBeacon` if available
|
|
123
|
+
- `flushSync()` - Synchronous best-effort flush using `sendBeacon` (for page unload)
|
|
124
|
+
- `close()` - Flush and prevent further logging
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DeliveryAdapter, IngestPayload } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Browser-based delivery adapter with sendBeacon fallback
|
|
4
|
+
*/
|
|
5
|
+
export declare class BrowserDeliveryAdapter implements DeliveryAdapter {
|
|
6
|
+
private endpoint;
|
|
7
|
+
constructor(endpoint: string);
|
|
8
|
+
deliver(payload: IngestPayload): Promise<boolean>;
|
|
9
|
+
/**
|
|
10
|
+
* Best-effort delivery using sendBeacon for page unload scenarios
|
|
11
|
+
*/
|
|
12
|
+
deliverBestEffort(payload: IngestPayload): boolean;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/adapters/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAC;AAE/E;;GAEG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAChD,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE9B,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IA6BvD;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO;CAanD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based delivery adapter with sendBeacon fallback
|
|
3
|
+
*/
|
|
4
|
+
export class BrowserDeliveryAdapter {
|
|
5
|
+
constructor(endpoint) {
|
|
6
|
+
this.endpoint = endpoint;
|
|
7
|
+
}
|
|
8
|
+
async deliver(payload) {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch(this.endpoint, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
},
|
|
15
|
+
body: JSON.stringify(payload),
|
|
16
|
+
// keepalive allows the request to outlive the page
|
|
17
|
+
keepalive: true,
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const text = await response.text();
|
|
21
|
+
console.error(`[Logger] Delivery failed: ${response.status} ${text}`);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const result = await response.json();
|
|
25
|
+
if (result.rejected > 0) {
|
|
26
|
+
console.warn(`[Logger] ${result.rejected} events rejected:`, result.errors);
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('[Logger] Delivery error:', error);
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Best-effort delivery using sendBeacon for page unload scenarios
|
|
37
|
+
*/
|
|
38
|
+
deliverBestEffort(payload) {
|
|
39
|
+
if (typeof navigator !== 'undefined' && navigator.sendBeacon) {
|
|
40
|
+
const blob = new Blob([JSON.stringify(payload)], {
|
|
41
|
+
type: 'application/json',
|
|
42
|
+
});
|
|
43
|
+
const success = navigator.sendBeacon(this.endpoint, blob);
|
|
44
|
+
if (!success) {
|
|
45
|
+
console.error('[Logger] sendBeacon failed');
|
|
46
|
+
}
|
|
47
|
+
return success;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/adapters/browser.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,sBAAsB;IACjC,YAAoB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAExC,KAAK,CAAC,OAAO,CAAC,OAAsB;QAClC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAC1C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAC7B,mDAAmD;gBACnD,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;gBACtE,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,MAAM,GAAmB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrD,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,QAAQ,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,OAAsB;QACtC,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YAC7D,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE;gBAC/C,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DeliveryAdapter, IngestPayload } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Fetch-based delivery adapter for Cloudflare Workers and Node.js environments
|
|
4
|
+
*/
|
|
5
|
+
export declare class FetchDeliveryAdapter implements DeliveryAdapter {
|
|
6
|
+
private endpoint;
|
|
7
|
+
constructor(endpoint: string);
|
|
8
|
+
deliver(payload: IngestPayload): Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/adapters/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAC;AAE/E;;GAEG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC9C,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE9B,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;CA0BxD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch-based delivery adapter for Cloudflare Workers and Node.js environments
|
|
3
|
+
*/
|
|
4
|
+
export class FetchDeliveryAdapter {
|
|
5
|
+
constructor(endpoint) {
|
|
6
|
+
this.endpoint = endpoint;
|
|
7
|
+
}
|
|
8
|
+
async deliver(payload) {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch(this.endpoint, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
},
|
|
15
|
+
body: JSON.stringify(payload),
|
|
16
|
+
});
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
const text = await response.text();
|
|
19
|
+
console.error(`[Logger] Delivery failed: ${response.status} ${text}`);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const result = await response.json();
|
|
23
|
+
if (result.rejected > 0) {
|
|
24
|
+
console.warn(`[Logger] ${result.rejected} events rejected:`, result.errors);
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('[Logger] Delivery error:', error);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/adapters/fetch.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,oBAAoB;IAC/B,YAAoB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAExC,KAAK,CAAC,OAAO,CAAC,OAAsB;QAClC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAC1C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAC9B,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;gBACtE,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,MAAM,GAAmB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrD,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,QAAQ,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @steve31415/log-logger-ts - Lightweight logging library for Cloudflare Workers and browsers
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Dual logging: console + backend delivery
|
|
6
|
+
* - Automatic batching (10 events, 1 second, or on ERROR)
|
|
7
|
+
* - Timeout-based flush for Workers
|
|
8
|
+
* - Best-effort sendBeacon for browser page unload
|
|
9
|
+
*
|
|
10
|
+
* @example Workers fetch handler
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { Logger, FetchDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
13
|
+
*
|
|
14
|
+
* const INGEST_ENDPOINT = 'https://log-ingest.example.com/v1/logs:ingest';
|
|
15
|
+
*
|
|
16
|
+
* export default {
|
|
17
|
+
* async fetch(request, env, ctx) {
|
|
18
|
+
* const logger = new Logger(
|
|
19
|
+
* { app: 'my-app', context: 'worker_http' },
|
|
20
|
+
* new FetchDeliveryAdapter(INGEST_ENDPOINT)
|
|
21
|
+
* );
|
|
22
|
+
* try {
|
|
23
|
+
* logger.info('Request received', { url: request.url });
|
|
24
|
+
* // ... handle request
|
|
25
|
+
* return new Response('OK');
|
|
26
|
+
* } finally {
|
|
27
|
+
* ctx.waitUntil(logger.flushWithTimeout(3000));
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Browser
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { Logger, BrowserDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
36
|
+
*
|
|
37
|
+
* const logger = new Logger(
|
|
38
|
+
* { app: 'my-app', context: 'web_frontend' },
|
|
39
|
+
* new BrowserDeliveryAdapter('/api/logs')
|
|
40
|
+
* );
|
|
41
|
+
*
|
|
42
|
+
* // Flush on page unload
|
|
43
|
+
* document.addEventListener('visibilitychange', () => {
|
|
44
|
+
* if (document.visibilityState === 'hidden') {
|
|
45
|
+
* logger.flushSync();
|
|
46
|
+
* }
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export { Logger } from './logger';
|
|
51
|
+
export { FetchDeliveryAdapter, BrowserDeliveryAdapter } from './adapters';
|
|
52
|
+
export type { LogLevel, LogEvent, LoggerConfig, DeliveryAdapter, ConsoleAdapter, IngestPayload, IngestResponse, } from './types';
|
|
53
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC1E,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @steve31415/log-logger-ts - Lightweight logging library for Cloudflare Workers and browsers
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Dual logging: console + backend delivery
|
|
6
|
+
* - Automatic batching (10 events, 1 second, or on ERROR)
|
|
7
|
+
* - Timeout-based flush for Workers
|
|
8
|
+
* - Best-effort sendBeacon for browser page unload
|
|
9
|
+
*
|
|
10
|
+
* @example Workers fetch handler
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { Logger, FetchDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
13
|
+
*
|
|
14
|
+
* const INGEST_ENDPOINT = 'https://log-ingest.example.com/v1/logs:ingest';
|
|
15
|
+
*
|
|
16
|
+
* export default {
|
|
17
|
+
* async fetch(request, env, ctx) {
|
|
18
|
+
* const logger = new Logger(
|
|
19
|
+
* { app: 'my-app', context: 'worker_http' },
|
|
20
|
+
* new FetchDeliveryAdapter(INGEST_ENDPOINT)
|
|
21
|
+
* );
|
|
22
|
+
* try {
|
|
23
|
+
* logger.info('Request received', { url: request.url });
|
|
24
|
+
* // ... handle request
|
|
25
|
+
* return new Response('OK');
|
|
26
|
+
* } finally {
|
|
27
|
+
* ctx.waitUntil(logger.flushWithTimeout(3000));
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Browser
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { Logger, BrowserDeliveryAdapter } from '@steve31415/log-logger-ts';
|
|
36
|
+
*
|
|
37
|
+
* const logger = new Logger(
|
|
38
|
+
* { app: 'my-app', context: 'web_frontend' },
|
|
39
|
+
* new BrowserDeliveryAdapter('/api/logs')
|
|
40
|
+
* );
|
|
41
|
+
*
|
|
42
|
+
* // Flush on page unload
|
|
43
|
+
* document.addEventListener('visibilitychange', () => {
|
|
44
|
+
* if (document.visibilityState === 'hidden') {
|
|
45
|
+
* logger.flushSync();
|
|
46
|
+
* }
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export { Logger } from './logger';
|
|
51
|
+
export { FetchDeliveryAdapter, BrowserDeliveryAdapter } from './adapters';
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { LogLevel, LoggerConfig, DeliveryAdapter, ConsoleAdapter } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Logger class with batching and multi-environment support
|
|
4
|
+
*/
|
|
5
|
+
export declare class Logger {
|
|
6
|
+
private config;
|
|
7
|
+
private adapter;
|
|
8
|
+
private console;
|
|
9
|
+
private buffer;
|
|
10
|
+
private flushTimer;
|
|
11
|
+
private firstEventTime;
|
|
12
|
+
private closed;
|
|
13
|
+
private flushPromise;
|
|
14
|
+
private inFlightPayload;
|
|
15
|
+
constructor(config: LoggerConfig, adapter: DeliveryAdapter, consoleAdapter?: ConsoleAdapter);
|
|
16
|
+
/**
|
|
17
|
+
* Create a child logger with a different logger name
|
|
18
|
+
*/
|
|
19
|
+
child(loggerName: string): Logger;
|
|
20
|
+
/**
|
|
21
|
+
* Log at DEBUG level
|
|
22
|
+
*/
|
|
23
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
24
|
+
/**
|
|
25
|
+
* Log at INFO level
|
|
26
|
+
*/
|
|
27
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
28
|
+
/**
|
|
29
|
+
* Log at WARN level
|
|
30
|
+
*/
|
|
31
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Log at ERROR level
|
|
34
|
+
*/
|
|
35
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
36
|
+
/**
|
|
37
|
+
* Log at a specific level
|
|
38
|
+
*/
|
|
39
|
+
log(level: LogLevel, message: string, meta?: Record<string, unknown>): void;
|
|
40
|
+
/**
|
|
41
|
+
* Schedule a flush after the batch timeout
|
|
42
|
+
*/
|
|
43
|
+
private scheduleFlush;
|
|
44
|
+
/**
|
|
45
|
+
* Clear the scheduled flush timer
|
|
46
|
+
*/
|
|
47
|
+
private clearFlushTimer;
|
|
48
|
+
/**
|
|
49
|
+
* Flush buffered events to the backend
|
|
50
|
+
*/
|
|
51
|
+
flush(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Deliver payload with a single retry on failure
|
|
54
|
+
*/
|
|
55
|
+
private deliverWithRetry;
|
|
56
|
+
/**
|
|
57
|
+
* Flush with a timeout - useful for Workers and end-of-task scenarios
|
|
58
|
+
* @param timeoutMs Maximum time to wait for flush to complete
|
|
59
|
+
* @returns Promise that resolves when flush completes or times out
|
|
60
|
+
*/
|
|
61
|
+
flushWithTimeout(timeoutMs: number): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Close the logger - flushes remaining events and prevents further logging
|
|
64
|
+
*/
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Best-effort flush using sendBeacon (for page unload scenarios)
|
|
68
|
+
* Call this from visibilitychange or pagehide event handlers
|
|
69
|
+
*/
|
|
70
|
+
flushSync(): void;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAER,YAAY,EACZ,eAAe,EACf,cAAc,EAEf,MAAM,SAAS,CAAC;AAqBjB;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAyG;IACvH,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,eAAe,CAA8B;gBAGnD,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,eAAe,EACxB,cAAc,GAAE,cAAwB;IAgB1C;;OAEG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAQjC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAkD3E;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC5B;;OAEG;YACW,gBAAgB;IAe9B;;;;OAIG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BxD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;;OAGG;IACH,SAAS,IAAI,IAAI;CAmBlB"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
const LEVEL_PRIORITY = {
|
|
2
|
+
DEBUG: 0,
|
|
3
|
+
INFO: 1,
|
|
4
|
+
WARN: 2,
|
|
5
|
+
ERROR: 3,
|
|
6
|
+
};
|
|
7
|
+
const DEFAULT_BATCH_SIZE = 10;
|
|
8
|
+
const DEFAULT_BATCH_TIMEOUT_MS = 1000;
|
|
9
|
+
/**
|
|
10
|
+
* Generate a simple unique ID for log events
|
|
11
|
+
*/
|
|
12
|
+
function generateId() {
|
|
13
|
+
const timestamp = Date.now().toString(36);
|
|
14
|
+
const random = Math.random().toString(36).substring(2, 10);
|
|
15
|
+
return `${timestamp}-${random}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Logger class with batching and multi-environment support
|
|
19
|
+
*/
|
|
20
|
+
export class Logger {
|
|
21
|
+
constructor(config, adapter, consoleAdapter = console) {
|
|
22
|
+
this.buffer = [];
|
|
23
|
+
this.flushTimer = null;
|
|
24
|
+
this.firstEventTime = null;
|
|
25
|
+
this.closed = false;
|
|
26
|
+
this.flushPromise = null;
|
|
27
|
+
this.inFlightPayload = null;
|
|
28
|
+
this.config = {
|
|
29
|
+
app: config.app,
|
|
30
|
+
context: config.context,
|
|
31
|
+
runId: config.runId,
|
|
32
|
+
logger: config.logger,
|
|
33
|
+
batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,
|
|
34
|
+
batchTimeoutMs: config.batchTimeoutMs ?? DEFAULT_BATCH_TIMEOUT_MS,
|
|
35
|
+
consoleLog: config.consoleLog ?? true,
|
|
36
|
+
minLevel: config.minLevel ?? 'DEBUG',
|
|
37
|
+
};
|
|
38
|
+
this.adapter = adapter;
|
|
39
|
+
this.console = consoleAdapter;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a child logger with a different logger name
|
|
43
|
+
*/
|
|
44
|
+
child(loggerName) {
|
|
45
|
+
return new Logger({ ...this.config, logger: loggerName }, this.adapter, this.console);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Log at DEBUG level
|
|
49
|
+
*/
|
|
50
|
+
debug(message, meta) {
|
|
51
|
+
this.log('DEBUG', message, meta);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Log at INFO level
|
|
55
|
+
*/
|
|
56
|
+
info(message, meta) {
|
|
57
|
+
this.log('INFO', message, meta);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Log at WARN level
|
|
61
|
+
*/
|
|
62
|
+
warn(message, meta) {
|
|
63
|
+
this.log('WARN', message, meta);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Log at ERROR level
|
|
67
|
+
*/
|
|
68
|
+
error(message, meta) {
|
|
69
|
+
this.log('ERROR', message, meta);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Log at a specific level
|
|
73
|
+
*/
|
|
74
|
+
log(level, message, meta) {
|
|
75
|
+
if (this.closed) {
|
|
76
|
+
this.console.warn('[Logger] Attempted to log after close');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Check minimum level
|
|
80
|
+
if (LEVEL_PRIORITY[level] < LEVEL_PRIORITY[this.config.minLevel]) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const timestamp = Date.now();
|
|
84
|
+
// Log to native console immediately
|
|
85
|
+
if (this.config.consoleLog) {
|
|
86
|
+
const prefix = this.config.logger
|
|
87
|
+
? `[${this.config.app}:${this.config.logger}]`
|
|
88
|
+
: `[${this.config.app}]`;
|
|
89
|
+
const consoleFn = this.console[level.toLowerCase()];
|
|
90
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
91
|
+
consoleFn(`${prefix} ${message}`, meta);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
consoleFn(`${prefix} ${message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Create event for batching
|
|
98
|
+
const event = {
|
|
99
|
+
id: generateId(),
|
|
100
|
+
level,
|
|
101
|
+
message,
|
|
102
|
+
time_generated_client_ms: timestamp,
|
|
103
|
+
logger: this.config.logger,
|
|
104
|
+
meta,
|
|
105
|
+
};
|
|
106
|
+
this.buffer.push(event);
|
|
107
|
+
// Track first event time for batch timeout
|
|
108
|
+
if (this.firstEventTime === null) {
|
|
109
|
+
this.firstEventTime = timestamp;
|
|
110
|
+
this.scheduleFlush();
|
|
111
|
+
}
|
|
112
|
+
// Flush immediately on ERROR or when batch size reached
|
|
113
|
+
if (level === 'ERROR' || this.buffer.length >= this.config.batchSize) {
|
|
114
|
+
this.flush();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Schedule a flush after the batch timeout
|
|
119
|
+
*/
|
|
120
|
+
scheduleFlush() {
|
|
121
|
+
if (this.flushTimer !== null) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.flushTimer = setTimeout(() => {
|
|
125
|
+
this.flushTimer = null;
|
|
126
|
+
this.flush();
|
|
127
|
+
}, this.config.batchTimeoutMs);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Clear the scheduled flush timer
|
|
131
|
+
*/
|
|
132
|
+
clearFlushTimer() {
|
|
133
|
+
if (this.flushTimer !== null) {
|
|
134
|
+
clearTimeout(this.flushTimer);
|
|
135
|
+
this.flushTimer = null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Flush buffered events to the backend
|
|
140
|
+
*/
|
|
141
|
+
async flush() {
|
|
142
|
+
// If already flushing, wait for it
|
|
143
|
+
if (this.flushPromise) {
|
|
144
|
+
await this.flushPromise;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
this.clearFlushTimer();
|
|
148
|
+
if (this.buffer.length === 0) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Take current buffer
|
|
152
|
+
const events = this.buffer;
|
|
153
|
+
this.buffer = [];
|
|
154
|
+
this.firstEventTime = null;
|
|
155
|
+
const payload = {
|
|
156
|
+
app: this.config.app,
|
|
157
|
+
context: this.config.context,
|
|
158
|
+
run_id: this.config.runId,
|
|
159
|
+
events,
|
|
160
|
+
};
|
|
161
|
+
this.inFlightPayload = payload;
|
|
162
|
+
this.flushPromise = this.deliverWithRetry(payload);
|
|
163
|
+
try {
|
|
164
|
+
await this.flushPromise;
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
this.flushPromise = null;
|
|
168
|
+
this.inFlightPayload = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Deliver payload with a single retry on failure
|
|
173
|
+
*/
|
|
174
|
+
async deliverWithRetry(payload) {
|
|
175
|
+
let success = await this.adapter.deliver(payload);
|
|
176
|
+
if (!success) {
|
|
177
|
+
// Single retry
|
|
178
|
+
this.console.warn('[Logger] Retrying delivery...');
|
|
179
|
+
success = await this.adapter.deliver(payload);
|
|
180
|
+
if (!success) {
|
|
181
|
+
this.console.error(`[Logger] CRITICAL: Failed to deliver ${payload.events.length} log events after retry`);
|
|
182
|
+
// Events are lost at this point - we don't re-queue to avoid memory growth
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Flush with a timeout - useful for Workers and end-of-task scenarios
|
|
188
|
+
* @param timeoutMs Maximum time to wait for flush to complete
|
|
189
|
+
* @returns Promise that resolves when flush completes or times out
|
|
190
|
+
*/
|
|
191
|
+
async flushWithTimeout(timeoutMs) {
|
|
192
|
+
const flushPromise = this.flush();
|
|
193
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
reject(new Error(`Flush timed out after ${timeoutMs}ms`));
|
|
196
|
+
}, timeoutMs);
|
|
197
|
+
});
|
|
198
|
+
try {
|
|
199
|
+
await Promise.race([flushPromise, timeoutPromise]);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
this.console.error('[Logger] Flush timeout:', error);
|
|
203
|
+
// Attempt best-effort delivery if adapter supports it
|
|
204
|
+
// Use in-flight payload if flush took the buffer, otherwise use current buffer
|
|
205
|
+
const payload = this.inFlightPayload ?? (this.buffer.length > 0 ? {
|
|
206
|
+
app: this.config.app,
|
|
207
|
+
context: this.config.context,
|
|
208
|
+
run_id: this.config.runId,
|
|
209
|
+
events: this.buffer,
|
|
210
|
+
} : null);
|
|
211
|
+
if (payload && this.adapter.deliverBestEffort) {
|
|
212
|
+
this.adapter.deliverBestEffort(payload);
|
|
213
|
+
this.buffer = [];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Close the logger - flushes remaining events and prevents further logging
|
|
219
|
+
*/
|
|
220
|
+
async close() {
|
|
221
|
+
if (this.closed) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
this.closed = true;
|
|
225
|
+
this.clearFlushTimer();
|
|
226
|
+
await this.flush();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Best-effort flush using sendBeacon (for page unload scenarios)
|
|
230
|
+
* Call this from visibilitychange or pagehide event handlers
|
|
231
|
+
*/
|
|
232
|
+
flushSync() {
|
|
233
|
+
if (this.buffer.length === 0) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (this.adapter.deliverBestEffort) {
|
|
237
|
+
const payload = {
|
|
238
|
+
app: this.config.app,
|
|
239
|
+
context: this.config.context,
|
|
240
|
+
run_id: this.config.runId,
|
|
241
|
+
events: this.buffer,
|
|
242
|
+
};
|
|
243
|
+
const success = this.adapter.deliverBestEffort(payload);
|
|
244
|
+
if (success) {
|
|
245
|
+
this.buffer = [];
|
|
246
|
+
this.firstEventTime = null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level types
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
|
|
5
|
+
/**
|
|
6
|
+
* A single log event to be delivered to the backend
|
|
7
|
+
*/
|
|
8
|
+
export interface LogEvent {
|
|
9
|
+
id: string;
|
|
10
|
+
level: LogLevel;
|
|
11
|
+
message: string;
|
|
12
|
+
time_generated_client_ms: number;
|
|
13
|
+
logger?: string;
|
|
14
|
+
meta?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The payload sent to the ingest API
|
|
18
|
+
*/
|
|
19
|
+
export interface IngestPayload {
|
|
20
|
+
app: string;
|
|
21
|
+
context: string;
|
|
22
|
+
run_id?: string;
|
|
23
|
+
events: LogEvent[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Response from the ingest API
|
|
27
|
+
*/
|
|
28
|
+
export interface IngestResponse {
|
|
29
|
+
accepted: number;
|
|
30
|
+
rejected: number;
|
|
31
|
+
errors?: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Configuration for the logger
|
|
35
|
+
*/
|
|
36
|
+
export interface LoggerConfig {
|
|
37
|
+
/** Application name (required) */
|
|
38
|
+
app: string;
|
|
39
|
+
/** Execution context: web_frontend, worker_http, worker_cron, etc. */
|
|
40
|
+
context: string;
|
|
41
|
+
/** @deprecated Endpoint is now specified in the DeliveryAdapter constructor */
|
|
42
|
+
endpoint?: string;
|
|
43
|
+
/** Optional run/session ID for correlation */
|
|
44
|
+
runId?: string;
|
|
45
|
+
/** Optional default logger name (subsystem) */
|
|
46
|
+
logger?: string;
|
|
47
|
+
/** Batch size threshold (default: 10) */
|
|
48
|
+
batchSize?: number;
|
|
49
|
+
/** Batch time threshold in ms (default: 1000) */
|
|
50
|
+
batchTimeoutMs?: number;
|
|
51
|
+
/** Whether to log to console in addition to backend (default: true) */
|
|
52
|
+
consoleLog?: boolean;
|
|
53
|
+
/** Minimum level to log (default: DEBUG) */
|
|
54
|
+
minLevel?: LogLevel;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Delivery adapter interface for different environments
|
|
58
|
+
*/
|
|
59
|
+
export interface DeliveryAdapter {
|
|
60
|
+
/**
|
|
61
|
+
* Send a batch of events to the backend
|
|
62
|
+
* @returns true if delivery succeeded, false otherwise
|
|
63
|
+
*/
|
|
64
|
+
deliver(payload: IngestPayload): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Attempt to deliver using best-effort methods (e.g., sendBeacon)
|
|
67
|
+
* Used during page unload or service worker termination
|
|
68
|
+
*/
|
|
69
|
+
deliverBestEffort?(payload: IngestPayload): boolean;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Native console interface for logging
|
|
73
|
+
*/
|
|
74
|
+
export interface ConsoleAdapter {
|
|
75
|
+
debug(message: string, ...args: unknown[]): void;
|
|
76
|
+
info(message: string, ...args: unknown[]): void;
|
|
77
|
+
warn(message: string, ...args: unknown[]): void;
|
|
78
|
+
error(message: string, ...args: unknown[]): void;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,EAAE,MAAM,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IAEZ,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAEhB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElD;;;OAGG;IACH,iBAAiB,CAAC,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@steve31415/log-logger-ts",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Lightweight logging library for Cloudflare Workers and browsers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"test": "vitest"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"logging",
|
|
26
|
+
"cloudflare",
|
|
27
|
+
"workers",
|
|
28
|
+
"browser"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/plasticine-apps/log.git",
|
|
34
|
+
"directory": "libs/logger-ts"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"typescript": "^5.0.0",
|
|
38
|
+
"vitest": "^2.1.9"
|
|
39
|
+
}
|
|
40
|
+
}
|