spanport 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Spanport SDK: send your Node.js app's logs to Spanport.
3
+ *
4
+ * import * as spanport from "spanport";
5
+ * spanport.init({ dataKey: "sp_ingest_...", service: "orders-api" });
6
+ *
7
+ * It never breaks the host app: init() never throws, logs are sent in the background, and if
8
+ * anything is wrong it says so on stderr and the app carries on.
9
+ */
10
+ import {} from "node:stream";
11
+ import {} from "@opentelemetry/api";
12
+ import {} from "@opentelemetry/sdk-logs";
13
+ import { captureConsole } from "./consoleCapture.js";
14
+ import { CONSOLE_SOURCE, DATA_KEY_PREFIX, DEFAULT_COLLECTOR_URL, DEFAULT_SERVER_URL, LOG_STREAM_SOURCE, SDK_SCOPE_NAME, } from "./constants.js";
15
+ import { checkDataKey } from "./keyCheck.js";
16
+ import { createLogStream } from "./logStream.js";
17
+ import { buildLoggerProvider, buildOtlpExporter, toLogRecord } from "./pipeline.js";
18
+ import { sdkError, sdkInfo, sdkWarning } from "./sdkMessages.js";
19
+ import { consoleSeverity } from "./severity.js";
20
+ import { isHttpUrl } from "./urls.js";
21
+ let active;
22
+ let exitFlushInstalled = false;
23
+ /**
24
+ * Start sending this app's logs to Spanport. Call once at start-up. Never throws.
25
+ *
26
+ * @param options - Data key, service name and where Spanport runs.
27
+ */
28
+ export function init(options) {
29
+ try {
30
+ start(options);
31
+ }
32
+ catch (error) {
33
+ sdkError(`setup failed; the app keeps running but logs are not sent: ${describe(error)}`);
34
+ }
35
+ }
36
+ /**
37
+ * Send any logs still queued, stop capturing console and stop. Safe to call more than once.
38
+ * Call it on SIGTERM; a normal exit calls it for you. Never rejects.
39
+ */
40
+ export async function shutdown() {
41
+ const pipeline = active;
42
+ active = undefined;
43
+ if (!pipeline)
44
+ return;
45
+ pipeline.restoreConsole?.();
46
+ try {
47
+ await pipeline.provider.shutdown();
48
+ }
49
+ catch (error) {
50
+ sdkWarning(`shutdown failed; some queued logs may not have been sent: ${describe(error)}`);
51
+ }
52
+ }
53
+ /**
54
+ * A stream for pino or winston (JSON lines). Lines written before init() or after shutdown()
55
+ * are dropped.
56
+ *
57
+ * pino(spanport.logStream())
58
+ * new winston.transports.Stream({ stream: spanport.logStream() })
59
+ *
60
+ * @returns A new writable stream.
61
+ */
62
+ export function logStream() {
63
+ return createLogStream((entry) => {
64
+ active?.logger.emit(toLogRecord(entry, LOG_STREAM_SOURCE));
65
+ });
66
+ }
67
+ function start(options) {
68
+ if (active) {
69
+ sdkWarning("init() was already called; ignoring the second call");
70
+ return;
71
+ }
72
+ const collectorUrl = options.collectorUrl ?? DEFAULT_COLLECTOR_URL;
73
+ const problem = findProblem(options, collectorUrl);
74
+ if (problem) {
75
+ sdkError(`${problem}; logs are not sent`);
76
+ return;
77
+ }
78
+ const provider = buildLoggerProvider(options.service, buildOtlpExporter(collectorUrl, options.dataKey));
79
+ const logger = provider.getLogger(SDK_SCOPE_NAME);
80
+ const restoreConsole = options.captureConsole === false
81
+ ? undefined
82
+ : captureConsole((method, message) => {
83
+ logger.emit(toLogRecord({ body: message, severity: consoleSeverity(method), attributes: {} }, CONSOLE_SOURCE));
84
+ });
85
+ active = { provider, logger, restoreConsole };
86
+ installExitFlush();
87
+ sdkInfo(`sending logs for service ${options.service} to ${collectorUrl}`);
88
+ if (options.checkKey !== false) {
89
+ void checkDataKey(options.serverUrl ?? DEFAULT_SERVER_URL, options.dataKey);
90
+ }
91
+ }
92
+ /** Send what is queued when the app exits normally. Installed once, however often init runs. */
93
+ function installExitFlush() {
94
+ if (exitFlushInstalled)
95
+ return;
96
+ exitFlushInstalled = true;
97
+ process.on("beforeExit", () => void shutdown());
98
+ }
99
+ function findProblem(options, collectorUrl) {
100
+ if (!options.dataKey.startsWith(DATA_KEY_PREFIX)) {
101
+ return `dataKey must be a data key (${DATA_KEY_PREFIX}...)`;
102
+ }
103
+ if (!options.service)
104
+ return "service must name this app, e.g. service: 'orders-api'";
105
+ if (!isHttpUrl(collectorUrl))
106
+ return "collectorUrl must start with http:// or https://";
107
+ return undefined;
108
+ }
109
+ function describe(error) {
110
+ return error instanceof Error ? error.message : String(error);
111
+ }
112
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Checks the data key once against the Spanport server and says clearly if it is wrong.
3
+ *
4
+ * The collector accepts logs without checking keys, so without this an app with a wrong key would
5
+ * lose its logs silently.
6
+ */
7
+ /**
8
+ * Ask the server whether the data key is valid and report the answer on stderr. Never throws.
9
+ *
10
+ * Redirects are refused: following one would send the key to whatever host it names.
11
+ *
12
+ * @param serverUrl - Base URL of the Spanport server.
13
+ * @param dataKey - The raw data key; only its last characters are ever printed.
14
+ * @returns True if the server accepted the key; false if it rejected it or could not be asked.
15
+ */
16
+ export declare function checkDataKey(serverUrl: string, dataKey: string): Promise<boolean>;
17
+ //# sourceMappingURL=keyCheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyCheck.d.ts","sourceRoot":"","sources":["../src/keyCheck.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqBvF"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Checks the data key once against the Spanport server and says clearly if it is wrong.
3
+ *
4
+ * The collector accepts logs without checking keys, so without this an app with a wrong key would
5
+ * lose its logs silently.
6
+ */
7
+ import { AUTHORIZATION_HEADER, BEARER_PREFIX, CURRENT_API_KEY_PATH, HTTP_UNAUTHORIZED, KEY_CHECK_TIMEOUT_MS, VISIBLE_KEY_SUFFIX_LENGTH, } from "./constants.js";
8
+ import { sdkError, sdkInfo, sdkWarning } from "./sdkMessages.js";
9
+ import { isHttpUrl, joinUrl } from "./urls.js";
10
+ /**
11
+ * Ask the server whether the data key is valid and report the answer on stderr. Never throws.
12
+ *
13
+ * Redirects are refused: following one would send the key to whatever host it names.
14
+ *
15
+ * @param serverUrl - Base URL of the Spanport server.
16
+ * @param dataKey - The raw data key; only its last characters are ever printed.
17
+ * @returns True if the server accepted the key; false if it rejected it or could not be asked.
18
+ */
19
+ export async function checkDataKey(serverUrl, dataKey) {
20
+ const keySuffix = dataKey.slice(-VISIBLE_KEY_SUFFIX_LENGTH);
21
+ if (!isHttpUrl(serverUrl)) {
22
+ sdkWarning("serverUrl must start with http:// or https://; key not checked");
23
+ return false;
24
+ }
25
+ try {
26
+ const response = await fetch(joinUrl(serverUrl, CURRENT_API_KEY_PATH), {
27
+ headers: { [AUTHORIZATION_HEADER]: BEARER_PREFIX + dataKey },
28
+ redirect: "manual",
29
+ signal: AbortSignal.timeout(KEY_CHECK_TIMEOUT_MS),
30
+ });
31
+ // The body isn't needed; release the connection.
32
+ await response.body?.cancel();
33
+ return reportAnswer(response.status, response.ok, serverUrl, keySuffix);
34
+ }
35
+ catch (error) {
36
+ sdkWarning(`could not reach ${serverUrl} to check data key ...${keySuffix}: ${describe(error)}`);
37
+ return false;
38
+ }
39
+ }
40
+ function reportAnswer(status, ok, serverUrl, keySuffix) {
41
+ if (ok) {
42
+ sdkInfo(`data key ...${keySuffix} accepted`);
43
+ return true;
44
+ }
45
+ if (status === HTTP_UNAUTHORIZED) {
46
+ sdkError(`data key ...${keySuffix} was rejected by ${serverUrl}; logs will NOT be stored. ` +
47
+ "Check the key, or create one with create-data-key.");
48
+ return false;
49
+ }
50
+ sdkWarning(`could not check data key ...${keySuffix}: HTTP ${String(status)}`);
51
+ return false;
52
+ }
53
+ function describe(error) {
54
+ return error instanceof Error ? error.message : String(error);
55
+ }
56
+ //# sourceMappingURL=keyCheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyCheck.js","sourceRoot":"","sources":["../src/keyCheck.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB,EAAE,OAAe;IACnE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,yBAAyB,CAAC,CAAC;IAC5D,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,UAAU,CAAC,gEAAgE,CAAC,CAAC;QAC7E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE;YACrE,OAAO,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,aAAa,GAAG,OAAO,EAAE;YAC5D,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC;SAClD,CAAC,CAAC;QACH,iDAAiD;QACjD,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,UAAU,CACR,mBAAmB,SAAS,yBAAyB,SAAS,KAAK,QAAQ,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,EAAW,EAAE,SAAiB,EAAE,SAAiB;IACrF,IAAI,EAAE,EAAE,CAAC;QACP,OAAO,CAAC,eAAe,SAAS,WAAW,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;QACjC,QAAQ,CACN,eAAe,SAAS,oBAAoB,SAAS,6BAA6B;YAChF,oDAAoD,CACvD,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,UAAU,CAAC,+BAA+B,SAAS,UAAU,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A writable stream for loggers that write JSON lines: pino (as its destination) and winston (with
3
+ * the Stream transport and JSON format). The SDK depends on neither.
4
+ */
5
+ import { Writable } from "node:stream";
6
+ import { type LogEntry } from "./pipeline.js";
7
+ /**
8
+ * Create a stream that turns each line written to it into a log entry.
9
+ *
10
+ * Lines split across writes are joined before parsing.
11
+ *
12
+ * @param onEntry - Receives each parsed entry.
13
+ * @returns The stream to give to pino or winston.
14
+ */
15
+ export declare function createLogStream(onEntry: (entry: LogEntry) => void): Writable;
16
+ /**
17
+ * Parse one pino or winston JSON line. A line that isn't JSON becomes an INFO entry with the line
18
+ * as its message.
19
+ *
20
+ * @param line - One line, without the newline.
21
+ * @returns The log entry.
22
+ */
23
+ export declare function parseLogLine(line: string): LogEntry;
24
+ //# sourceMappingURL=logStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logStream.d.ts","sourceRoot":"","sources":["../src/logStream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmBvC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAc9C;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,QAAQ,CAY5E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAanD"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * A writable stream for loggers that write JSON lines: pino (as its destination) and winston (with
3
+ * the Stream transport and JSON format). The SDK depends on neither.
4
+ */
5
+ import { Writable } from "node:stream";
6
+ import { ROOT_CONTEXT, TraceFlags, isSpanContextValid, trace, } from "@opentelemetry/api";
7
+ import { LEVEL_FIELD, LINE_SEPARATOR, MESSAGE_FIELDS, SPAN_ID_FIELD, TIME_FIELDS, TRACE_ID_FIELD, } from "./constants.js";
8
+ import {} from "./pipeline.js";
9
+ import { INFO, pinoSeverity, winstonSeverity } from "./severity.js";
10
+ /** Fields that become part of the record itself, not attributes. */
11
+ const RECORD_FIELDS = new Set([
12
+ ...MESSAGE_FIELDS,
13
+ LEVEL_FIELD,
14
+ ...TIME_FIELDS,
15
+ TRACE_ID_FIELD,
16
+ SPAN_ID_FIELD,
17
+ ]);
18
+ /**
19
+ * Create a stream that turns each line written to it into a log entry.
20
+ *
21
+ * Lines split across writes are joined before parsing.
22
+ *
23
+ * @param onEntry - Receives each parsed entry.
24
+ * @returns The stream to give to pino or winston.
25
+ */
26
+ export function createLogStream(onEntry) {
27
+ let partialLine = "";
28
+ return new Writable({
29
+ write(chunk, _encoding, done) {
30
+ const lines = (partialLine + chunk.toString()).split(LINE_SEPARATOR);
31
+ partialLine = lines.pop() ?? "";
32
+ for (const line of lines) {
33
+ if (line.trim())
34
+ onEntry(parseLogLine(line));
35
+ }
36
+ done();
37
+ },
38
+ });
39
+ }
40
+ /**
41
+ * Parse one pino or winston JSON line. A line that isn't JSON becomes an INFO entry with the line
42
+ * as its message.
43
+ *
44
+ * @param line - One line, without the newline.
45
+ * @returns The log entry.
46
+ */
47
+ export function parseLogLine(line) {
48
+ const fields = parseJsonObject(line);
49
+ if (!fields)
50
+ return { body: line, severity: INFO, attributes: {} };
51
+ const entry = {
52
+ body: messageOf(fields) ?? line,
53
+ severity: severityOf(fields[LEVEL_FIELD]),
54
+ attributes: attributesOf(fields),
55
+ };
56
+ const context = traceContextOf(fields);
57
+ if (context)
58
+ entry.context = context;
59
+ const timestamp = timestampOf(fields);
60
+ if (timestamp)
61
+ entry.timestamp = timestamp;
62
+ return entry;
63
+ }
64
+ function parseJsonObject(line) {
65
+ try {
66
+ const parsed = JSON.parse(line);
67
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
68
+ ? parsed
69
+ : undefined;
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ function messageOf(fields) {
76
+ for (const name of MESSAGE_FIELDS) {
77
+ const value = fields[name];
78
+ if (typeof value === "string")
79
+ return value;
80
+ }
81
+ return undefined;
82
+ }
83
+ function severityOf(level) {
84
+ if (typeof level === "number")
85
+ return pinoSeverity(level);
86
+ if (typeof level === "string")
87
+ return winstonSeverity(level);
88
+ return INFO;
89
+ }
90
+ function attributesOf(fields) {
91
+ const attributes = {};
92
+ for (const [name, value] of Object.entries(fields)) {
93
+ if (!RECORD_FIELDS.has(name))
94
+ attributes[name] = toAttributeValue(value);
95
+ }
96
+ return attributes;
97
+ }
98
+ function toAttributeValue(value) {
99
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
100
+ return value;
101
+ }
102
+ return JSON.stringify(value);
103
+ }
104
+ /** Use the line's trace_id/span_id (as written by pino's OpenTelemetry integration) if valid. */
105
+ function traceContextOf(fields) {
106
+ const traceId = fields[TRACE_ID_FIELD];
107
+ const spanId = fields[SPAN_ID_FIELD];
108
+ if (typeof traceId !== "string" || typeof spanId !== "string")
109
+ return undefined;
110
+ const spanContext = { traceId, spanId, traceFlags: TraceFlags.SAMPLED, isRemote: true };
111
+ return isSpanContextValid(spanContext)
112
+ ? trace.setSpanContext(ROOT_CONTEXT, spanContext)
113
+ : undefined;
114
+ }
115
+ /** pino writes epoch milliseconds in `time`; winston's timestamp format writes an ISO string. */
116
+ function timestampOf(fields) {
117
+ for (const name of TIME_FIELDS) {
118
+ const value = fields[name];
119
+ if (typeof value !== "number" && typeof value !== "string")
120
+ continue;
121
+ const date = new Date(value);
122
+ if (!Number.isNaN(date.getTime()))
123
+ return date;
124
+ }
125
+ return undefined;
126
+ }
127
+ //# sourceMappingURL=logStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logStream.js","sourceRoot":"","sources":["../src/logStream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /** Builds the OpenTelemetry pipeline: log records → batch → OTLP/HTTP → collector. */
2
+ import { type Attributes, type Context, type LogRecord } from "@opentelemetry/api";
3
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
4
+ import { LoggerProvider, type LogRecordExporter } from "@opentelemetry/sdk-logs";
5
+ import { type Severity } from "./severity.js";
6
+ /** One log line, whatever logger it came from, before it becomes an OpenTelemetry record. */
7
+ export interface LogEntry {
8
+ body: string;
9
+ severity: Severity;
10
+ attributes: Attributes;
11
+ /** Carries the trace and span the log belongs to; the active span is used when absent. */
12
+ context?: Context;
13
+ timestamp?: Date;
14
+ }
15
+ /**
16
+ * Exporter that sends batches to the collector with the data key as a bearer token.
17
+ *
18
+ * @param collectorUrl - Base URL of the OTel Collector, e.g. "http://localhost:4318".
19
+ * @param dataKey - The raw data key.
20
+ * @returns The OTLP/HTTP log exporter.
21
+ */
22
+ export declare function buildOtlpExporter(collectorUrl: string, dataKey: string): OTLPLogExporter;
23
+ /**
24
+ * Provider that batches records in the background and hands them to `exporter`.
25
+ *
26
+ * @param service - Service name shown in Spanport, e.g. "orders-api".
27
+ * @param exporter - Where batches go; OTLP in real use, in-memory in tests.
28
+ * @returns The provider; shut it down to send what is still queued.
29
+ */
30
+ export declare function buildLoggerProvider(service: string, exporter: LogRecordExporter): LoggerProvider;
31
+ /**
32
+ * Turn a log entry into an OpenTelemetry log record.
33
+ *
34
+ * @param entry - The parsed log line.
35
+ * @param source - Where it came from ("console" or "stream"), kept as the log.source attribute.
36
+ * @returns The record to emit.
37
+ */
38
+ export declare function toLogRecord(entry: LogEntry, source: string): LogRecord;
39
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,EAEL,cAAc,EACd,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AASjC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG9C,6FAA6F;AAC7F,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAKxF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,cAAc,CAKhG;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAUtE"}
@@ -0,0 +1,55 @@
1
+ /** Builds the OpenTelemetry pipeline: log records → batch → OTLP/HTTP → collector. */
2
+ import {} from "@opentelemetry/api";
3
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
4
+ import { resourceFromAttributes } from "@opentelemetry/resources";
5
+ import { BatchLogRecordProcessor, LoggerProvider, } from "@opentelemetry/sdk-logs";
6
+ import { AUTHORIZATION_HEADER, BEARER_PREFIX, LOG_SOURCE_ATTRIBUTE, OTLP_LOGS_PATH, SERVICE_NAME_ATTRIBUTE, } from "./constants.js";
7
+ import {} from "./severity.js";
8
+ import { joinUrl } from "./urls.js";
9
+ /**
10
+ * Exporter that sends batches to the collector with the data key as a bearer token.
11
+ *
12
+ * @param collectorUrl - Base URL of the OTel Collector, e.g. "http://localhost:4318".
13
+ * @param dataKey - The raw data key.
14
+ * @returns The OTLP/HTTP log exporter.
15
+ */
16
+ export function buildOtlpExporter(collectorUrl, dataKey) {
17
+ return new OTLPLogExporter({
18
+ url: joinUrl(collectorUrl, OTLP_LOGS_PATH),
19
+ headers: { [AUTHORIZATION_HEADER]: BEARER_PREFIX + dataKey },
20
+ });
21
+ }
22
+ /**
23
+ * Provider that batches records in the background and hands them to `exporter`.
24
+ *
25
+ * @param service - Service name shown in Spanport, e.g. "orders-api".
26
+ * @param exporter - Where batches go; OTLP in real use, in-memory in tests.
27
+ * @returns The provider; shut it down to send what is still queued.
28
+ */
29
+ export function buildLoggerProvider(service, exporter) {
30
+ return new LoggerProvider({
31
+ resource: resourceFromAttributes({ [SERVICE_NAME_ATTRIBUTE]: service }),
32
+ processors: [new BatchLogRecordProcessor({ exporter })],
33
+ });
34
+ }
35
+ /**
36
+ * Turn a log entry into an OpenTelemetry log record.
37
+ *
38
+ * @param entry - The parsed log line.
39
+ * @param source - Where it came from ("console" or "stream"), kept as the log.source attribute.
40
+ * @returns The record to emit.
41
+ */
42
+ export function toLogRecord(entry, source) {
43
+ const record = {
44
+ body: entry.body,
45
+ severityNumber: entry.severity.number,
46
+ severityText: entry.severity.text,
47
+ attributes: { ...entry.attributes, [LOG_SOURCE_ATTRIBUTE]: source },
48
+ };
49
+ if (entry.context)
50
+ record.context = entry.context;
51
+ if (entry.timestamp)
52
+ record.timestamp = entry.timestamp;
53
+ return record;
54
+ }
55
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAiD,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,uBAAuB,EACvB,cAAc,GAEf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAiB,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAoB,EAAE,OAAe;IACrE,OAAO,IAAI,eAAe,CAAC;QACzB,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,cAAc,CAAC;QAC1C,OAAO,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,aAAa,GAAG,OAAO,EAAE;KAC7D,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,QAA2B;IAC9E,OAAO,IAAI,cAAc,CAAC;QACxB,QAAQ,EAAE,sBAAsB,CAAC,EAAE,CAAC,sBAAsB,CAAC,EAAE,OAAO,EAAE,CAAC;QACvE,UAAU,EAAE,CAAC,IAAI,uBAAuB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;KACxD,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAe,EAAE,MAAc;IACzD,MAAM,MAAM,GAAc;QACxB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;QACrC,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI;QACjC,UAAU,EAAE,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE;KACpE,CAAC;IACF,IAAI,KAAK,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAClD,IAAI,KAAK,CAAC,SAAS;QAAE,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACxD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The SDK's own messages. They go straight to stderr: never through console (which the SDK may be
3
+ * capturing, so they would loop) and never exported.
4
+ */
5
+ /** Report normal progress, e.g. the key was accepted. */
6
+ export declare function sdkInfo(message: string): void;
7
+ /** Report something that may stop logs from arriving, e.g. the server could not be reached. */
8
+ export declare function sdkWarning(message: string): void;
9
+ /** Report something that stops logs from being stored, e.g. a rejected key. */
10
+ export declare function sdkError(message: string): void;
11
+ //# sourceMappingURL=sdkMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkMessages.d.ts","sourceRoot":"","sources":["../src/sdkMessages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9C"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The SDK's own messages. They go straight to stderr: never through console (which the SDK may be
3
+ * capturing, so they would loop) and never exported.
4
+ */
5
+ import { SDK_MESSAGE_PREFIX } from "./constants.js";
6
+ function write(level, message) {
7
+ process.stderr.write(`${level} ${SDK_MESSAGE_PREFIX} ${message}\n`);
8
+ }
9
+ /** Report normal progress, e.g. the key was accepted. */
10
+ export function sdkInfo(message) {
11
+ write("INFO", message);
12
+ }
13
+ /** Report something that may stop logs from arriving, e.g. the server could not be reached. */
14
+ export function sdkWarning(message) {
15
+ write("WARNING", message);
16
+ }
17
+ /** Report something that stops logs from being stored, e.g. a rejected key. */
18
+ export function sdkError(message) {
19
+ write("ERROR", message);
20
+ }
21
+ //# sourceMappingURL=sdkMessages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkMessages.js","sourceRoot":"","sources":["../src/sdkMessages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAIpD,SAAS,KAAK,CAAC,KAAmB,EAAE,OAAe;IACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,kBAAkB,IAAI,OAAO,IAAI,CAAC,CAAC;AACtE,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,31 @@
1
+ /** Maps console, pino and winston levels to OpenTelemetry severities. */
2
+ import { SeverityNumber } from "@opentelemetry/api";
3
+ import { type CAPTURED_CONSOLE_METHODS } from "./constants.js";
4
+ export type ConsoleMethod = (typeof CAPTURED_CONSOLE_METHODS)[number];
5
+ export interface Severity {
6
+ number: SeverityNumber;
7
+ text: string;
8
+ }
9
+ export declare const INFO: Severity;
10
+ /**
11
+ * Severity of a console call.
12
+ *
13
+ * @param method - The console method that was called.
14
+ * @returns console.debug is DEBUG, log and info are INFO, warn is WARN, error is ERROR.
15
+ */
16
+ export declare function consoleSeverity(method: ConsoleMethod): Severity;
17
+ /**
18
+ * Severity of a pino level number (10 trace ... 60 fatal; custom levels fall into the band below).
19
+ *
20
+ * @param level - pino's numeric level.
21
+ * @returns The matching severity.
22
+ */
23
+ export declare function pinoSeverity(level: number): Severity;
24
+ /**
25
+ * Severity of a winston (npm-style) level name. Unknown names count as INFO.
26
+ *
27
+ * @param level - e.g. "error", "warn", "info", "http", "verbose", "debug", "silly".
28
+ * @returns The matching severity.
29
+ */
30
+ export declare function winstonSeverity(level: string): Severity;
31
+ //# sourceMappingURL=severity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity.d.ts","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EACL,KAAK,wBAAwB,EAM9B,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAID,eAAO,MAAM,IAAI,EAAE,QAAwD,CAAC;AAK5E;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAY/D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAOpD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAqBvD"}
@@ -0,0 +1,76 @@
1
+ /** Maps console, pino and winston levels to OpenTelemetry severities. */
2
+ import { SeverityNumber } from "@opentelemetry/api";
3
+ import { PINO_DEBUG, PINO_ERROR, PINO_FATAL, PINO_INFO, PINO_WARN, } from "./constants.js";
4
+ const TRACE = { number: SeverityNumber.TRACE, text: "TRACE" };
5
+ const DEBUG = { number: SeverityNumber.DEBUG, text: "DEBUG" };
6
+ export const INFO = { number: SeverityNumber.INFO, text: "INFO" };
7
+ const WARN = { number: SeverityNumber.WARN, text: "WARN" };
8
+ const ERROR = { number: SeverityNumber.ERROR, text: "ERROR" };
9
+ const FATAL = { number: SeverityNumber.FATAL, text: "FATAL" };
10
+ /**
11
+ * Severity of a console call.
12
+ *
13
+ * @param method - The console method that was called.
14
+ * @returns console.debug is DEBUG, log and info are INFO, warn is WARN, error is ERROR.
15
+ */
16
+ export function consoleSeverity(method) {
17
+ switch (method) {
18
+ case "debug":
19
+ return DEBUG;
20
+ case "log":
21
+ case "info":
22
+ return INFO;
23
+ case "warn":
24
+ return WARN;
25
+ case "error":
26
+ return ERROR;
27
+ }
28
+ }
29
+ /**
30
+ * Severity of a pino level number (10 trace ... 60 fatal; custom levels fall into the band below).
31
+ *
32
+ * @param level - pino's numeric level.
33
+ * @returns The matching severity.
34
+ */
35
+ export function pinoSeverity(level) {
36
+ if (level >= PINO_FATAL)
37
+ return FATAL;
38
+ if (level >= PINO_ERROR)
39
+ return ERROR;
40
+ if (level >= PINO_WARN)
41
+ return WARN;
42
+ if (level >= PINO_INFO)
43
+ return INFO;
44
+ if (level >= PINO_DEBUG)
45
+ return DEBUG;
46
+ return TRACE;
47
+ }
48
+ /**
49
+ * Severity of a winston (npm-style) level name. Unknown names count as INFO.
50
+ *
51
+ * @param level - e.g. "error", "warn", "info", "http", "verbose", "debug", "silly".
52
+ * @returns The matching severity.
53
+ */
54
+ export function winstonSeverity(level) {
55
+ switch (level.toLowerCase()) {
56
+ case "fatal":
57
+ case "emerg":
58
+ case "alert":
59
+ case "crit":
60
+ return FATAL;
61
+ case "error":
62
+ return ERROR;
63
+ case "warn":
64
+ case "warning":
65
+ return WARN;
66
+ case "debug":
67
+ case "verbose":
68
+ return DEBUG;
69
+ case "silly":
70
+ case "trace":
71
+ return TRACE;
72
+ default:
73
+ return INFO;
74
+ }
75
+ }
76
+ //# sourceMappingURL=severity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity.js","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAEL,UAAU,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,GACV,MAAM,gBAAgB,CAAC;AASxB,MAAM,KAAK,GAAa,EAAE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACxE,MAAM,KAAK,GAAa,EAAE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACxE,MAAM,CAAC,MAAM,IAAI,GAAa,EAAE,MAAM,EAAE,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC5E,MAAM,IAAI,GAAa,EAAE,MAAM,EAAE,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACrE,MAAM,KAAK,GAAa,EAAE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACxE,MAAM,KAAK,GAAa,EAAE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAExE;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqB;IACnD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,MAAM;YACT,OAAO,IAAI,CAAC;QACd,KAAK,MAAM;YACT,OAAO,IAAI,CAAC;QACd,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,KAAK,IAAI,UAAU;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,KAAK,IAAI,UAAU;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,KAAK,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,KAAK,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,KAAK,IAAI,UAAU;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,QAAQ,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QAC5B,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,MAAM;YACT,OAAO,KAAK,CAAC;QACf,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC;QACf,KAAK,OAAO,CAAC;QACb,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;QACf;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
package/dist/urls.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ /** URL helpers shared by the exporter and the key check. */
2
+ /**
3
+ * Append a path to a base URL, keeping any path the base already has (e.g. behind a proxy).
4
+ *
5
+ * @param baseUrl - e.g. "https://example.com/spanport" or "https://example.com/spanport/".
6
+ * @param path - Starting with "/", e.g. "/v1/logs".
7
+ * @returns The joined URL text.
8
+ */
9
+ export declare function joinUrl(baseUrl: string, path: string): string;
10
+ /**
11
+ * Whether the text is an absolute http:// or https:// URL.
12
+ *
13
+ * @param url - The URL text to check.
14
+ * @returns True only for parseable http(s) URLs.
15
+ */
16
+ export declare function isHttpUrl(url: string): boolean;
17
+ //# sourceMappingURL=urls.d.ts.map