@fabbahiense/pulsar-pino-transport 0.2.1 → 0.4.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/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +205 -110
- package/dist/index.cjs +1438 -86
- package/dist/index.d.cts +278 -4
- package/dist/index.d.ts +278 -4
- package/dist/index.js +1423 -85
- package/dist/middleware.cjs +387 -0
- package/dist/middleware.d.cts +70 -0
- package/dist/middleware.d.ts +70 -0
- package/dist/middleware.js +360 -0
- package/package.json +35 -8
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,269 @@
|
|
|
1
1
|
import * as pino_abstract_transport from 'pino-abstract-transport';
|
|
2
2
|
import * as node_stream from 'node:stream';
|
|
3
|
+
import { PinoLikeLogger } from './middleware.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Distributed trace context shared by the Node.js SDKs (bundled into each
|
|
7
|
+
* SDK's dist; not public API by itself: each SDK re-exports what it offers).
|
|
8
|
+
*
|
|
9
|
+
* - The context of the operation in progress (`traceId`, `spanId`,
|
|
10
|
+
* `parentSpanId`, the W3C `sampled` flag and `tracestate`) lives in an
|
|
11
|
+
* `AsyncLocalStorage`. That store is shared through a process-wide registry,
|
|
12
|
+
* so every SDK copy loaded in the process (pulsar-node, pulsar-next, the
|
|
13
|
+
* pino helpers) sees the same context.
|
|
14
|
+
* - Inbound: W3C `traceparent` (with `tracestate`) and the legacy
|
|
15
|
+
* `x-trace-id` header. An `x-trace-id` value always names the trace, as it
|
|
16
|
+
* did before; a `traceparent` of the same trace supplies the parent span.
|
|
17
|
+
* - Outbound: `traceparent` plus `x-trace-id`, so services on older SDKs keep
|
|
18
|
+
* following the same trace id.
|
|
19
|
+
* - Spans: `runSpan()` runs a function in a child span and reports it to a
|
|
20
|
+
* sink when it settles; each SDK turns that into a span-end log entry.
|
|
21
|
+
*
|
|
22
|
+
* Every helper here is total where it touches the host's traffic: header
|
|
23
|
+
* parsing never throws, and instrumentation failures never break a request.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** The trace context of the operation in progress. */
|
|
27
|
+
interface TraceContext {
|
|
28
|
+
/**
|
|
29
|
+
* Groups the entries of one distributed operation. Traces Pulsar starts use
|
|
30
|
+
* a W3C trace id (32 lowercase hex characters); an inbound `x-trace-id`
|
|
31
|
+
* value is kept exactly as it was sent.
|
|
32
|
+
*/
|
|
33
|
+
traceId: string;
|
|
34
|
+
/** The current span: 16 lowercase hex characters. */
|
|
35
|
+
spanId: string;
|
|
36
|
+
/** The span this one is a child of, when it has one. */
|
|
37
|
+
parentSpanId?: string;
|
|
38
|
+
/** The W3C sampled flag, propagated as received. Pulsar sends every log regardless of it. */
|
|
39
|
+
sampled: boolean;
|
|
40
|
+
/** The inbound W3C `tracestate`, passed through unchanged to outgoing calls. */
|
|
41
|
+
traceState?: string;
|
|
42
|
+
/** HTTP method of the request, attached to entries that do not set their own. */
|
|
43
|
+
method?: string;
|
|
44
|
+
/** URL of the request, attached to entries that do not set their own. */
|
|
45
|
+
url?: string;
|
|
46
|
+
}
|
|
47
|
+
/** A context to run with: missing ids are generated (a new trace, a new span). */
|
|
48
|
+
interface TraceContextInit {
|
|
49
|
+
traceId?: string;
|
|
50
|
+
spanId?: string;
|
|
51
|
+
parentSpanId?: string;
|
|
52
|
+
sampled?: boolean;
|
|
53
|
+
traceState?: string;
|
|
54
|
+
method?: string;
|
|
55
|
+
url?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A trace context read from a carrier (headers, job data). `spanId` is the
|
|
59
|
+
* span that injected it; it is absent when the carrier only had an
|
|
60
|
+
* `x-trace-id`, so spans started under it have no parent.
|
|
61
|
+
*/
|
|
62
|
+
interface ExtractedTrace {
|
|
63
|
+
traceId: string;
|
|
64
|
+
spanId?: string;
|
|
65
|
+
sampled: boolean;
|
|
66
|
+
traceState?: string;
|
|
67
|
+
}
|
|
68
|
+
/** A parsed W3C `traceparent` header. */
|
|
69
|
+
interface Traceparent {
|
|
70
|
+
/** Two lowercase hex characters; `00` today, later versions are accepted. */
|
|
71
|
+
version: string;
|
|
72
|
+
traceId: string;
|
|
73
|
+
/** The caller's span id (`parent-id` in the specification). */
|
|
74
|
+
parentId: string;
|
|
75
|
+
/** The trace-flags byte. */
|
|
76
|
+
flags: number;
|
|
77
|
+
/** Bit 0 of the flags. */
|
|
78
|
+
sampled: boolean;
|
|
79
|
+
}
|
|
80
|
+
type SpanKind = 'server' | 'client' | 'internal' | 'producer' | 'consumer';
|
|
81
|
+
/** A span that ended, as handed to a {@link SpanSink}. */
|
|
82
|
+
interface FinishedSpan {
|
|
83
|
+
/** The span's name; it becomes the entry's `msg`. */
|
|
84
|
+
name: string;
|
|
85
|
+
kind: SpanKind;
|
|
86
|
+
context: TraceContext;
|
|
87
|
+
/** Start and end, in epoch milliseconds (fractional). */
|
|
88
|
+
start: number;
|
|
89
|
+
end: number;
|
|
90
|
+
/** `end - start`, in milliseconds, rounded to 3 decimals. */
|
|
91
|
+
duration: number;
|
|
92
|
+
/** What the function threw or rejected with, if it failed. */
|
|
93
|
+
error?: unknown;
|
|
94
|
+
attributes?: Record<string, unknown>;
|
|
95
|
+
method?: string;
|
|
96
|
+
url?: string;
|
|
97
|
+
statusCode?: number;
|
|
98
|
+
serviceName?: string;
|
|
99
|
+
}
|
|
100
|
+
/** Receives finished spans; each SDK logs them as span-end entries. */
|
|
101
|
+
type SpanSink = (span: FinishedSpan) => void;
|
|
102
|
+
interface SpanOptions {
|
|
103
|
+
/**
|
|
104
|
+
* The span to start under. Defaults to the current context; pass the result
|
|
105
|
+
* of `extractTrace()` to continue a trace received through a queue, or
|
|
106
|
+
* `null` to start a new trace.
|
|
107
|
+
*/
|
|
108
|
+
parent?: TraceContextInit | ExtractedTrace | null;
|
|
109
|
+
/** Stored as the entry's metadata. */
|
|
110
|
+
attributes?: Record<string, unknown>;
|
|
111
|
+
/** Default `internal`. */
|
|
112
|
+
kind?: SpanKind;
|
|
113
|
+
/** Service name of the span-end entry; defaults to the SDK's. */
|
|
114
|
+
serviceName?: string;
|
|
115
|
+
}
|
|
116
|
+
interface OutboundOptions {
|
|
117
|
+
/**
|
|
118
|
+
* Log one `client` span-end entry per call (method, URL without its query
|
|
119
|
+
* string, status, duration) and propagate that span, so the called service
|
|
120
|
+
* nests under it. Default true. With `false`, or when nothing can log it,
|
|
121
|
+
* the current span is propagated as it is.
|
|
122
|
+
*/
|
|
123
|
+
spans?: boolean;
|
|
124
|
+
/** Service name of the client span entries; defaults to the SDK's. */
|
|
125
|
+
serviceName?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Parses a W3C `traceparent` header. Returns null for anything the
|
|
129
|
+
* specification says to ignore: a malformed value, uppercase hex, version
|
|
130
|
+
* `ff`, a version-00 value with trailing data, or an all-zero trace or
|
|
131
|
+
* parent id. Later versions are accepted when their first four fields
|
|
132
|
+
* parse and anything after them starts with `-`.
|
|
133
|
+
*/
|
|
134
|
+
declare function parseTraceparent(value: unknown): Traceparent | null;
|
|
135
|
+
/** Formats a version-00 `traceparent` for a context (ids converted to their W3C form). */
|
|
136
|
+
declare function formatTraceparent(ctx: {
|
|
137
|
+
traceId: string;
|
|
138
|
+
spanId: string;
|
|
139
|
+
sampled?: boolean;
|
|
140
|
+
}): string;
|
|
141
|
+
/** The context of the current asynchronous flow, or null outside one. */
|
|
142
|
+
declare function getTraceContext(): TraceContext | null;
|
|
143
|
+
/**
|
|
144
|
+
* Runs `fn` with `ctx` as the current trace context (missing ids generated:
|
|
145
|
+
* pass null for a new trace). Every entry logged inside, including in async
|
|
146
|
+
* work started there, carries its ids.
|
|
147
|
+
*/
|
|
148
|
+
declare function runWithTrace<T>(ctx: TraceContextInit | ExtractedTrace | null | undefined, fn: () => T): T;
|
|
149
|
+
/**
|
|
150
|
+
* Reads a trace context from headers or job data:
|
|
151
|
+
* - an `x-trace-id` names the trace, as it always has; a `traceparent` of the
|
|
152
|
+
* same trace (compared through {@link toW3CTraceId}) supplies the span and
|
|
153
|
+
* the sampled flag, and `tracestate` comes along;
|
|
154
|
+
* - otherwise a valid `traceparent` does;
|
|
155
|
+
* - otherwise null.
|
|
156
|
+
* The result is the span that sent it: start a child of it (the request
|
|
157
|
+
* middlewares, `startSpan(name, fn, { parent })`) or run in it (`runWithTrace`).
|
|
158
|
+
*/
|
|
159
|
+
declare function extractTrace(carrier: unknown): ExtractedTrace | null;
|
|
160
|
+
/**
|
|
161
|
+
* The propagation headers for a context (default: the current one):
|
|
162
|
+
* `traceparent`, `x-trace-id`, and `tracestate` when the trace has one. Empty
|
|
163
|
+
* outside a trace. Spread them into any HTTP client's headers, for example
|
|
164
|
+
* Node's `http.request(url, { headers: { ...traceHeaders() } })`.
|
|
165
|
+
*/
|
|
166
|
+
declare function traceHeaders(ctx?: TraceContext | null): Record<string, string>;
|
|
167
|
+
/**
|
|
168
|
+
* Writes the propagation fields of a context (default: the current one) into
|
|
169
|
+
* `carrier`, a plain object such as a job's data or anything with
|
|
170
|
+
* `set(name, value)` (fetch `Headers`, a `Map`). Returns the carrier. Outside
|
|
171
|
+
* a trace it is returned unchanged. The current span is injected as it is:
|
|
172
|
+
* the consumer's span becomes its child (see {@link extractTrace}).
|
|
173
|
+
*/
|
|
174
|
+
declare function injectTrace<T extends object>(carrier: T, ctx?: TraceContext | null): T;
|
|
175
|
+
/** The parts of an axios instance the interceptor uses (axios is not a dependency). */
|
|
176
|
+
interface AxiosLike {
|
|
177
|
+
interceptors: {
|
|
178
|
+
request: {
|
|
179
|
+
use(onFulfilled: (config: any) => any, onRejected?: (error: any) => any): unknown;
|
|
180
|
+
};
|
|
181
|
+
response: {
|
|
182
|
+
use(onFulfilled: (response: any) => any, onRejected?: (error: any) => any): unknown;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Distributed tracing for pino. pino runs this transport in a worker thread,
|
|
189
|
+
* where the application's AsyncLocalStorage is out of reach, so the trace ids
|
|
190
|
+
* have to be written into each record in the main thread: `pulsarMixin()`
|
|
191
|
+
* does that through pino's `mixin` option.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import pino from 'pino'
|
|
196
|
+
* import { pulsarMixin } from '@fabbahiense/pulsar-pino-transport'
|
|
197
|
+
*
|
|
198
|
+
* const logger = pino({
|
|
199
|
+
* mixin: pulsarMixin(),
|
|
200
|
+
* transport: { target: '@fabbahiense/pulsar-pino-transport', options: { url, apiKey } },
|
|
201
|
+
* })
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
/** The trace fields `pulsarMixin()` adds to a record. */
|
|
206
|
+
interface PulsarMixinFields {
|
|
207
|
+
traceId?: string;
|
|
208
|
+
spanId?: string;
|
|
209
|
+
parentSpanId?: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* A pino `mixin` that adds the current trace context to every record:
|
|
213
|
+
* `traceId`, `spanId` and `parentSpanId` (nothing outside a trace). It runs
|
|
214
|
+
* in the application's thread, so the ids travel with the record to the
|
|
215
|
+
* transport worker. Fields set on the log call itself win, as pino merges
|
|
216
|
+
* the mixin first.
|
|
217
|
+
*
|
|
218
|
+
* To combine it with a mixin of your own: `mixin: () => ({ ...pulsarMixin()(), ...mine() })`.
|
|
219
|
+
*/
|
|
220
|
+
declare function pulsarMixin(): () => PulsarMixinFields;
|
|
221
|
+
/**
|
|
222
|
+
* Logs finished spans through a pino logger, as records the transport maps to
|
|
223
|
+
* span-end entries: `msg` the name, `responseTime` the duration, the span ids
|
|
224
|
+
* and `spanKind` top level, `req`/`res` for HTTP client spans, `err` when it
|
|
225
|
+
* failed, and the attributes as `metadata`.
|
|
226
|
+
*/
|
|
227
|
+
declare function pinoSpanSink(logger: PinoLikeLogger): SpanSink;
|
|
228
|
+
/** Options of the pino `startSpan()`: the logger that writes the span-end entry. */
|
|
229
|
+
interface PinoSpanOptions extends SpanOptions {
|
|
230
|
+
/** Your pino logger (with the Pulsar transport configured). */
|
|
231
|
+
logger: PinoLikeLogger;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Runs `fn` in a new child span of the current one (or of `options.parent`,
|
|
235
|
+
* or in a new trace) and logs its span-end entry through `options.logger`
|
|
236
|
+
* when it returns or settles. Records logged inside (with `pulsarMixin()`)
|
|
237
|
+
* carry the new span's ids. The result or error is passed through unchanged.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* await startSpan('payments.charge', () => charge(order), { logger })
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
declare function startSpan<T>(name: string, fn: (span: TraceContext) => T, options: PinoSpanOptions): T;
|
|
245
|
+
/** Options of the pino outbound helpers. */
|
|
246
|
+
interface PinoOutboundOptions extends OutboundOptions {
|
|
247
|
+
/**
|
|
248
|
+
* Logs a `client` span-end entry per call through this logger. Without one,
|
|
249
|
+
* the current span is propagated as it is and nothing is logged.
|
|
250
|
+
*/
|
|
251
|
+
logger?: PinoLikeLogger;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Returns a fetch that propagates the trace: calls made inside a trace send
|
|
255
|
+
* `traceparent`, `tracestate` and `x-trace-id` (and, with `logger`, log a
|
|
256
|
+
* `client` span). Calls outside a trace are untouched. Nothing is patched;
|
|
257
|
+
* the fetch to wrap defaults to the global fetch as it is when this is called.
|
|
258
|
+
*/
|
|
259
|
+
declare function instrumentFetch(options?: PinoOutboundOptions): typeof fetch;
|
|
260
|
+
declare function instrumentFetch(fetchImpl: typeof fetch, options?: PinoOutboundOptions): typeof fetch;
|
|
261
|
+
/**
|
|
262
|
+
* Adds interceptors to an axios instance (duck-typed: axios is not a
|
|
263
|
+
* dependency) that propagate the trace like {@link instrumentFetch}.
|
|
264
|
+
* Returns the instance.
|
|
265
|
+
*/
|
|
266
|
+
declare function instrumentAxios<T extends AxiosLike>(instance: T, options?: PinoOutboundOptions): T;
|
|
3
267
|
|
|
4
268
|
interface PulsarTransportOptions {
|
|
5
269
|
/** Pulsar server URL (e.g., 'https://pulsar.example.com') */
|
|
@@ -10,10 +274,20 @@ interface PulsarTransportOptions {
|
|
|
10
274
|
source?: string;
|
|
11
275
|
/** Alias for source */
|
|
12
276
|
serviceName?: string;
|
|
13
|
-
/**
|
|
277
|
+
/** Buffered logs that trigger an immediate send (default: 50, max: 1000) */
|
|
14
278
|
batchSize?: number;
|
|
15
|
-
/**
|
|
279
|
+
/** Longest a log waits before it is sent, in milliseconds (default: 2000) */
|
|
16
280
|
flushInterval?: number;
|
|
281
|
+
/** Most logs held in memory while the server is slow or down (default: 5000). When full, the oldest are dropped and counted. */
|
|
282
|
+
maxBufferSize?: number;
|
|
283
|
+
/** Retries of a failing batch (429, 408, 5xx, network, timeout) before it is dropped; a batch is sent at most `maxRetries + 1` times (default: 10) */
|
|
284
|
+
maxRetries?: number;
|
|
285
|
+
/** Timeout per HTTP request, in milliseconds (default: 10000) */
|
|
286
|
+
requestTimeout?: number;
|
|
287
|
+
/** Longest the final flush waits when the logger is closed, in milliseconds (default: 3000) */
|
|
288
|
+
shutdownTimeout?: number;
|
|
289
|
+
/** Write a line to stderr (at most once a minute) when logs are dropped (default: true) */
|
|
290
|
+
warnOnDrop?: boolean;
|
|
17
291
|
}
|
|
18
292
|
/**
|
|
19
293
|
* Creates a Pino transport that sends logs to a Pulsar server.
|
|
@@ -21,7 +295,7 @@ interface PulsarTransportOptions {
|
|
|
21
295
|
* @example
|
|
22
296
|
* ```ts
|
|
23
297
|
* import pino from 'pino'
|
|
24
|
-
* import { createPulsarTransport } from '@pulsar
|
|
298
|
+
* import { createPulsarTransport } from '@fabbahiense/pulsar-pino-transport'
|
|
25
299
|
*
|
|
26
300
|
* const logger = pino(
|
|
27
301
|
* createPulsarTransport({
|
|
@@ -47,4 +321,4 @@ declare function createPulsarTransport(options: PulsarTransportOptions): {
|
|
|
47
321
|
};
|
|
48
322
|
declare function export_default(options: PulsarTransportOptions): Promise<node_stream.Transform & pino_abstract_transport.OnUnknown>;
|
|
49
323
|
|
|
50
|
-
export { type PulsarTransportOptions, createPulsarTransport, export_default as default };
|
|
324
|
+
export { type AxiosLike, type ExtractedTrace, type OutboundOptions, PinoLikeLogger, type PinoOutboundOptions, type PinoSpanOptions, type PulsarMixinFields, type PulsarTransportOptions, type SpanKind, type SpanOptions, type TraceContext, type TraceContextInit, type Traceparent, createPulsarTransport, export_default as default, extractTrace, formatTraceparent, getTraceContext, injectTrace, instrumentAxios, instrumentFetch, parseTraceparent, pinoSpanSink, pulsarMixin, runWithTrace, startSpan, traceHeaders };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,269 @@
|
|
|
1
1
|
import * as pino_abstract_transport from 'pino-abstract-transport';
|
|
2
2
|
import * as node_stream from 'node:stream';
|
|
3
|
+
import { PinoLikeLogger } from './middleware.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Distributed trace context shared by the Node.js SDKs (bundled into each
|
|
7
|
+
* SDK's dist; not public API by itself: each SDK re-exports what it offers).
|
|
8
|
+
*
|
|
9
|
+
* - The context of the operation in progress (`traceId`, `spanId`,
|
|
10
|
+
* `parentSpanId`, the W3C `sampled` flag and `tracestate`) lives in an
|
|
11
|
+
* `AsyncLocalStorage`. That store is shared through a process-wide registry,
|
|
12
|
+
* so every SDK copy loaded in the process (pulsar-node, pulsar-next, the
|
|
13
|
+
* pino helpers) sees the same context.
|
|
14
|
+
* - Inbound: W3C `traceparent` (with `tracestate`) and the legacy
|
|
15
|
+
* `x-trace-id` header. An `x-trace-id` value always names the trace, as it
|
|
16
|
+
* did before; a `traceparent` of the same trace supplies the parent span.
|
|
17
|
+
* - Outbound: `traceparent` plus `x-trace-id`, so services on older SDKs keep
|
|
18
|
+
* following the same trace id.
|
|
19
|
+
* - Spans: `runSpan()` runs a function in a child span and reports it to a
|
|
20
|
+
* sink when it settles; each SDK turns that into a span-end log entry.
|
|
21
|
+
*
|
|
22
|
+
* Every helper here is total where it touches the host's traffic: header
|
|
23
|
+
* parsing never throws, and instrumentation failures never break a request.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** The trace context of the operation in progress. */
|
|
27
|
+
interface TraceContext {
|
|
28
|
+
/**
|
|
29
|
+
* Groups the entries of one distributed operation. Traces Pulsar starts use
|
|
30
|
+
* a W3C trace id (32 lowercase hex characters); an inbound `x-trace-id`
|
|
31
|
+
* value is kept exactly as it was sent.
|
|
32
|
+
*/
|
|
33
|
+
traceId: string;
|
|
34
|
+
/** The current span: 16 lowercase hex characters. */
|
|
35
|
+
spanId: string;
|
|
36
|
+
/** The span this one is a child of, when it has one. */
|
|
37
|
+
parentSpanId?: string;
|
|
38
|
+
/** The W3C sampled flag, propagated as received. Pulsar sends every log regardless of it. */
|
|
39
|
+
sampled: boolean;
|
|
40
|
+
/** The inbound W3C `tracestate`, passed through unchanged to outgoing calls. */
|
|
41
|
+
traceState?: string;
|
|
42
|
+
/** HTTP method of the request, attached to entries that do not set their own. */
|
|
43
|
+
method?: string;
|
|
44
|
+
/** URL of the request, attached to entries that do not set their own. */
|
|
45
|
+
url?: string;
|
|
46
|
+
}
|
|
47
|
+
/** A context to run with: missing ids are generated (a new trace, a new span). */
|
|
48
|
+
interface TraceContextInit {
|
|
49
|
+
traceId?: string;
|
|
50
|
+
spanId?: string;
|
|
51
|
+
parentSpanId?: string;
|
|
52
|
+
sampled?: boolean;
|
|
53
|
+
traceState?: string;
|
|
54
|
+
method?: string;
|
|
55
|
+
url?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A trace context read from a carrier (headers, job data). `spanId` is the
|
|
59
|
+
* span that injected it; it is absent when the carrier only had an
|
|
60
|
+
* `x-trace-id`, so spans started under it have no parent.
|
|
61
|
+
*/
|
|
62
|
+
interface ExtractedTrace {
|
|
63
|
+
traceId: string;
|
|
64
|
+
spanId?: string;
|
|
65
|
+
sampled: boolean;
|
|
66
|
+
traceState?: string;
|
|
67
|
+
}
|
|
68
|
+
/** A parsed W3C `traceparent` header. */
|
|
69
|
+
interface Traceparent {
|
|
70
|
+
/** Two lowercase hex characters; `00` today, later versions are accepted. */
|
|
71
|
+
version: string;
|
|
72
|
+
traceId: string;
|
|
73
|
+
/** The caller's span id (`parent-id` in the specification). */
|
|
74
|
+
parentId: string;
|
|
75
|
+
/** The trace-flags byte. */
|
|
76
|
+
flags: number;
|
|
77
|
+
/** Bit 0 of the flags. */
|
|
78
|
+
sampled: boolean;
|
|
79
|
+
}
|
|
80
|
+
type SpanKind = 'server' | 'client' | 'internal' | 'producer' | 'consumer';
|
|
81
|
+
/** A span that ended, as handed to a {@link SpanSink}. */
|
|
82
|
+
interface FinishedSpan {
|
|
83
|
+
/** The span's name; it becomes the entry's `msg`. */
|
|
84
|
+
name: string;
|
|
85
|
+
kind: SpanKind;
|
|
86
|
+
context: TraceContext;
|
|
87
|
+
/** Start and end, in epoch milliseconds (fractional). */
|
|
88
|
+
start: number;
|
|
89
|
+
end: number;
|
|
90
|
+
/** `end - start`, in milliseconds, rounded to 3 decimals. */
|
|
91
|
+
duration: number;
|
|
92
|
+
/** What the function threw or rejected with, if it failed. */
|
|
93
|
+
error?: unknown;
|
|
94
|
+
attributes?: Record<string, unknown>;
|
|
95
|
+
method?: string;
|
|
96
|
+
url?: string;
|
|
97
|
+
statusCode?: number;
|
|
98
|
+
serviceName?: string;
|
|
99
|
+
}
|
|
100
|
+
/** Receives finished spans; each SDK logs them as span-end entries. */
|
|
101
|
+
type SpanSink = (span: FinishedSpan) => void;
|
|
102
|
+
interface SpanOptions {
|
|
103
|
+
/**
|
|
104
|
+
* The span to start under. Defaults to the current context; pass the result
|
|
105
|
+
* of `extractTrace()` to continue a trace received through a queue, or
|
|
106
|
+
* `null` to start a new trace.
|
|
107
|
+
*/
|
|
108
|
+
parent?: TraceContextInit | ExtractedTrace | null;
|
|
109
|
+
/** Stored as the entry's metadata. */
|
|
110
|
+
attributes?: Record<string, unknown>;
|
|
111
|
+
/** Default `internal`. */
|
|
112
|
+
kind?: SpanKind;
|
|
113
|
+
/** Service name of the span-end entry; defaults to the SDK's. */
|
|
114
|
+
serviceName?: string;
|
|
115
|
+
}
|
|
116
|
+
interface OutboundOptions {
|
|
117
|
+
/**
|
|
118
|
+
* Log one `client` span-end entry per call (method, URL without its query
|
|
119
|
+
* string, status, duration) and propagate that span, so the called service
|
|
120
|
+
* nests under it. Default true. With `false`, or when nothing can log it,
|
|
121
|
+
* the current span is propagated as it is.
|
|
122
|
+
*/
|
|
123
|
+
spans?: boolean;
|
|
124
|
+
/** Service name of the client span entries; defaults to the SDK's. */
|
|
125
|
+
serviceName?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Parses a W3C `traceparent` header. Returns null for anything the
|
|
129
|
+
* specification says to ignore: a malformed value, uppercase hex, version
|
|
130
|
+
* `ff`, a version-00 value with trailing data, or an all-zero trace or
|
|
131
|
+
* parent id. Later versions are accepted when their first four fields
|
|
132
|
+
* parse and anything after them starts with `-`.
|
|
133
|
+
*/
|
|
134
|
+
declare function parseTraceparent(value: unknown): Traceparent | null;
|
|
135
|
+
/** Formats a version-00 `traceparent` for a context (ids converted to their W3C form). */
|
|
136
|
+
declare function formatTraceparent(ctx: {
|
|
137
|
+
traceId: string;
|
|
138
|
+
spanId: string;
|
|
139
|
+
sampled?: boolean;
|
|
140
|
+
}): string;
|
|
141
|
+
/** The context of the current asynchronous flow, or null outside one. */
|
|
142
|
+
declare function getTraceContext(): TraceContext | null;
|
|
143
|
+
/**
|
|
144
|
+
* Runs `fn` with `ctx` as the current trace context (missing ids generated:
|
|
145
|
+
* pass null for a new trace). Every entry logged inside, including in async
|
|
146
|
+
* work started there, carries its ids.
|
|
147
|
+
*/
|
|
148
|
+
declare function runWithTrace<T>(ctx: TraceContextInit | ExtractedTrace | null | undefined, fn: () => T): T;
|
|
149
|
+
/**
|
|
150
|
+
* Reads a trace context from headers or job data:
|
|
151
|
+
* - an `x-trace-id` names the trace, as it always has; a `traceparent` of the
|
|
152
|
+
* same trace (compared through {@link toW3CTraceId}) supplies the span and
|
|
153
|
+
* the sampled flag, and `tracestate` comes along;
|
|
154
|
+
* - otherwise a valid `traceparent` does;
|
|
155
|
+
* - otherwise null.
|
|
156
|
+
* The result is the span that sent it: start a child of it (the request
|
|
157
|
+
* middlewares, `startSpan(name, fn, { parent })`) or run in it (`runWithTrace`).
|
|
158
|
+
*/
|
|
159
|
+
declare function extractTrace(carrier: unknown): ExtractedTrace | null;
|
|
160
|
+
/**
|
|
161
|
+
* The propagation headers for a context (default: the current one):
|
|
162
|
+
* `traceparent`, `x-trace-id`, and `tracestate` when the trace has one. Empty
|
|
163
|
+
* outside a trace. Spread them into any HTTP client's headers, for example
|
|
164
|
+
* Node's `http.request(url, { headers: { ...traceHeaders() } })`.
|
|
165
|
+
*/
|
|
166
|
+
declare function traceHeaders(ctx?: TraceContext | null): Record<string, string>;
|
|
167
|
+
/**
|
|
168
|
+
* Writes the propagation fields of a context (default: the current one) into
|
|
169
|
+
* `carrier`, a plain object such as a job's data or anything with
|
|
170
|
+
* `set(name, value)` (fetch `Headers`, a `Map`). Returns the carrier. Outside
|
|
171
|
+
* a trace it is returned unchanged. The current span is injected as it is:
|
|
172
|
+
* the consumer's span becomes its child (see {@link extractTrace}).
|
|
173
|
+
*/
|
|
174
|
+
declare function injectTrace<T extends object>(carrier: T, ctx?: TraceContext | null): T;
|
|
175
|
+
/** The parts of an axios instance the interceptor uses (axios is not a dependency). */
|
|
176
|
+
interface AxiosLike {
|
|
177
|
+
interceptors: {
|
|
178
|
+
request: {
|
|
179
|
+
use(onFulfilled: (config: any) => any, onRejected?: (error: any) => any): unknown;
|
|
180
|
+
};
|
|
181
|
+
response: {
|
|
182
|
+
use(onFulfilled: (response: any) => any, onRejected?: (error: any) => any): unknown;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Distributed tracing for pino. pino runs this transport in a worker thread,
|
|
189
|
+
* where the application's AsyncLocalStorage is out of reach, so the trace ids
|
|
190
|
+
* have to be written into each record in the main thread: `pulsarMixin()`
|
|
191
|
+
* does that through pino's `mixin` option.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import pino from 'pino'
|
|
196
|
+
* import { pulsarMixin } from '@fabbahiense/pulsar-pino-transport'
|
|
197
|
+
*
|
|
198
|
+
* const logger = pino({
|
|
199
|
+
* mixin: pulsarMixin(),
|
|
200
|
+
* transport: { target: '@fabbahiense/pulsar-pino-transport', options: { url, apiKey } },
|
|
201
|
+
* })
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
/** The trace fields `pulsarMixin()` adds to a record. */
|
|
206
|
+
interface PulsarMixinFields {
|
|
207
|
+
traceId?: string;
|
|
208
|
+
spanId?: string;
|
|
209
|
+
parentSpanId?: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* A pino `mixin` that adds the current trace context to every record:
|
|
213
|
+
* `traceId`, `spanId` and `parentSpanId` (nothing outside a trace). It runs
|
|
214
|
+
* in the application's thread, so the ids travel with the record to the
|
|
215
|
+
* transport worker. Fields set on the log call itself win, as pino merges
|
|
216
|
+
* the mixin first.
|
|
217
|
+
*
|
|
218
|
+
* To combine it with a mixin of your own: `mixin: () => ({ ...pulsarMixin()(), ...mine() })`.
|
|
219
|
+
*/
|
|
220
|
+
declare function pulsarMixin(): () => PulsarMixinFields;
|
|
221
|
+
/**
|
|
222
|
+
* Logs finished spans through a pino logger, as records the transport maps to
|
|
223
|
+
* span-end entries: `msg` the name, `responseTime` the duration, the span ids
|
|
224
|
+
* and `spanKind` top level, `req`/`res` for HTTP client spans, `err` when it
|
|
225
|
+
* failed, and the attributes as `metadata`.
|
|
226
|
+
*/
|
|
227
|
+
declare function pinoSpanSink(logger: PinoLikeLogger): SpanSink;
|
|
228
|
+
/** Options of the pino `startSpan()`: the logger that writes the span-end entry. */
|
|
229
|
+
interface PinoSpanOptions extends SpanOptions {
|
|
230
|
+
/** Your pino logger (with the Pulsar transport configured). */
|
|
231
|
+
logger: PinoLikeLogger;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Runs `fn` in a new child span of the current one (or of `options.parent`,
|
|
235
|
+
* or in a new trace) and logs its span-end entry through `options.logger`
|
|
236
|
+
* when it returns or settles. Records logged inside (with `pulsarMixin()`)
|
|
237
|
+
* carry the new span's ids. The result or error is passed through unchanged.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* await startSpan('payments.charge', () => charge(order), { logger })
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
declare function startSpan<T>(name: string, fn: (span: TraceContext) => T, options: PinoSpanOptions): T;
|
|
245
|
+
/** Options of the pino outbound helpers. */
|
|
246
|
+
interface PinoOutboundOptions extends OutboundOptions {
|
|
247
|
+
/**
|
|
248
|
+
* Logs a `client` span-end entry per call through this logger. Without one,
|
|
249
|
+
* the current span is propagated as it is and nothing is logged.
|
|
250
|
+
*/
|
|
251
|
+
logger?: PinoLikeLogger;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Returns a fetch that propagates the trace: calls made inside a trace send
|
|
255
|
+
* `traceparent`, `tracestate` and `x-trace-id` (and, with `logger`, log a
|
|
256
|
+
* `client` span). Calls outside a trace are untouched. Nothing is patched;
|
|
257
|
+
* the fetch to wrap defaults to the global fetch as it is when this is called.
|
|
258
|
+
*/
|
|
259
|
+
declare function instrumentFetch(options?: PinoOutboundOptions): typeof fetch;
|
|
260
|
+
declare function instrumentFetch(fetchImpl: typeof fetch, options?: PinoOutboundOptions): typeof fetch;
|
|
261
|
+
/**
|
|
262
|
+
* Adds interceptors to an axios instance (duck-typed: axios is not a
|
|
263
|
+
* dependency) that propagate the trace like {@link instrumentFetch}.
|
|
264
|
+
* Returns the instance.
|
|
265
|
+
*/
|
|
266
|
+
declare function instrumentAxios<T extends AxiosLike>(instance: T, options?: PinoOutboundOptions): T;
|
|
3
267
|
|
|
4
268
|
interface PulsarTransportOptions {
|
|
5
269
|
/** Pulsar server URL (e.g., 'https://pulsar.example.com') */
|
|
@@ -10,10 +274,20 @@ interface PulsarTransportOptions {
|
|
|
10
274
|
source?: string;
|
|
11
275
|
/** Alias for source */
|
|
12
276
|
serviceName?: string;
|
|
13
|
-
/**
|
|
277
|
+
/** Buffered logs that trigger an immediate send (default: 50, max: 1000) */
|
|
14
278
|
batchSize?: number;
|
|
15
|
-
/**
|
|
279
|
+
/** Longest a log waits before it is sent, in milliseconds (default: 2000) */
|
|
16
280
|
flushInterval?: number;
|
|
281
|
+
/** Most logs held in memory while the server is slow or down (default: 5000). When full, the oldest are dropped and counted. */
|
|
282
|
+
maxBufferSize?: number;
|
|
283
|
+
/** Retries of a failing batch (429, 408, 5xx, network, timeout) before it is dropped; a batch is sent at most `maxRetries + 1` times (default: 10) */
|
|
284
|
+
maxRetries?: number;
|
|
285
|
+
/** Timeout per HTTP request, in milliseconds (default: 10000) */
|
|
286
|
+
requestTimeout?: number;
|
|
287
|
+
/** Longest the final flush waits when the logger is closed, in milliseconds (default: 3000) */
|
|
288
|
+
shutdownTimeout?: number;
|
|
289
|
+
/** Write a line to stderr (at most once a minute) when logs are dropped (default: true) */
|
|
290
|
+
warnOnDrop?: boolean;
|
|
17
291
|
}
|
|
18
292
|
/**
|
|
19
293
|
* Creates a Pino transport that sends logs to a Pulsar server.
|
|
@@ -21,7 +295,7 @@ interface PulsarTransportOptions {
|
|
|
21
295
|
* @example
|
|
22
296
|
* ```ts
|
|
23
297
|
* import pino from 'pino'
|
|
24
|
-
* import { createPulsarTransport } from '@pulsar
|
|
298
|
+
* import { createPulsarTransport } from '@fabbahiense/pulsar-pino-transport'
|
|
25
299
|
*
|
|
26
300
|
* const logger = pino(
|
|
27
301
|
* createPulsarTransport({
|
|
@@ -47,4 +321,4 @@ declare function createPulsarTransport(options: PulsarTransportOptions): {
|
|
|
47
321
|
};
|
|
48
322
|
declare function export_default(options: PulsarTransportOptions): Promise<node_stream.Transform & pino_abstract_transport.OnUnknown>;
|
|
49
323
|
|
|
50
|
-
export { type PulsarTransportOptions, createPulsarTransport, export_default as default };
|
|
324
|
+
export { type AxiosLike, type ExtractedTrace, type OutboundOptions, PinoLikeLogger, type PinoOutboundOptions, type PinoSpanOptions, type PulsarMixinFields, type PulsarTransportOptions, type SpanKind, type SpanOptions, type TraceContext, type TraceContextInit, type Traceparent, createPulsarTransport, export_default as default, extractTrace, formatTraceparent, getTraceContext, injectTrace, instrumentAxios, instrumentFetch, parseTraceparent, pinoSpanSink, pulsarMixin, runWithTrace, startSpan, traceHeaders };
|