workers-axiom 0.1.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/dist/producer/index.d.ts +4 -0
  4. package/dist/producer/index.d.ts.map +1 -0
  5. package/dist/producer/index.js +5 -0
  6. package/dist/producer/index.js.map +1 -0
  7. package/dist/producer/logger.d.ts +146 -0
  8. package/dist/producer/logger.d.ts.map +1 -0
  9. package/dist/producer/logger.js +179 -0
  10. package/dist/producer/logger.js.map +1 -0
  11. package/dist/producer/tracing/clock.d.ts +21 -0
  12. package/dist/producer/tracing/clock.d.ts.map +1 -0
  13. package/dist/producer/tracing/clock.js +17 -0
  14. package/dist/producer/tracing/clock.js.map +1 -0
  15. package/dist/producer/tracing/index.d.ts +3 -0
  16. package/dist/producer/tracing/index.d.ts.map +1 -0
  17. package/dist/producer/tracing/index.js +3 -0
  18. package/dist/producer/tracing/index.js.map +1 -0
  19. package/dist/producer/tracing/span.d.ts +63 -0
  20. package/dist/producer/tracing/span.d.ts.map +1 -0
  21. package/dist/producer/tracing/span.js +94 -0
  22. package/dist/producer/tracing/span.js.map +1 -0
  23. package/dist/protocol/index.d.ts +58 -0
  24. package/dist/protocol/index.d.ts.map +1 -0
  25. package/dist/protocol/index.js +50 -0
  26. package/dist/protocol/index.js.map +1 -0
  27. package/dist/tail/index.d.ts +43 -0
  28. package/dist/tail/index.d.ts.map +1 -0
  29. package/dist/tail/index.js +155 -0
  30. package/dist/tail/index.js.map +1 -0
  31. package/dist/tail/spans.d.ts +19 -0
  32. package/dist/tail/spans.d.ts.map +1 -0
  33. package/dist/tail/spans.js +93 -0
  34. package/dist/tail/spans.js.map +1 -0
  35. package/package.json +41 -0
  36. package/src/producer/index.ts +28 -0
  37. package/src/producer/logger.ts +343 -0
  38. package/src/producer/tracing/clock.ts +38 -0
  39. package/src/producer/tracing/index.ts +8 -0
  40. package/src/producer/tracing/span.ts +148 -0
  41. package/src/protocol/index.ts +104 -0
  42. package/src/tail/index.ts +237 -0
  43. package/src/tail/spans.ts +137 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sapt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # workers-axiom
