evlog 1.6.0 → 1.7.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 +95 -0
- package/dist/_utils-DZA9nou3.mjs +23 -0
- package/dist/_utils-DZA9nou3.mjs.map +1 -0
- package/dist/adapters/axiom.d.mts +16 -15
- package/dist/adapters/axiom.d.mts.map +1 -0
- package/dist/adapters/axiom.mjs +95 -50
- package/dist/adapters/axiom.mjs.map +1 -0
- package/dist/adapters/better-stack.d.mts +62 -0
- package/dist/adapters/better-stack.d.mts.map +1 -0
- package/dist/adapters/better-stack.mjs +109 -0
- package/dist/adapters/better-stack.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +31 -30
- package/dist/adapters/otlp.d.mts.map +1 -0
- package/dist/adapters/otlp.mjs +197 -177
- package/dist/adapters/otlp.mjs.map +1 -0
- package/dist/adapters/posthog.d.mts +20 -19
- package/dist/adapters/posthog.d.mts.map +1 -0
- package/dist/adapters/posthog.mjs +109 -62
- package/dist/adapters/posthog.mjs.map +1 -0
- package/dist/adapters/sentry.d.mts +24 -23
- package/dist/adapters/sentry.d.mts.map +1 -0
- package/dist/adapters/sentry.mjs +208 -151
- package/dist/adapters/sentry.mjs.map +1 -0
- package/dist/enrichers.d.mts +74 -0
- package/dist/enrichers.d.mts.map +1 -0
- package/dist/enrichers.mjs +172 -0
- package/dist/enrichers.mjs.map +1 -0
- package/dist/error.d.mts +24 -22
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +107 -76
- package/dist/error.mjs.map +1 -0
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +6 -5
- package/dist/logger.d.mts +5 -3
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs +200 -184
- package/dist/logger.mjs.map +1 -0
- package/dist/nitro/errorHandler.d.mts +4 -2
- package/dist/nitro/errorHandler.d.mts.map +1 -0
- package/dist/nitro/errorHandler.mjs +49 -38
- package/dist/nitro/errorHandler.mjs.map +1 -0
- package/dist/nitro/plugin.d.mts +4 -2
- package/dist/nitro/plugin.d.mts.map +1 -0
- package/dist/nitro/plugin.mjs +155 -136
- package/dist/nitro/plugin.mjs.map +1 -0
- package/dist/nuxt/module.d.mts +149 -168
- package/dist/nuxt/module.d.mts.map +1 -0
- package/dist/nuxt/module.mjs +66 -65
- package/dist/nuxt/module.mjs.map +1 -0
- package/dist/pipeline.d.mts +46 -0
- package/dist/pipeline.d.mts.map +1 -0
- package/dist/pipeline.mjs +122 -0
- package/dist/pipeline.mjs.map +1 -0
- package/dist/runtime/client/log.d.mts +7 -5
- package/dist/runtime/client/log.d.mts.map +1 -0
- package/dist/runtime/client/log.mjs +57 -62
- package/dist/runtime/client/log.mjs.map +1 -0
- package/dist/runtime/client/plugin.d.mts +3 -1
- package/dist/runtime/client/plugin.d.mts.map +1 -0
- package/dist/runtime/client/plugin.mjs +13 -12
- package/dist/runtime/client/plugin.mjs.map +1 -0
- package/dist/runtime/server/routes/_evlog/ingest.post.d.mts +4 -2
- package/dist/runtime/server/routes/_evlog/ingest.post.d.mts.map +1 -0
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +113 -76
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -0
- package/dist/runtime/server/useLogger.d.mts +14 -3
- package/dist/runtime/server/useLogger.d.mts.map +1 -0
- package/dist/runtime/server/useLogger.mjs +39 -10
- package/dist/runtime/server/useLogger.mjs.map +1 -0
- package/dist/runtime/utils/parseError.d.mts +5 -3
- package/dist/runtime/utils/parseError.d.mts.map +1 -0
- package/dist/runtime/utils/parseError.mjs +25 -26
- package/dist/runtime/utils/parseError.mjs.map +1 -0
- package/dist/types.d.mts +348 -246
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +1 -1
- package/dist/utils.d.mts +19 -14
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +59 -50
- package/dist/utils.mjs.map +1 -0
- package/dist/workers.d.mts +10 -9
- package/dist/workers.d.mts.map +1 -0
- package/dist/workers.mjs +68 -39
- package/dist/workers.mjs.map +1 -0
- package/package.json +26 -5
- package/dist/adapters/axiom.d.ts +0 -62
- package/dist/adapters/otlp.d.ts +0 -83
- package/dist/adapters/posthog.d.ts +0 -72
- package/dist/adapters/sentry.d.ts +0 -78
- package/dist/error.d.ts +0 -63
- package/dist/index.d.ts +0 -5
- package/dist/logger.d.ts +0 -40
- package/dist/nitro/errorHandler.d.ts +0 -13
- package/dist/nitro/plugin.d.ts +0 -5
- package/dist/nuxt/module.d.ts +0 -171
- package/dist/runtime/client/log.d.ts +0 -10
- package/dist/runtime/client/plugin.d.ts +0 -3
- package/dist/runtime/server/routes/_evlog/ingest.post.d.ts +0 -5
- package/dist/runtime/server/useLogger.d.ts +0 -28
- package/dist/runtime/utils/parseError.d.ts +0 -5
- package/dist/shared/evlog.Bc35pxiY.mjs +0 -10
- package/dist/types.d.ts +0 -364
- package/dist/utils.d.ts +0 -29
- package/dist/workers.d.ts +0 -45
package/README.md
CHANGED
|
@@ -390,6 +390,44 @@ Notes:
|
|
|
390
390
|
- `request.cf` is included (colo, country, asn) unless disabled
|
|
391
391
|
- Use `headerAllowlist` to avoid logging sensitive headers
|
|
392
392
|
|
|
393
|
+
## Enrichment Hook
|
|
394
|
+
|
|
395
|
+
Use the `evlog:enrich` hook to add derived context after emit, before drain.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
// server/plugins/evlog-enrich.ts
|
|
399
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
400
|
+
nitroApp.hooks.hook('evlog:enrich', (ctx) => {
|
|
401
|
+
ctx.event.deploymentId = process.env.DEPLOYMENT_ID
|
|
402
|
+
})
|
|
403
|
+
})
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Built-in Enrichers
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
// server/plugins/evlog-enrich.ts
|
|
410
|
+
import {
|
|
411
|
+
createGeoEnricher,
|
|
412
|
+
createRequestSizeEnricher,
|
|
413
|
+
createTraceContextEnricher,
|
|
414
|
+
createUserAgentEnricher,
|
|
415
|
+
} from 'evlog/enrichers'
|
|
416
|
+
|
|
417
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
418
|
+
const enrich = [
|
|
419
|
+
createUserAgentEnricher(),
|
|
420
|
+
createGeoEnricher(),
|
|
421
|
+
createRequestSizeEnricher(),
|
|
422
|
+
createTraceContextEnricher(),
|
|
423
|
+
]
|
|
424
|
+
|
|
425
|
+
nitroApp.hooks.hook('evlog:enrich', (ctx) => {
|
|
426
|
+
for (const enricher of enrich) enricher(ctx)
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
```
|
|
430
|
+
|
|
393
431
|
## Adapters
|
|
394
432
|
|
|
395
433
|
Send your logs to external observability platforms with built-in adapters.
|
|
@@ -486,6 +524,63 @@ export default defineNitroPlugin((nitroApp) => {
|
|
|
486
524
|
|
|
487
525
|
> See the [full documentation](https://evlog.hrcd.fr/adapters/overview) for adapter configuration options, troubleshooting, and advanced patterns.
|
|
488
526
|
|
|
527
|
+
## Drain Pipeline
|
|
528
|
+
|
|
529
|
+
For production use, wrap your drain adapter with `createDrainPipeline` to get **batching**, **retry with backoff**, and **buffer overflow protection**.
|
|
530
|
+
|
|
531
|
+
Without a pipeline, each event triggers a separate network call. The pipeline buffers events and sends them in batches, reducing overhead and handling transient failures automatically.
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
// server/plugins/evlog-drain.ts
|
|
535
|
+
import type { DrainContext } from 'evlog'
|
|
536
|
+
import { createDrainPipeline } from 'evlog/pipeline'
|
|
537
|
+
import { createAxiomDrain } from 'evlog/axiom'
|
|
538
|
+
|
|
539
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
540
|
+
const pipeline = createDrainPipeline<DrainContext>({
|
|
541
|
+
batch: { size: 50, intervalMs: 5000 },
|
|
542
|
+
retry: { maxAttempts: 3, backoff: 'exponential', initialDelayMs: 1000 },
|
|
543
|
+
onDropped: (events, error) => {
|
|
544
|
+
console.error(`[evlog] Dropped ${events.length} events:`, error?.message)
|
|
545
|
+
},
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
const drain = pipeline(createAxiomDrain())
|
|
549
|
+
|
|
550
|
+
nitroApp.hooks.hook('evlog:drain', drain)
|
|
551
|
+
nitroApp.hooks.hook('close', () => drain.flush())
|
|
552
|
+
})
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### How it works
|
|
556
|
+
|
|
557
|
+
1. Events are buffered in memory as they arrive
|
|
558
|
+
2. A batch is flushed when either the **batch size** is reached or the **interval** expires (whichever comes first)
|
|
559
|
+
3. If the drain function fails, the batch is retried with the configured **backoff strategy**
|
|
560
|
+
4. If all retries are exhausted, `onDropped` is called with the lost events
|
|
561
|
+
5. If the buffer exceeds `maxBufferSize`, the oldest events are dropped to prevent memory leaks
|
|
562
|
+
|
|
563
|
+
### Options
|
|
564
|
+
|
|
565
|
+
| Option | Default | Description |
|
|
566
|
+
|--------|---------|-------------|
|
|
567
|
+
| `batch.size` | `50` | Maximum events per batch |
|
|
568
|
+
| `batch.intervalMs` | `5000` | Max time (ms) before flushing a partial batch |
|
|
569
|
+
| `retry.maxAttempts` | `3` | Total attempts (including first) |
|
|
570
|
+
| `retry.backoff` | `'exponential'` | `'exponential'` \| `'linear'` \| `'fixed'` |
|
|
571
|
+
| `retry.initialDelayMs` | `1000` | Base delay for first retry |
|
|
572
|
+
| `retry.maxDelayMs` | `30000` | Upper bound for any retry delay |
|
|
573
|
+
| `maxBufferSize` | `1000` | Max buffered events before dropping oldest |
|
|
574
|
+
| `onDropped` | — | Callback when events are dropped |
|
|
575
|
+
|
|
576
|
+
### Returned drain function
|
|
577
|
+
|
|
578
|
+
The function returned by `pipeline(drain)` is hook-compatible and exposes:
|
|
579
|
+
|
|
580
|
+
- **`drain(ctx)`** — Push a single event into the buffer
|
|
581
|
+
- **`drain.flush()`** — Force-flush all buffered events (call on server shutdown)
|
|
582
|
+
- **`drain.pending`** — Number of events currently buffered
|
|
583
|
+
|
|
489
584
|
## API Reference
|
|
490
585
|
|
|
491
586
|
### `initLogger(config)`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/adapters/_utils.ts
|
|
8
|
+
/**
|
|
9
|
+
* Try to get runtime config from Nitro/Nuxt environment.
|
|
10
|
+
* Returns undefined if not in a Nitro context.
|
|
11
|
+
*/
|
|
12
|
+
function getRuntimeConfig() {
|
|
13
|
+
try {
|
|
14
|
+
const { useRuntimeConfig } = __require("nitropack/runtime");
|
|
15
|
+
return useRuntimeConfig();
|
|
16
|
+
} catch {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { getRuntimeConfig as t };
|
|
23
|
+
//# sourceMappingURL=_utils-DZA9nou3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_utils-DZA9nou3.mjs","names":[],"sources":["../src/adapters/_utils.ts"],"sourcesContent":["/**\n * Try to get runtime config from Nitro/Nuxt environment.\n * Returns undefined if not in a Nitro context.\n */\nexport function getRuntimeConfig(): Record<string, any> | undefined {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { useRuntimeConfig } = require('nitropack/runtime')\n return useRuntimeConfig()\n } catch {\n return undefined\n }\n}\n"],"mappings":";;;;;;;;;;;AAIA,SAAgB,mBAAoD;AAClE,KAAI;EAEF,MAAM,EAAE,+BAA6B,oBAAoB;AACzD,SAAO,kBAAkB;SACnB;AACN"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { DrainContext, WideEvent } from
|
|
1
|
+
import { DrainContext, WideEvent } from "../types.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/adapters/axiom.d.ts
|
|
3
4
|
interface AxiomConfig {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
/** Axiom dataset name */
|
|
6
|
+
dataset: string;
|
|
7
|
+
/** Axiom API token */
|
|
8
|
+
token: string;
|
|
9
|
+
/** Organization ID (required for Personal Access Tokens) */
|
|
10
|
+
orgId?: string;
|
|
11
|
+
/** Base URL for Axiom API. Default: https://api.axiom.co */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
14
|
+
timeout?: number;
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Create a drain function for sending logs to Axiom.
|
|
@@ -32,7 +33,7 @@ interface AxiomConfig {
|
|
|
32
33
|
* }))
|
|
33
34
|
* ```
|
|
34
35
|
*/
|
|
35
|
-
declare function createAxiomDrain(overrides?: Partial<AxiomConfig>): (ctx: DrainContext) => Promise<void>;
|
|
36
|
+
declare function createAxiomDrain(overrides?: Partial<AxiomConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void>;
|
|
36
37
|
/**
|
|
37
38
|
* Send a single event to Axiom.
|
|
38
39
|
*
|
|
@@ -57,6 +58,6 @@ declare function sendToAxiom(event: WideEvent, config: AxiomConfig): Promise<voi
|
|
|
57
58
|
* ```
|
|
58
59
|
*/
|
|
59
60
|
declare function sendBatchToAxiom(events: WideEvent[], config: AxiomConfig): Promise<void>;
|
|
60
|
-
|
|
61
|
-
export { createAxiomDrain, sendBatchToAxiom, sendToAxiom };
|
|
62
|
-
|
|
61
|
+
//#endregion
|
|
62
|
+
export { AxiomConfig, createAxiomDrain, sendBatchToAxiom, sendToAxiom };
|
|
63
|
+
//# sourceMappingURL=axiom.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axiom.d.mts","names":[],"sources":["../../src/adapters/axiom.ts"],"mappings":";;;UAGiB,WAAA;;EAEf,OAAA;EAF0B;EAI1B,KAAA;EAJ0B;EAM1B,KAAA;EAFA;EAIA,OAAA;EAAA;EAEA,OAAA;AAAA;;AAuBF;;;;;;;;;;;;;;;;;;;iBAAgB,gBAAA,CAAiB,SAAA,GAAY,OAAA,CAAQ,WAAA,KAAgB,GAAA,EAAK,YAAA,GAAe,YAAA,OAAmB,OAAA;;;;;;;;;;;;iBA2CtF,WAAA,CAAY,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,WAAA,GAAc,OAAA;;;AAe1E;;;;;;;;;iBAAsB,gBAAA,CAAiB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,WAAA,GAAc,OAAA"}
|
package/dist/adapters/axiom.mjs
CHANGED
|
@@ -1,59 +1,104 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as getRuntimeConfig } from "../_utils-DZA9nou3.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/adapters/axiom.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create a drain function for sending logs to Axiom.
|
|
6
|
+
*
|
|
7
|
+
* Configuration priority (highest to lowest):
|
|
8
|
+
* 1. Overrides passed to createAxiomDrain()
|
|
9
|
+
* 2. runtimeConfig.evlog.axiom
|
|
10
|
+
* 3. runtimeConfig.axiom
|
|
11
|
+
* 4. Environment variables: NUXT_AXIOM_*, AXIOM_*
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // Zero config - just set NUXT_AXIOM_TOKEN and NUXT_AXIOM_DATASET env vars
|
|
16
|
+
* nitroApp.hooks.hook('evlog:drain', createAxiomDrain())
|
|
17
|
+
*
|
|
18
|
+
* // With overrides
|
|
19
|
+
* nitroApp.hooks.hook('evlog:drain', createAxiomDrain({
|
|
20
|
+
* dataset: 'my-dataset',
|
|
21
|
+
* }))
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
3
24
|
function createAxiomDrain(overrides) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
return async (ctx) => {
|
|
26
|
+
const contexts = Array.isArray(ctx) ? ctx : [ctx];
|
|
27
|
+
if (contexts.length === 0) return;
|
|
28
|
+
const runtimeConfig = getRuntimeConfig();
|
|
29
|
+
const evlogAxiom = runtimeConfig?.evlog?.axiom;
|
|
30
|
+
const rootAxiom = runtimeConfig?.axiom;
|
|
31
|
+
const config = {
|
|
32
|
+
dataset: overrides?.dataset ?? evlogAxiom?.dataset ?? rootAxiom?.dataset ?? process.env.NUXT_AXIOM_DATASET ?? process.env.AXIOM_DATASET,
|
|
33
|
+
token: overrides?.token ?? evlogAxiom?.token ?? rootAxiom?.token ?? process.env.NUXT_AXIOM_TOKEN ?? process.env.AXIOM_TOKEN,
|
|
34
|
+
orgId: overrides?.orgId ?? evlogAxiom?.orgId ?? rootAxiom?.orgId ?? process.env.NUXT_AXIOM_ORG_ID ?? process.env.AXIOM_ORG_ID,
|
|
35
|
+
baseUrl: overrides?.baseUrl ?? evlogAxiom?.baseUrl ?? rootAxiom?.baseUrl ?? process.env.NUXT_AXIOM_URL ?? process.env.AXIOM_URL,
|
|
36
|
+
timeout: overrides?.timeout ?? evlogAxiom?.timeout ?? rootAxiom?.timeout
|
|
37
|
+
};
|
|
38
|
+
if (!config.dataset || !config.token) {
|
|
39
|
+
console.error("[evlog/axiom] Missing dataset or token. Set NUXT_AXIOM_TOKEN/NUXT_AXIOM_DATASET env vars or pass to createAxiomDrain()");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
await sendBatchToAxiom(contexts.map((c) => c.event), config);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("[evlog/axiom] Failed to send events to Axiom:", error);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
25
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Send a single event to Axiom.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* await sendToAxiom(event, {
|
|
55
|
+
* dataset: 'my-logs',
|
|
56
|
+
* token: process.env.AXIOM_TOKEN!,
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
26
60
|
async function sendToAxiom(event, config) {
|
|
27
|
-
|
|
61
|
+
await sendBatchToAxiom([event], config);
|
|
28
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Send a batch of events to Axiom.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* await sendBatchToAxiom(events, {
|
|
69
|
+
* dataset: 'my-logs',
|
|
70
|
+
* token: process.env.AXIOM_TOKEN!,
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
29
74
|
async function sendBatchToAxiom(events, config) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
clearTimeout(timeoutId);
|
|
56
|
-
}
|
|
75
|
+
const baseUrl = config.baseUrl ?? "https://api.axiom.co";
|
|
76
|
+
const timeout = config.timeout ?? 5e3;
|
|
77
|
+
const url = `${baseUrl}/v1/datasets/${encodeURIComponent(config.dataset)}/ingest`;
|
|
78
|
+
const headers = {
|
|
79
|
+
"Content-Type": "application/json",
|
|
80
|
+
"Authorization": `Bearer ${config.token}`
|
|
81
|
+
};
|
|
82
|
+
if (config.orgId) headers["X-Axiom-Org-Id"] = config.orgId;
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
85
|
+
try {
|
|
86
|
+
const response = await fetch(url, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers,
|
|
89
|
+
body: JSON.stringify(events),
|
|
90
|
+
signal: controller.signal
|
|
91
|
+
});
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
const text = await response.text().catch(() => "Unknown error");
|
|
94
|
+
const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text;
|
|
95
|
+
throw new Error(`Axiom API error: ${response.status} ${response.statusText} - ${safeText}`);
|
|
96
|
+
}
|
|
97
|
+
} finally {
|
|
98
|
+
clearTimeout(timeoutId);
|
|
99
|
+
}
|
|
57
100
|
}
|
|
58
101
|
|
|
102
|
+
//#endregion
|
|
59
103
|
export { createAxiomDrain, sendBatchToAxiom, sendToAxiom };
|
|
104
|
+
//# sourceMappingURL=axiom.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axiom.mjs","names":[],"sources":["../../src/adapters/axiom.ts"],"sourcesContent":["import type { DrainContext, WideEvent } from '../types'\nimport { getRuntimeConfig } from './_utils'\n\nexport interface AxiomConfig {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Base URL for Axiom API. Default: https://api.axiom.co */\n baseUrl?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\n/**\n * Create a drain function for sending logs to Axiom.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createAxiomDrain()\n * 2. runtimeConfig.evlog.axiom\n * 3. runtimeConfig.axiom\n * 4. Environment variables: NUXT_AXIOM_*, AXIOM_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_AXIOM_TOKEN and NUXT_AXIOM_DATASET env vars\n * nitroApp.hooks.hook('evlog:drain', createAxiomDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createAxiomDrain({\n * dataset: 'my-dataset',\n * }))\n * ```\n */\nexport function createAxiomDrain(overrides?: Partial<AxiomConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void> {\n return async (ctx: DrainContext | DrainContext[]) => {\n const contexts = Array.isArray(ctx) ? ctx : [ctx]\n if (contexts.length === 0) return\n\n const runtimeConfig = getRuntimeConfig()\n // Support both runtimeConfig.evlog.axiom and runtimeConfig.axiom\n const evlogAxiom = runtimeConfig?.evlog?.axiom\n const rootAxiom = runtimeConfig?.axiom\n\n // Build config with fallbacks: overrides > evlog.axiom > axiom > env vars (NUXT_AXIOM_* or AXIOM_*)\n const config: Partial<AxiomConfig> = {\n dataset: overrides?.dataset ?? evlogAxiom?.dataset ?? rootAxiom?.dataset ?? process.env.NUXT_AXIOM_DATASET ?? process.env.AXIOM_DATASET,\n token: overrides?.token ?? evlogAxiom?.token ?? rootAxiom?.token ?? process.env.NUXT_AXIOM_TOKEN ?? process.env.AXIOM_TOKEN,\n orgId: overrides?.orgId ?? evlogAxiom?.orgId ?? rootAxiom?.orgId ?? process.env.NUXT_AXIOM_ORG_ID ?? process.env.AXIOM_ORG_ID,\n baseUrl: overrides?.baseUrl ?? evlogAxiom?.baseUrl ?? rootAxiom?.baseUrl ?? process.env.NUXT_AXIOM_URL ?? process.env.AXIOM_URL,\n timeout: overrides?.timeout ?? evlogAxiom?.timeout ?? rootAxiom?.timeout,\n }\n\n if (!config.dataset || !config.token) {\n console.error('[evlog/axiom] Missing dataset or token. Set NUXT_AXIOM_TOKEN/NUXT_AXIOM_DATASET env vars or pass to createAxiomDrain()')\n return\n }\n\n try {\n await sendBatchToAxiom(contexts.map(c => c.event), config as AxiomConfig)\n } catch (error) {\n console.error('[evlog/axiom] Failed to send events to Axiom:', error)\n }\n }\n}\n\n/**\n * Send a single event to Axiom.\n *\n * @example\n * ```ts\n * await sendToAxiom(event, {\n * dataset: 'my-logs',\n * token: process.env.AXIOM_TOKEN!,\n * })\n * ```\n */\nexport async function sendToAxiom(event: WideEvent, config: AxiomConfig): Promise<void> {\n await sendBatchToAxiom([event], config)\n}\n\n/**\n * Send a batch of events to Axiom.\n *\n * @example\n * ```ts\n * await sendBatchToAxiom(events, {\n * dataset: 'my-logs',\n * token: process.env.AXIOM_TOKEN!,\n * })\n * ```\n */\nexport async function sendBatchToAxiom(events: WideEvent[], config: AxiomConfig): Promise<void> {\n const baseUrl = config.baseUrl ?? 'https://api.axiom.co'\n const timeout = config.timeout ?? 5000\n const url = `${baseUrl}/v1/datasets/${encodeURIComponent(config.dataset)}/ingest`\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.token}`,\n }\n\n if (config.orgId) {\n headers['X-Axiom-Org-Id'] = config.orgId\n }\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(events),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => 'Unknown error')\n const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text\n throw new Error(`Axiom API error: ${response.status} ${response.statusText} - ${safeText}`)\n }\n } finally {\n clearTimeout(timeoutId)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,iBAAiB,WAAyF;AACxH,QAAO,OAAO,QAAuC;EACnD,MAAM,WAAW,MAAM,QAAQ,IAAI,GAAG,MAAM,CAAC,IAAI;AACjD,MAAI,SAAS,WAAW,EAAG;EAE3B,MAAM,gBAAgB,kBAAkB;EAExC,MAAM,aAAa,eAAe,OAAO;EACzC,MAAM,YAAY,eAAe;EAGjC,MAAM,SAA+B;GACnC,SAAS,WAAW,WAAW,YAAY,WAAW,WAAW,WAAW,QAAQ,IAAI,sBAAsB,QAAQ,IAAI;GAC1H,OAAO,WAAW,SAAS,YAAY,SAAS,WAAW,SAAS,QAAQ,IAAI,oBAAoB,QAAQ,IAAI;GAChH,OAAO,WAAW,SAAS,YAAY,SAAS,WAAW,SAAS,QAAQ,IAAI,qBAAqB,QAAQ,IAAI;GACjH,SAAS,WAAW,WAAW,YAAY,WAAW,WAAW,WAAW,QAAQ,IAAI,kBAAkB,QAAQ,IAAI;GACtH,SAAS,WAAW,WAAW,YAAY,WAAW,WAAW;GAClE;AAED,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,OAAO;AACpC,WAAQ,MAAM,yHAAyH;AACvI;;AAGF,MAAI;AACF,SAAM,iBAAiB,SAAS,KAAI,MAAK,EAAE,MAAM,EAAE,OAAsB;WAClE,OAAO;AACd,WAAQ,MAAM,iDAAiD,MAAM;;;;;;;;;;;;;;;AAgB3E,eAAsB,YAAY,OAAkB,QAAoC;AACtF,OAAM,iBAAiB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;;AAczC,eAAsB,iBAAiB,QAAqB,QAAoC;CAC9F,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,MAAM,GAAG,QAAQ,eAAe,mBAAmB,OAAO,QAAQ,CAAC;CAEzE,MAAM,UAAkC;EACtC,gBAAgB;EAChB,iBAAiB,UAAU,OAAO;EACnC;AAED,KAAI,OAAO,MACT,SAAQ,oBAAoB,OAAO;CAGrC,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,WAAW;GACpB,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,gBAAgB;GAC/D,MAAM,WAAW,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC,kBAAkB;AAC7E,SAAM,IAAI,MAAM,oBAAoB,SAAS,OAAO,GAAG,SAAS,WAAW,KAAK,WAAW;;WAErF;AACR,eAAa,UAAU"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/better-stack.d.ts
|
|
4
|
+
interface BetterStackConfig {
|
|
5
|
+
/** Better Stack source token */
|
|
6
|
+
sourceToken: string;
|
|
7
|
+
/** Logtail ingestion endpoint. Default: https://in.logs.betterstack.com */
|
|
8
|
+
endpoint?: string;
|
|
9
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Transform an evlog wide event into a Better Stack event.
|
|
14
|
+
* Maps `timestamp` to `dt` (Better Stack's expected field).
|
|
15
|
+
*/
|
|
16
|
+
declare function toBetterStackEvent(event: WideEvent): Record<string, unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a drain function for sending logs to Better Stack.
|
|
19
|
+
*
|
|
20
|
+
* Configuration priority (highest to lowest):
|
|
21
|
+
* 1. Overrides passed to createBetterStackDrain()
|
|
22
|
+
* 2. runtimeConfig.evlog.betterStack
|
|
23
|
+
* 3. runtimeConfig.betterStack
|
|
24
|
+
* 4. Environment variables: NUXT_BETTER_STACK_*, BETTER_STACK_*
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var
|
|
29
|
+
* nitroApp.hooks.hook('evlog:drain', createBetterStackDrain())
|
|
30
|
+
*
|
|
31
|
+
* // With overrides
|
|
32
|
+
* nitroApp.hooks.hook('evlog:drain', createBetterStackDrain({
|
|
33
|
+
* sourceToken: 'my-token',
|
|
34
|
+
* }))
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
declare function createBetterStackDrain(overrides?: Partial<BetterStackConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Send a single event to Better Stack.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* await sendToBetterStack(event, {
|
|
44
|
+
* sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,
|
|
45
|
+
* })
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare function sendToBetterStack(event: WideEvent, config: BetterStackConfig): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Send a batch of events to Better Stack.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* await sendBatchToBetterStack(events, {
|
|
55
|
+
* sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare function sendBatchToBetterStack(events: WideEvent[], config: BetterStackConfig): Promise<void>;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { BetterStackConfig, createBetterStackDrain, sendBatchToBetterStack, sendToBetterStack, toBetterStackEvent };
|
|
62
|
+
//# sourceMappingURL=better-stack.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-stack.d.mts","names":[],"sources":["../../src/adapters/better-stack.ts"],"mappings":";;;UAGiB,iBAAA;;EAEf,WAAA;EAFgC;EAIhC,QAAA;EAJgC;EAMhC,OAAA;AAAA;;;;AAOF;iBAAgB,kBAAA,CAAmB,KAAA,EAAO,SAAA,GAAY,MAAA;;;;;;;;AAyBtD;;;;;;;;;;;;;iBAAgB,sBAAA,CAAuB,SAAA,GAAY,OAAA,CAAQ,iBAAA,KAAsB,GAAA,EAAK,YAAA,GAAe,YAAA,OAAmB,OAAA;;;;;;AAsCxH;;;;;iBAAsB,iBAAA,CAAkB,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,iBAAA,GAAoB,OAAA;;;;;;;;;;AActF;iBAAsB,sBAAA,CAAuB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,iBAAA,GAAoB,OAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { t as getRuntimeConfig } from "../_utils-DZA9nou3.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/better-stack.ts
|
|
4
|
+
/**
|
|
5
|
+
* Transform an evlog wide event into a Better Stack event.
|
|
6
|
+
* Maps `timestamp` to `dt` (Better Stack's expected field).
|
|
7
|
+
*/
|
|
8
|
+
function toBetterStackEvent(event) {
|
|
9
|
+
const { timestamp, ...rest } = event;
|
|
10
|
+
return {
|
|
11
|
+
...rest,
|
|
12
|
+
dt: timestamp
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a drain function for sending logs to Better Stack.
|
|
17
|
+
*
|
|
18
|
+
* Configuration priority (highest to lowest):
|
|
19
|
+
* 1. Overrides passed to createBetterStackDrain()
|
|
20
|
+
* 2. runtimeConfig.evlog.betterStack
|
|
21
|
+
* 3. runtimeConfig.betterStack
|
|
22
|
+
* 4. Environment variables: NUXT_BETTER_STACK_*, BETTER_STACK_*
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var
|
|
27
|
+
* nitroApp.hooks.hook('evlog:drain', createBetterStackDrain())
|
|
28
|
+
*
|
|
29
|
+
* // With overrides
|
|
30
|
+
* nitroApp.hooks.hook('evlog:drain', createBetterStackDrain({
|
|
31
|
+
* sourceToken: 'my-token',
|
|
32
|
+
* }))
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function createBetterStackDrain(overrides) {
|
|
36
|
+
return async (ctx) => {
|
|
37
|
+
const contexts = Array.isArray(ctx) ? ctx : [ctx];
|
|
38
|
+
if (contexts.length === 0) return;
|
|
39
|
+
const runtimeConfig = getRuntimeConfig();
|
|
40
|
+
const evlogBetterStack = runtimeConfig?.evlog?.betterStack;
|
|
41
|
+
const rootBetterStack = runtimeConfig?.betterStack;
|
|
42
|
+
const config = {
|
|
43
|
+
sourceToken: overrides?.sourceToken ?? evlogBetterStack?.sourceToken ?? rootBetterStack?.sourceToken ?? process.env.NUXT_BETTER_STACK_SOURCE_TOKEN ?? process.env.BETTER_STACK_SOURCE_TOKEN,
|
|
44
|
+
endpoint: overrides?.endpoint ?? evlogBetterStack?.endpoint ?? rootBetterStack?.endpoint ?? process.env.NUXT_BETTER_STACK_ENDPOINT ?? process.env.BETTER_STACK_ENDPOINT,
|
|
45
|
+
timeout: overrides?.timeout ?? evlogBetterStack?.timeout ?? rootBetterStack?.timeout
|
|
46
|
+
};
|
|
47
|
+
if (!config.sourceToken) {
|
|
48
|
+
console.error("[evlog/better-stack] Missing source token. Set NUXT_BETTER_STACK_SOURCE_TOKEN env var or pass to createBetterStackDrain()");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
await sendBatchToBetterStack(contexts.map((c) => c.event), config);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error("[evlog/better-stack] Failed to send events to Better Stack:", error);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Send a single event to Better Stack.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* await sendToBetterStack(event, {
|
|
64
|
+
* sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,
|
|
65
|
+
* })
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
async function sendToBetterStack(event, config) {
|
|
69
|
+
await sendBatchToBetterStack([event], config);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Send a batch of events to Better Stack.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* await sendBatchToBetterStack(events, {
|
|
77
|
+
* sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
async function sendBatchToBetterStack(events, config) {
|
|
82
|
+
const endpoint = (config.endpoint ?? "https://in.logs.betterstack.com").replace(/\/+$/, "");
|
|
83
|
+
const timeout = config.timeout ?? 5e3;
|
|
84
|
+
const headers = {
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
"Authorization": `Bearer ${config.sourceToken}`
|
|
87
|
+
};
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(endpoint, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers,
|
|
94
|
+
body: JSON.stringify(events.map(toBetterStackEvent)),
|
|
95
|
+
signal: controller.signal
|
|
96
|
+
});
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const text = await response.text().catch(() => "Unknown error");
|
|
99
|
+
const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text;
|
|
100
|
+
throw new Error(`Better Stack API error: ${response.status} ${response.statusText} - ${safeText}`);
|
|
101
|
+
}
|
|
102
|
+
} finally {
|
|
103
|
+
clearTimeout(timeoutId);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
export { createBetterStackDrain, sendBatchToBetterStack, sendToBetterStack, toBetterStackEvent };
|
|
109
|
+
//# sourceMappingURL=better-stack.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-stack.mjs","names":[],"sources":["../../src/adapters/better-stack.ts"],"sourcesContent":["import type { DrainContext, WideEvent } from '../types'\nimport { getRuntimeConfig } from './_utils'\n\nexport interface BetterStackConfig {\n /** Better Stack source token */\n sourceToken: string\n /** Logtail ingestion endpoint. Default: https://in.logs.betterstack.com */\n endpoint?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\n/**\n * Transform an evlog wide event into a Better Stack event.\n * Maps `timestamp` to `dt` (Better Stack's expected field).\n */\nexport function toBetterStackEvent(event: WideEvent): Record<string, unknown> {\n const { timestamp, ...rest } = event\n return { ...rest, dt: timestamp }\n}\n\n/**\n * Create a drain function for sending logs to Better Stack.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createBetterStackDrain()\n * 2. runtimeConfig.evlog.betterStack\n * 3. runtimeConfig.betterStack\n * 4. Environment variables: NUXT_BETTER_STACK_*, BETTER_STACK_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var\n * nitroApp.hooks.hook('evlog:drain', createBetterStackDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('evlog:drain', createBetterStackDrain({\n * sourceToken: 'my-token',\n * }))\n * ```\n */\nexport function createBetterStackDrain(overrides?: Partial<BetterStackConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void> {\n return async (ctx: DrainContext | DrainContext[]) => {\n const contexts = Array.isArray(ctx) ? ctx : [ctx]\n if (contexts.length === 0) return\n\n const runtimeConfig = getRuntimeConfig()\n const evlogBetterStack = runtimeConfig?.evlog?.betterStack\n const rootBetterStack = runtimeConfig?.betterStack\n\n const config: Partial<BetterStackConfig> = {\n sourceToken: overrides?.sourceToken ?? evlogBetterStack?.sourceToken ?? rootBetterStack?.sourceToken ?? process.env.NUXT_BETTER_STACK_SOURCE_TOKEN ?? process.env.BETTER_STACK_SOURCE_TOKEN,\n endpoint: overrides?.endpoint ?? evlogBetterStack?.endpoint ?? rootBetterStack?.endpoint ?? process.env.NUXT_BETTER_STACK_ENDPOINT ?? process.env.BETTER_STACK_ENDPOINT,\n timeout: overrides?.timeout ?? evlogBetterStack?.timeout ?? rootBetterStack?.timeout,\n }\n\n if (!config.sourceToken) {\n console.error('[evlog/better-stack] Missing source token. Set NUXT_BETTER_STACK_SOURCE_TOKEN env var or pass to createBetterStackDrain()')\n return\n }\n\n try {\n await sendBatchToBetterStack(contexts.map(c => c.event), config as BetterStackConfig)\n } catch (error) {\n console.error('[evlog/better-stack] Failed to send events to Better Stack:', error)\n }\n }\n}\n\n/**\n * Send a single event to Better Stack.\n *\n * @example\n * ```ts\n * await sendToBetterStack(event, {\n * sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,\n * })\n * ```\n */\nexport async function sendToBetterStack(event: WideEvent, config: BetterStackConfig): Promise<void> {\n await sendBatchToBetterStack([event], config)\n}\n\n/**\n * Send a batch of events to Better Stack.\n *\n * @example\n * ```ts\n * await sendBatchToBetterStack(events, {\n * sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,\n * })\n * ```\n */\nexport async function sendBatchToBetterStack(events: WideEvent[], config: BetterStackConfig): Promise<void> {\n const endpoint = (config.endpoint ?? 'https://in.logs.betterstack.com').replace(/\\/+$/, '')\n const timeout = config.timeout ?? 5000\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.sourceToken}`,\n }\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(events.map(toBetterStackEvent)),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => 'Unknown error')\n const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text\n throw new Error(`Better Stack API error: ${response.status} ${response.statusText} - ${safeText}`)\n }\n } finally {\n clearTimeout(timeoutId)\n }\n}\n"],"mappings":";;;;;;;AAgBA,SAAgB,mBAAmB,OAA2C;CAC5E,MAAM,EAAE,WAAW,GAAG,SAAS;AAC/B,QAAO;EAAE,GAAG;EAAM,IAAI;EAAW;;;;;;;;;;;;;;;;;;;;;;AAuBnC,SAAgB,uBAAuB,WAA+F;AACpI,QAAO,OAAO,QAAuC;EACnD,MAAM,WAAW,MAAM,QAAQ,IAAI,GAAG,MAAM,CAAC,IAAI;AACjD,MAAI,SAAS,WAAW,EAAG;EAE3B,MAAM,gBAAgB,kBAAkB;EACxC,MAAM,mBAAmB,eAAe,OAAO;EAC/C,MAAM,kBAAkB,eAAe;EAEvC,MAAM,SAAqC;GACzC,aAAa,WAAW,eAAe,kBAAkB,eAAe,iBAAiB,eAAe,QAAQ,IAAI,kCAAkC,QAAQ,IAAI;GAClK,UAAU,WAAW,YAAY,kBAAkB,YAAY,iBAAiB,YAAY,QAAQ,IAAI,8BAA8B,QAAQ,IAAI;GAClJ,SAAS,WAAW,WAAW,kBAAkB,WAAW,iBAAiB;GAC9E;AAED,MAAI,CAAC,OAAO,aAAa;AACvB,WAAQ,MAAM,4HAA4H;AAC1I;;AAGF,MAAI;AACF,SAAM,uBAAuB,SAAS,KAAI,MAAK,EAAE,MAAM,EAAE,OAA4B;WAC9E,OAAO;AACd,WAAQ,MAAM,+DAA+D,MAAM;;;;;;;;;;;;;;AAezF,eAAsB,kBAAkB,OAAkB,QAA0C;AAClG,OAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAa/C,eAAsB,uBAAuB,QAAqB,QAA0C;CAC1G,MAAM,YAAY,OAAO,YAAY,mCAAmC,QAAQ,QAAQ,GAAG;CAC3F,MAAM,UAAU,OAAO,WAAW;CAElC,MAAM,UAAkC;EACtC,gBAAgB;EAChB,iBAAiB,UAAU,OAAO;EACnC;CAED,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,UAAU;GACrC,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,OAAO,IAAI,mBAAmB,CAAC;GACpD,QAAQ,WAAW;GACpB,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,gBAAgB;GAC/D,MAAM,WAAW,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC,kBAAkB;AAC7E,SAAM,IAAI,MAAM,2BAA2B,SAAS,OAAO,GAAG,SAAS,WAAW,KAAK,WAAW;;WAE5F;AACR,eAAa,UAAU"}
|
package/dist/adapters/otlp.d.mts
CHANGED
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
import { DrainContext, WideEvent } from
|
|
1
|
+
import { DrainContext, WideEvent } from "../types.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/adapters/otlp.d.ts
|
|
3
4
|
interface OTLPConfig {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
/** OTLP HTTP endpoint (e.g., http://localhost:4318) */
|
|
6
|
+
endpoint: string;
|
|
7
|
+
/** Override service name (defaults to event.service) */
|
|
8
|
+
serviceName?: string;
|
|
9
|
+
/** Additional resource attributes */
|
|
10
|
+
resourceAttributes?: Record<string, string | number | boolean>;
|
|
11
|
+
/** Custom headers (e.g., for authentication) */
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
14
|
+
timeout?: number;
|
|
14
15
|
}
|
|
15
16
|
/** OTLP Log Record structure */
|
|
16
17
|
interface OTLPLogRecord {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
timeUnixNano: string;
|
|
19
|
+
severityNumber: number;
|
|
20
|
+
severityText: string;
|
|
21
|
+
body: {
|
|
22
|
+
stringValue: string;
|
|
23
|
+
};
|
|
24
|
+
attributes: Array<{
|
|
25
|
+
key: string;
|
|
26
|
+
value: {
|
|
27
|
+
stringValue?: string;
|
|
28
|
+
intValue?: string;
|
|
29
|
+
boolValue?: boolean;
|
|
22
30
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
stringValue?: string;
|
|
27
|
-
intValue?: string;
|
|
28
|
-
boolValue?: boolean;
|
|
29
|
-
};
|
|
30
|
-
}>;
|
|
31
|
-
traceId?: string;
|
|
32
|
-
spanId?: string;
|
|
31
|
+
}>;
|
|
32
|
+
traceId?: string;
|
|
33
|
+
spanId?: string;
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* Convert an evlog WideEvent to an OTLP LogRecord.
|
|
@@ -55,7 +56,7 @@ declare function toOTLPLogRecord(event: WideEvent): OTLPLogRecord;
|
|
|
55
56
|
* }))
|
|
56
57
|
* ```
|
|
57
58
|
*/
|
|
58
|
-
declare function createOTLPDrain(overrides?: Partial<OTLPConfig>): (ctx: DrainContext) => Promise<void>;
|
|
59
|
+
declare function createOTLPDrain(overrides?: Partial<OTLPConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void>;
|
|
59
60
|
/**
|
|
60
61
|
* Send a single event to an OTLP endpoint.
|
|
61
62
|
*
|
|
@@ -78,6 +79,6 @@ declare function sendToOTLP(event: WideEvent, config: OTLPConfig): Promise<void>
|
|
|
78
79
|
* ```
|
|
79
80
|
*/
|
|
80
81
|
declare function sendBatchToOTLP(events: WideEvent[], config: OTLPConfig): Promise<void>;
|
|
81
|
-
|
|
82
|
-
export { createOTLPDrain, sendBatchToOTLP, sendToOTLP, toOTLPLogRecord };
|
|
83
|
-
|
|
82
|
+
//#endregion
|
|
83
|
+
export { OTLPConfig, OTLPLogRecord, createOTLPDrain, sendBatchToOTLP, sendToOTLP, toOTLPLogRecord };
|
|
84
|
+
//# sourceMappingURL=otlp.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otlp.d.mts","names":[],"sources":["../../src/adapters/otlp.ts"],"mappings":";;;UAGiB,UAAA;;EAEf,QAAA;EAFyB;EAIzB,WAAA;EAIgB;EAFhB,kBAAA,GAAqB,MAAA;EAFrB;EAIA,OAAA,GAAU,MAAA;EAFW;EAIrB,OAAA;AAAA;;UAIe,aAAA;EACf,YAAA;EACA,cAAA;EACA,YAAA;EACA,IAAA;IAAQ,WAAA;EAAA;EACR,UAAA,EAAY,KAAA;IACV,GAAA;IACA,KAAA;MAAS,WAAA;MAAsB,QAAA;MAAmB,SAAA;IAAA;EAAA;EAEpD,OAAA;EACA,MAAA;AAAA;;;;iBAkEc,eAAA,CAAgB,KAAA,EAAO,SAAA,GAAY,aAAA;AAAnD;;;;;;;;;AA4HA;;;;;;;;;;;AA5HA,iBA4HgB,eAAA,CAAgB,SAAA,GAAY,OAAA,CAAQ,UAAA,KAAe,GAAA,EAAK,YAAA,GAAe,YAAA,OAAmB,OAAA;;;;;;;;AA0E1G;;;iBAAsB,UAAA,CAAW,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,UAAA,GAAa,OAAA;;;;;;;;;;;iBAclD,eAAA,CAAgB,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,UAAA,GAAa,OAAA"}
|