2
+
3
+ Structured logging, tracing, and metrics for Cloudflare Workers, with an Axiom tail-worker sink.
4
+
5
+ > **Status:** used internally by Sapt. Open source, MIT-licensed. PRs welcome, support is best-effort.
6
+
7
+ ## What it does
8
+
9
+ - **Producer** (`workers-axiom/producer`): a `Logger` your worker uses to emit structured logs, metrics, and OpenTelemetry-style spans. Output is plain `console.log` JSON — nothing leaves the worker directly.
10
+ - **Tail consumer** (`workers-axiom/tail`): a factory that builds a Cloudflare `tail()` handler. Point your other workers at it via `tail_consumers`. It parses the producer's JSON, batches it, and forwards logs to Axiom's ingest endpoint and sampled spans to Axiom's OTLP traces endpoint.
11
+
12
+ The two halves communicate through a shared wire format (`workers-axiom/protocol`) and nothing else. You can deploy them independently.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ pnpm add workers-axiom
18
+ ```
19
+
20
+ ## Producer usage
21
+
22
+ ```ts
23
+ import { withTrace, type Logger } from 'workers-axiom/producer'
24
+
25
+ interface Env { ENVIRONMENT: string }
26
+
27
+ export default {
28
+ fetch: (request: Request, env: Env, ctx: ExecutionContext) =>
29
+ withTrace(
30
+ {
31
+ name: 'api.fetch',
32
+ kind: 'server',
33
+ service: 'my-api',
34
+ environment: env.ENVIRONMENT,
35
+ headers: request.headers, // continues inbound traceparent if present
36
+ },
37
+ async (logger) => handle(request, env, logger),
38
+ {
39
+ onError: (_err, logger) => {
40
+ logger.error(_err, 'unhandled')
41
+ return new Response('Internal error', { status: 500 })
42
+ },
43
+ }
44
+ ),
45
+ }
46
+
47
+ async function handle(request: Request, env: Env, logger: Logger) {
48
+ logger.info('handling request')
49
+ return logger.span('db.query', { kind: 'client' }, async (logger) => {
50
+ // ... use logger.tracingHeaders() on outbound fetches to propagate the trace
51
+ return new Response('ok')
52
+ })
53
+ }
54
+ ```
55
+
56
+ ## Tail consumer usage
57
+
58
+ A minimal Worker:
59
+
60
+ ```ts
61
+ // src/index.ts
62
+ import { createTailHandler } from 'workers-axiom/tail'
63
+
64
+ interface Env {
65
+ AXIOM_TOKEN: string
66
+ AXIOM_DATASET: string
67
+ }
68
+
69
+ export default {
70
+ tail: (events: TraceItem[], env: Env, ctx: ExecutionContext) =>
71
+ createTailHandler({
72
+ axiomToken: env.AXIOM_TOKEN,
73
+ axiomDataset: env.AXIOM_DATASET,
74
+ })(events, env, ctx),
75
+ }
76
+ ```
77
+
78
+ ```jsonc
79
+ // wrangler.jsonc for the tail worker
80
+ {
81
+ "name": "my-tail-worker",
82
+ "main": "src/index.ts",
83
+ "compatibility_date": "2026-01-01",
84
+ "vars": { "AXIOM_DATASET": "my-dataset" }
85
+ // AXIOM_TOKEN set via: wrangler secret put AXIOM_TOKEN
86
+ }
87
+ ```
88
+
89
+ Then opt each producing worker in:
90
+
91
+ ```jsonc
92
+ // wrangler.jsonc for a producer worker
93
+ {
94
+ "tail_consumers": [{ "service": "my-tail-worker" }]
95
+ }
96
+ ```
97
+
98
+ ## How it works
99
+
100
+ Three event types flow through `console.log` from producer to tail:
101
+
102
+ - **`type: "log"` / `"metric"` / `"error"`** — forwarded to Axiom's ingest endpoint (`https://us-east-1.aws.edge.axiom.co/v1/ingest/{dataset}` by default).
103
+ - **`type: "span"`** — wire format defined in `workers-axiom/protocol`. The tail worker filters by `sampled === true`, converts to OTLP, and POSTs to `https://api.axiom.co/v1/traces`.
104
+ - **`type: "summary_properties"`** — emitted by `logger.summary({ ... })`. Merged onto a synthesized `invocation_summary` event the tail worker writes for every worker invocation (with CPU/wall time, request metadata from `event.event`, and `trace_id`).
105
+
106
+ Sampling is decided once at the trace root, propagated via `traceparent`, and stamped on every span. Logs, metrics, and errors are forwarded unconditionally — sampling gates traces only.
107
+
108
+ ## Config reference
109
+
110
+ ### `createTailHandler(config)`
111
+
112
+ | Field | Required | Default | Notes |
113
+ |---|---|---|---|
114
+ | `axiomToken` | yes | — | Axiom API token, bearer-auth. |
115
+ | `axiomDataset` | yes | — | Dataset name for both ingest and OTLP traces. |
116
+ | `ingestBaseUrl` | no | `https://us-east-1.aws.edge.axiom.co/v1/ingest` | Override for EU edge or self-hosted Axiom. Dataset name is appended. |
117
+ | `tracesEndpoint` | no | `https://api.axiom.co/v1/traces` | Full URL of the OTLP traces endpoint. |
118
+
119
+ ### `withTrace(options, fn, hooks?)` / `createLogger(options)`
120
+
121
+ | Field | Required | Default | Notes |
122
+ |---|---|---|---|
123
+ | `service` | yes | — | OTel `service.name`. |
124
+ | `environment` | no | — | OTel `deployment.environment`. `"development"` enables pretty-printed logs and suppresses metrics. |
125
+ | `level` | no | `"info"` | Log level. Forced to `"debug"` when `environment === "development"`. |
126
+ | `context` | no | `{}` | Correlation fields merged into every emitted record. |
127
+ | `isExpectedError` | no | — | Predicate marking expected/business errors so spans aren't flagged as failed. |
128
+ | `headers` | no | — | Inbound `Request.headers`. Continues `traceparent` if present. |
129
+ | `sampleRate` | no | `1` | Trace-root sampling probability. Inbound traces inherit the upstream verdict. |
130
+ | `kv` | no | — | KV namespace for dynamic log-level lookup at key `logLevel` (or `logLevel:{logLevelKey}`). |
131
+ | `name` | yes (`withTrace`) | — | Root span name, e.g. `"api.fetch"`, `"scheduled.tick"`. |
132
+ | `kind` | no (`withTrace`) | `"server"` | Use `"consumer"` for queue/cron handlers. |
133
+
134
+ ## Outbound trace propagation
135
+
136
+ The logger doesn't auto-instrument outbound `fetch`. Wrap each outbound call in `logger.span(...)` and copy `logger.tracingHeaders()` onto the request — that's what makes the downstream service join the same trace:
137
+
138
+ ```ts
139
+ await logger.span('backend.fetch', { kind: 'client' }, async (logger) => {
140
+ const headers = new Headers(init.headers)
141
+ for (const [k, v] of logger.tracingHeaders()) headers.set(k, v)
142
+ return fetch(url, { ...init, headers })
143
+ })
144
+ ```
145
+
146
+ `tracingHeaders()` on an unbound root logger returns an empty `Headers` — you must be inside a `.span(...)` for propagation to fire.
147
+
148
+ ## Limitations
149
+
150
+ - Axiom-specific. There is no sink abstraction; the tail worker speaks Axiom's ingest API and OTLP/HTTP JSON. If you need a different backend, fork the `tail/` directory.
151
+ - No browser entry. This package is server-side only, targeted at Cloudflare Workers (and works in any environment with `crypto.getRandomValues` and `console.log`).
152
+ - The `tail()` handler runs forwarding synchronously, not via `waitUntil`, so ingest failures surface in tail logs.
153
+
154
+ ## License
155
+
156
+ MIT
@@ -0,0 +1,4 @@
1
+ export { LogLevel, createLogger, noopLogger, withTrace, type KVLike, type LogContext, type Logger, type LoggerOptions, type WithTraceOptions, } from './logger';
2
+ export type { SpanOptions, TraceContext } from './tracing';
3
+ export { SPAN_EVENT_TYPE, SUMMARY_PROPERTIES_TYPE, isSpanEvent, parseTraceparent, formatTraceparent, type AttributeValue, type SpanEvent, type SpanKind, type SpanStatus, type TraceParent, } from '../protocol';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/producer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,SAAS,EACT,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,UAAU,CAAA;AAEjB,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAI1D,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,aAAa,CAAA"}
@@ -0,0 +1,5 @@
1
+ export { LogLevel, createLogger, noopLogger, withTrace, } from './logger';
2
+ // Re-export wire-format types that consumers commonly need when extending
3
+ // the producer (custom attributes, propagation helpers in middleware, etc.).
4
+ export { SPAN_EVENT_TYPE, SUMMARY_PROPERTIES_TYPE, isSpanEvent, parseTraceparent, formatTraceparent, } from '../protocol';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/producer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,SAAS,GAMV,MAAM,UAAU,CAAA;AAIjB,0EAA0E;AAC1E,6EAA6E;AAC7E,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAMlB,MAAM,aAAa,CAAA"}
@@ -0,0 +1,146 @@
1
+ import { type AttributeValue, type SpanKind } from '../protocol';
2
+ import { type SpanOptions, type TraceContext } from './tracing';
3
+ /**
4
+ * Bag of correlation fields (requestId, actorId, etc.). Has no semantic meaning
5
+ * to the logger — it's just merged into emitted JSON. First-class metadata
6
+ * (`service`, `environment`, trace IDs) lives on the logger directly, not here.
7
+ */
8
+ export type LogContext = Record<string, unknown>;
9
+ export interface Logger {
10
+ /** OTel `service.name`. */
11
+ readonly service: string;
12
+ /** OTel `deployment.environment`, if set. */
13
+ readonly environment: string | undefined;
14
+ readonly context: Readonly<LogContext>;
15
+ readonly trace: TraceContext;
16
+ debug(message: string): void;
17
+ info(message: string): void;
18
+ warn(message: string): void;
19
+ error(error: unknown, message?: string): void;
20
+ metric(event: string, data?: Record<string, unknown>): void;
21
+ /**
22
+ * Emit fields the tail worker should merge onto this invocation's
23
+ * `invocation_summary` event. Use for cross-cutting correlation fields
24
+ * (`requestId`, `trace_id`, identity, etc.) that should appear on the
25
+ * per-invocation summary regardless of which log/metric also carried them.
26
+ *
27
+ * Last-write-wins on collision per invocation in the tail worker.
28
+ */
29
+ summary(properties: Record<string, unknown>): void;
30
+ /** Extend the correlation context. Returns a new logger sharing trace state. */
31
+ child(context: LogContext): Logger;
32
+ /**
33
+ * Run an async function inside a new span. The child logger passed to `fn`
34
+ * has the new span's traceId/spanId bound, so any logs/metrics emitted
35
+ * inside automatically correlate with the span.
36
+ *
37
+ * Errors thrown by `fn` are recorded on the span and re-thrown unchanged.
38
+ * Errors matched by the `isExpectedError` predicate (configured at logger
39
+ * creation) are recorded as `status: 'ok'` — they're expected user-facing
40
+ * failures, not span failures.
41
+ */
42
+ span<T>(name: string, options: SpanOptions, fn: (logger: Logger) => Promise<T>): Promise<T>;
43
+ /**
44
+ * Returns headers to propagate the current trace context on outbound calls.
45
+ * Always include the result on outbound `fetch` calls (including service
46
+ * bindings) to maintain a single distributed trace across services.
47
+ */
48
+ tracingHeaders(): Headers;
49
+ }
50
+ export declare const LogLevel: {
51
+ readonly debug: 0;
52
+ readonly info: 1;
53
+ readonly warn: 2;
54
+ readonly error: 3;
55
+ };
56
+ export type LogLevel = keyof typeof LogLevel;
57
+ export declare function isValidLogLevel(value: unknown): value is LogLevel;
58
+ export interface KVLike {
59
+ get(key: string): Promise<string | null>;
60
+ }
61
+ export interface LoggerOptions {
62
+ /**
63
+ * Logical service name. Required on every logger because OpenTelemetry
64
+ * mandates `service.name` on every span; loggers without it would produce
65
+ * spans tagged `unknown_service` by collectors.
66
+ */
67
+ service: string;
68
+ /**
69
+ * Deployment environment. Maps to OTel `deployment.environment` on spans.
70
+ * When set to `'development'`, metrics are suppressed and logs are
71
+ * pretty-printed instead of emitted as JSON.
72
+ */
73
+ environment?: string;
74
+ /**
75
+ * Explicit log level. Used as the fallback when `kv` is also provided but
76
+ * doesn't contain a valid level. Defaults to `'info'`.
77
+ */
78
+ level?: LogLevel;
79
+ /** Additional correlation fields (requestId, etc.). */
80
+ context?: LogContext;
81
+ /**
82
+ * Predicate identifying expected/business errors that should not mark spans
83
+ * as failed. Typical use: `(err) => err instanceof MyExpectedError`. The
84
+ * library stays domain-free; the predicate is the explicit contract.
85
+ */
86
+ isExpectedError?: (err: unknown) => boolean;
87
+ /**
88
+ * Inbound headers carrying `traceparent`. When present, the logger continues
89
+ * the inbound trace; otherwise it starts a fresh one. Pass at HTTP entrypoints.
90
+ */
91
+ headers?: Headers;
92
+ /**
93
+ * Probability (0..1) of sampling a freshly minted trace. The verdict is
94
+ * decided once at the trace root, propagated to all descendants via
95
+ * `traceparent`, and stamped onto every emitted record. Inbound traces
96
+ * inherit the upstream verdict and ignore this. Defaults to 1 (sample all).
97
+ *
98
+ * Logs/metrics/errors are always forwarded regardless — only span forwarding
99
+ * to Axiom's traces store is gated by the verdict.
100
+ */
101
+ sampleRate?: number;
102
+ /**
103
+ * KV namespace for log-level lookup. When set, the logger reads `logLevel`
104
+ * (or `logLevel:{logLevelKey}` if a suffix is provided) from KV and uses
105
+ * that level if valid; otherwise falls back to `level`. Forced to `'debug'`
106
+ * in development.
107
+ */
108
+ kv?: KVLike;
109
+ /** Optional KV key suffix; looks up `logLevel:{logLevelKey}` instead of `logLevel`. */
110
+ logLevelKey?: string;
111
+ }
112
+ /**
113
+ * Create a new logger. If `options.headers` carries a `traceparent`, the trace
114
+ * is continued; otherwise a fresh trace starts.
115
+ *
116
+ * Async because the log level may be resolved from KV. If `options.kv` is
117
+ * omitted, no I/O happens but the function is still async for shape consistency.
118
+ *
119
+ * Most entrypoints should use `withTrace` instead, which calls `createLogger`
120
+ * and wraps the handler in a root span. `createLogger` is the right primitive
121
+ * only when there's no enclosing async scope to open a span around.
122
+ */
123
+ export declare function createLogger(options: LoggerOptions): Promise<Logger>;
124
+ export interface WithTraceOptions extends LoggerOptions {
125
+ /** Span name. Use the entrypoint's logical operation, e.g. `api.fetch`, `scheduled.tick`. */
126
+ name: string;
127
+ /** Span kind. Defaults to `'server'`. Use `'consumer'` for queue/cron. */
128
+ kind?: SpanKind;
129
+ /** Attributes to attach to the root span. */
130
+ attributes?: Record<string, AttributeValue>;
131
+ }
132
+ /**
133
+ * Entrypoint helper: build a logger and wrap the handler in a root span in one
134
+ * call. The root span is what local child spans (`logger.span(...)`) parent to,
135
+ * so without it those children are orphaned in the trace viewer.
136
+ *
137
+ * For HTTP entrypoints, pass `headers` to continue any inbound `traceparent`.
138
+ * For queue/cron entrypoints, omit `headers` and the trace starts fresh.
139
+ * Pass `kv` to resolve the log level from KV.
140
+ */
141
+ export declare function withTrace<T>(options: WithTraceOptions, fn: (logger: Logger) => Promise<T>, hooks?: {
142
+ onError?: (err: unknown, logger: Logger) => T | Promise<T>;
143
+ }): Promise<T>;
144
+ /** No-op logger for tests and environments where logging should be suppressed. */
145
+ export declare const noopLogger: Logger;
146
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/producer/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,179 @@
1
+ import { formatTraceparent, generateTraceId, parseTraceparent, SUMMARY_PROPERTIES_TYPE, } from '../protocol';
2
+ import { createClock, runSpan, toSpanException, } from './tracing';
3
+ const BASE_LOG_LEVEL_KEY = 'logLevel';
4
+ export const LogLevel = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ };
10
+ export function isValidLogLevel(value) {
11
+ return typeof value === 'string' && value in LogLevel;
12
+ }
13
+ /**
14
+ * Create a new logger. If `options.headers` carries a `traceparent`, the trace
15
+ * is continued; otherwise a fresh trace starts.
16
+ *
17
+ * Async because the log level may be resolved from KV. If `options.kv` is
18
+ * omitted, no I/O happens but the function is still async for shape consistency.
19
+ *
20
+ * Most entrypoints should use `withTrace` instead, which calls `createLogger`
21
+ * and wraps the handler in a root span. `createLogger` is the right primitive
22
+ * only when there's no enclosing async scope to open a span around.
23
+ */
24
+ export async function createLogger(options) {
25
+ const level = await resolveLogLevel(options);
26
+ const incoming = options.headers
27
+ ? parseTraceparent(options.headers.get('traceparent'))
28
+ : undefined;
29
+ const sampled = incoming?.sampled ?? Math.random() < (options.sampleRate ?? 1);
30
+ return _createLogger({ ...options, level }, createClock(), {
31
+ trace_id: incoming?.trace_id ?? generateTraceId(),
32
+ span_id: undefined,
33
+ parent_span_id: incoming?.span_id,
34
+ sampled,
35
+ });
36
+ }
37
+ async function resolveLogLevel(opts) {
38
+ if (opts.environment === 'development')
39
+ return 'debug';
40
+ if (!opts.kv)
41
+ return opts.level ?? 'info';
42
+ const key = opts.logLevelKey ? `${BASE_LOG_LEVEL_KEY}:${opts.logLevelKey}` : BASE_LOG_LEVEL_KEY;
43
+ const value = await opts.kv.get(key);
44
+ return isValidLogLevel(value) ? value : (opts.level ?? 'info');
45
+ }
46
+ function _createLogger(options, clock, trace) {
47
+ const { service, environment, isExpectedError, level = 'info' } = options;
48
+ const context = { ...options.context };
49
+ const isDev = environment === 'development';
50
+ const shouldLog = (logLevel) => {
51
+ return LogLevel[logLevel] >= LogLevel[level];
52
+ };
53
+ const emit = (entry) => {
54
+ // eslint-disable-next-line no-console
55
+ console.log(JSON.stringify({
56
+ service,
57
+ environment,
58
+ ...context,
59
+ trace_id: trace.trace_id,
60
+ span_id: trace.span_id,
61
+ parent_span_id: trace.parent_span_id,
62
+ sampled: trace.sampled,
63
+ ...entry,
64
+ }));
65
+ };
66
+ const log = (logLevel, message) => {
67
+ if (!shouldLog(logLevel))
68
+ return;
69
+ if (isDev) {
70
+ const levelTag = logLevel.toUpperCase().padEnd(5);
71
+ // eslint-disable-next-line no-console
72
+ console.log(`${levelTag} ${message}`);
73
+ }
74
+ else {
75
+ emit({ type: 'log', level: logLevel, message });
76
+ }
77
+ };
78
+ return {
79
+ service,
80
+ environment,
81
+ context,
82
+ trace,
83
+ debug(message) {
84
+ log('debug', message);
85
+ },
86
+ info(message) {
87
+ log('info', message);
88
+ },
89
+ warn(message) {
90
+ log('warn', message);
91
+ },
92
+ error(error, message) {
93
+ if (!shouldLog('error'))
94
+ return;
95
+ const exception = error instanceof Error ? toSpanException(error) : undefined;
96
+ const body = message ?? (error instanceof Error ? error.message : String(error));
97
+ if (isDev) {
98
+ // eslint-disable-next-line no-console
99
+ console.log(`ERROR ${body}${exception?.stacktrace ? `\n${exception.stacktrace}` : ''}`);
100
+ }
101
+ else {
102
+ emit({ type: 'error', message: body, ...(exception !== undefined ? { exception } : {}) });
103
+ }
104
+ },
105
+ metric(event, data) {
106
+ if (isDev)
107
+ return;
108
+ emit({ type: 'metric', event, ...data });
109
+ },
110
+ summary(properties) {
111
+ // Bypass `emit` so trace-context, service, environment, and inherited
112
+ // context don't ride along. Summary records are invocation-scoped and
113
+ // exist only to feed `invocation_summary` in the tail worker.
114
+ // eslint-disable-next-line no-console
115
+ console.log(JSON.stringify({ type: SUMMARY_PROPERTIES_TYPE, ...properties }));
116
+ },
117
+ child(newContext) {
118
+ return _createLogger({ ...options, context: { ...context, ...newContext } }, clock, trace);
119
+ },
120
+ async span(name, spanOptions, fn) {
121
+ return runSpan({
122
+ parent: trace,
123
+ resource: { service, environment },
124
+ name,
125
+ options: spanOptions,
126
+ clock,
127
+ isExpectedError,
128
+ fn: (childCtx) => fn(_createLogger(options, clock, childCtx)),
129
+ onUnexpectedError: (err, childCtx) => _createLogger(options, clock, childCtx).error(err, `span "${name}" failed`),
130
+ });
131
+ },
132
+ tracingHeaders() {
133
+ const headers = new Headers();
134
+ if (trace.span_id !== undefined) {
135
+ headers.set('traceparent', formatTraceparent(trace.trace_id, trace.span_id, trace.sampled));
136
+ }
137
+ return headers;
138
+ },
139
+ };
140
+ }
141
+ /**
142
+ * Entrypoint helper: build a logger and wrap the handler in a root span in one
143
+ * call. The root span is what local child spans (`logger.span(...)`) parent to,
144
+ * so without it those children are orphaned in the trace viewer.
145
+ *
146
+ * For HTTP entrypoints, pass `headers` to continue any inbound `traceparent`.
147
+ * For queue/cron entrypoints, omit `headers` and the trace starts fresh.
148
+ * Pass `kv` to resolve the log level from KV.
149
+ */
150
+ export async function withTrace(options, fn, hooks) {
151
+ const { name, kind = 'server', attributes, ...loggerOptions } = options;
152
+ const logger = await createLogger(loggerOptions);
153
+ try {
154
+ return await logger.span(name, { kind, attributes }, fn);
155
+ }
156
+ catch (err) {
157
+ if (hooks?.onError) {
158
+ return await hooks.onError(err, logger);
159
+ }
160
+ throw err;
161
+ }
162
+ }
163
+ /** No-op logger for tests and environments where logging should be suppressed. */
164
+ export const noopLogger = {
165
+ service: '',
166
+ environment: undefined,
167
+ context: {},
168
+ trace: { trace_id: '', span_id: undefined, parent_span_id: undefined, sampled: false },
169
+ debug: () => { },
170
+ info: () => { },
171
+ warn: () => { },
172
+ error: () => { },
173
+ metric: () => { },
174
+ summary: () => { },
175
+ child: () => noopLogger,
176
+ span: (_name, _options, fn) => fn(noopLogger),
177
+ tracingHeaders: () => new Headers(),
178
+ };
179
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/producer/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Monotonic-anchored wall clock for span timing.
3
+ *
4
+ * Span timestamps come from a single anchor captured at root-logger creation:
5
+ * - `unixMsAtAnchor` — Date.now() at anchor time (wall clock)
6
+ * - `perfAtAnchor` — performance.now() at anchor time (monotonic, sub-ms)
7
+ *
8
+ * Subsequent reads compute `unixMsAtAnchor + (performance.now() - perfAtAnchor)`.
9
+ * This preserves sub-ms ordering within a request and avoids drift if Date.now()
10
+ * jumps mid-request (rare on Workers, but free to guard against).
11
+ *
12
+ * Cross-service clock skew is not addressed here — Workers in different colos may
13
+ * have small wall-clock differences. Tracing UIs tolerate this; it's not fixable
14
+ * from inside the worker.
15
+ */
16
+ export interface Clock {
17
+ /** Returns the current time as Unix epoch nanoseconds (string, no precision loss). */
18
+ nowUnixNano(): string;
19
+ }
20
+ export declare function createClock(): Clock;
21
+ //# sourceMappingURL=clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../../src/producer/tracing/clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,KAAK;IACpB,sFAAsF;IACtF,WAAW,IAAI,MAAM,CAAA;CACtB;AAED,wBAAgB,WAAW,IAAI,KAAK,CAWnC"}
@@ -0,0 +1,17 @@
1
+ export function createClock() {
2
+ const unixMsAtAnchor = Date.now();
3
+ const perfAtAnchor = performanceNowOrFallback();
4
+ return {
5
+ nowUnixNano() {
6
+ const elapsedMs = performanceNowOrFallback() - perfAtAnchor;
7
+ const unixMs = unixMsAtAnchor + elapsedMs;
8
+ return BigInt(Math.trunc(unixMs * 1_000_000)).toString();
9
+ },
10
+ };
11
+ }
12
+ function performanceNowOrFallback() {
13
+ return typeof performance !== 'undefined' && typeof performance.now === 'function'
14
+ ? performance.now()
15
+ : Date.now();
16
+ }
17
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../../../src/producer/tracing/clock.ts"],"names":[],"mappings":"AAoBA,MAAM,UAAU,WAAW;IACzB,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAA;IAE/C,OAAO;QACL,WAAW;YACT,MAAM,SAAS,GAAG,wBAAwB,EAAE,GAAG,YAAY,CAAA;YAC3D,MAAM,MAAM,GAAG,cAAc,GAAG,SAAS,CAAA;YACzC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC1D,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,wBAAwB;IAC/B,OAAO,OAAO,WAAW,KAAK,WAAW,IAAI,OAAO,WAAW,CAAC,GAAG,KAAK,UAAU;QAChF,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE;QACnB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { createClock, type Clock } from './clock';
2
+ export { runSpan, toSpanException, type ChildTraceContext, type SpanOptions, type TraceContext, } from './span';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/producer/tracing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EACL,OAAO,EACP,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,QAAQ,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { createClock } from './clock';
2
+ export { runSpan, toSpanException, } from './span';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/producer/tracing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAA;AACjD,OAAO,EACL,OAAO,EACP,eAAe,GAIhB,MAAM,QAAQ,CAAA"}