@foam-ai/node-cliengo 0.1.0-alpha.6 → 0.1.0-alpha.7
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/node-cliengo/src/http/express.d.ts +12 -0
- package/dist/node-cliengo/src/http/express.js +22 -0
- package/dist/node-cliengo/src/http/fastify.d.ts +10 -0
- package/dist/node-cliengo/src/http/fastify.js +20 -0
- package/dist/node-cliengo/src/index.d.ts +2 -2
- package/dist/node-cliengo/src/index.js +3 -1
- package/dist/node-cliengo/src/logs/pino-destination.js +14 -0
- package/dist/node-cliengo/src/trace-bridge.js +12 -5
- package/package.json +1 -1
|
@@ -36,6 +36,18 @@
|
|
|
36
36
|
import { type Tracer } from '@opentelemetry/api';
|
|
37
37
|
import type { ExpressErrorHandler, ExpressRequestHandler } from '../types';
|
|
38
38
|
export declare function createExpressMiddleware(tracer: Tracer): ExpressRequestHandler;
|
|
39
|
+
/**
|
|
40
|
+
* Reads the trace context that was captured on the request at middleware time.
|
|
41
|
+
* Use this in pino-http's `customProps` to get trace IDs even after NR's
|
|
42
|
+
* transaction has ended:
|
|
43
|
+
*
|
|
44
|
+
* pinoHttp({ customProps: (req) => getRequestTraceContext(req) })
|
|
45
|
+
*/
|
|
46
|
+
export declare function getRequestTraceContext(req: any): {
|
|
47
|
+
traceId: string;
|
|
48
|
+
spanId: string;
|
|
49
|
+
traceparent: string;
|
|
50
|
+
};
|
|
39
51
|
export declare function createExpressErrorHandler(middlewareRef?: ExpressRequestHandler & {
|
|
40
52
|
_markErrorHandler?: () => void;
|
|
41
53
|
}): ExpressErrorHandler;
|
|
@@ -36,11 +36,13 @@
|
|
|
36
36
|
*/
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
38
|
exports.createExpressMiddleware = createExpressMiddleware;
|
|
39
|
+
exports.getRequestTraceContext = getRequestTraceContext;
|
|
39
40
|
exports.createExpressErrorHandler = createExpressErrorHandler;
|
|
40
41
|
const api_1 = require("@opentelemetry/api");
|
|
41
42
|
const trace_bridge_1 = require("../trace-bridge");
|
|
42
43
|
const request_context_1 = require("./request-context");
|
|
43
44
|
const SPAN_KEY = Symbol.for('foam.shadow.span');
|
|
45
|
+
const TRACE_CTX_KEY = Symbol.for('foam.trace.context');
|
|
44
46
|
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
|
|
45
47
|
function createExpressMiddleware(tracer) {
|
|
46
48
|
let errorHandlerRegistered = false;
|
|
@@ -61,6 +63,7 @@ function createExpressMiddleware(tracer) {
|
|
|
61
63
|
},
|
|
62
64
|
});
|
|
63
65
|
req[SPAN_KEY] = span;
|
|
66
|
+
req[TRACE_CTX_KEY] = { traceId, spanId };
|
|
64
67
|
const startTime = Date.now();
|
|
65
68
|
const onFinish = () => {
|
|
66
69
|
try {
|
|
@@ -99,6 +102,25 @@ function createExpressMiddleware(tracer) {
|
|
|
99
102
|
middleware._markErrorHandler = markErrorHandlerRegistered;
|
|
100
103
|
return middleware;
|
|
101
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Reads the trace context that was captured on the request at middleware time.
|
|
107
|
+
* Use this in pino-http's `customProps` to get trace IDs even after NR's
|
|
108
|
+
* transaction has ended:
|
|
109
|
+
*
|
|
110
|
+
* pinoHttp({ customProps: (req) => getRequestTraceContext(req) })
|
|
111
|
+
*/
|
|
112
|
+
function getRequestTraceContext(req) {
|
|
113
|
+
try {
|
|
114
|
+
const ctx = req[TRACE_CTX_KEY];
|
|
115
|
+
const traceId = ctx?.traceId ?? '';
|
|
116
|
+
const spanId = ctx?.spanId ?? '';
|
|
117
|
+
const traceparent = traceId && spanId ? `00-${traceId}-${spanId}-01` : '';
|
|
118
|
+
return { traceId, spanId, traceparent };
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return { traceId: '', spanId: '', traceparent: '' };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
102
124
|
function createExpressErrorHandler(middlewareRef) {
|
|
103
125
|
middlewareRef?._markErrorHandler?.();
|
|
104
126
|
return (err, req, _res, next) => {
|
|
@@ -25,4 +25,14 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { type Tracer } from '@opentelemetry/api';
|
|
27
27
|
import type { FastifyPluginAsync } from '../types';
|
|
28
|
+
/**
|
|
29
|
+
* Reads the trace context that was captured on the request at hook time.
|
|
30
|
+
* Use this in Fastify's logger mixin or serializers to get trace IDs even
|
|
31
|
+
* after NR's transaction has ended.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getRequestTraceContext(request: any): {
|
|
34
|
+
traceId: string;
|
|
35
|
+
spanId: string;
|
|
36
|
+
traceparent: string;
|
|
37
|
+
};
|
|
28
38
|
export declare function createFastifyPlugin(tracer: Tracer): FastifyPluginAsync;
|
|
@@ -25,12 +25,31 @@
|
|
|
25
25
|
* - done() always called even if our code throws — Fastify hook contract.
|
|
26
26
|
*/
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.getRequestTraceContext = getRequestTraceContext;
|
|
28
29
|
exports.createFastifyPlugin = createFastifyPlugin;
|
|
29
30
|
const api_1 = require("@opentelemetry/api");
|
|
30
31
|
const trace_bridge_1 = require("../trace-bridge");
|
|
31
32
|
const request_context_1 = require("./request-context");
|
|
32
33
|
const SPAN_KEY = Symbol.for('foam.shadow.span');
|
|
33
34
|
const START_KEY = Symbol.for('foam.shadow.start');
|
|
35
|
+
const TRACE_CTX_KEY = Symbol.for('foam.trace.context');
|
|
36
|
+
/**
|
|
37
|
+
* Reads the trace context that was captured on the request at hook time.
|
|
38
|
+
* Use this in Fastify's logger mixin or serializers to get trace IDs even
|
|
39
|
+
* after NR's transaction has ended.
|
|
40
|
+
*/
|
|
41
|
+
function getRequestTraceContext(request) {
|
|
42
|
+
try {
|
|
43
|
+
const ctx = request[TRACE_CTX_KEY];
|
|
44
|
+
const traceId = ctx?.traceId ?? '';
|
|
45
|
+
const spanId = ctx?.spanId ?? '';
|
|
46
|
+
const traceparent = traceId && spanId ? `00-${traceId}-${spanId}-01` : '';
|
|
47
|
+
return { traceId, spanId, traceparent };
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return { traceId: '', spanId: '', traceparent: '' };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
34
53
|
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
|
|
35
54
|
function createFastifyPlugin(tracer) {
|
|
36
55
|
return async (fastify) => {
|
|
@@ -49,6 +68,7 @@ function createFastifyPlugin(tracer) {
|
|
|
49
68
|
});
|
|
50
69
|
request[SPAN_KEY] = span;
|
|
51
70
|
request[START_KEY] = Date.now();
|
|
71
|
+
request[TRACE_CTX_KEY] = { traceId, spanId };
|
|
52
72
|
}
|
|
53
73
|
catch {
|
|
54
74
|
/* never crash */
|
|
@@ -18,8 +18,8 @@ export { buildTraceparent, extractParentContext, getTraceContext } from './trace
|
|
|
18
18
|
export { injectSnsAttributes } from './sns';
|
|
19
19
|
export { injectJobData, wrapJobConsumer } from './job';
|
|
20
20
|
export { wrapSqsConsumer } from './sqs';
|
|
21
|
-
export { createExpressMiddleware, createExpressErrorHandler } from './http/express';
|
|
22
|
-
export { createFastifyPlugin } from './http/fastify';
|
|
21
|
+
export { createExpressMiddleware, createExpressErrorHandler, getRequestTraceContext } from './http/express';
|
|
22
|
+
export { createFastifyPlugin, getRequestTraceContext as getFastifyRequestTraceContext } from './http/fastify';
|
|
23
23
|
export { createWinstonFormat } from './logs/winston-format';
|
|
24
24
|
export { createPinoMixin } from './logs/pino-mixin';
|
|
25
25
|
export { FOAM_OTEL_ENDPOINT } from './constants';
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* access to the foam instance.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.FOAM_OTEL_ENDPOINT = exports.createPinoMixin = exports.createWinstonFormat = exports.createFastifyPlugin = exports.createExpressErrorHandler = exports.createExpressMiddleware = exports.wrapSqsConsumer = exports.wrapJobConsumer = exports.injectJobData = exports.injectSnsAttributes = exports.getTraceContext = exports.extractParentContext = exports.buildTraceparent = exports.init = void 0;
|
|
18
|
+
exports.FOAM_OTEL_ENDPOINT = exports.createPinoMixin = exports.createWinstonFormat = exports.getFastifyRequestTraceContext = exports.createFastifyPlugin = exports.getRequestTraceContext = exports.createExpressErrorHandler = exports.createExpressMiddleware = exports.wrapSqsConsumer = exports.wrapJobConsumer = exports.injectJobData = exports.injectSnsAttributes = exports.getTraceContext = exports.extractParentContext = exports.buildTraceparent = exports.init = void 0;
|
|
19
19
|
var init_1 = require("./init");
|
|
20
20
|
Object.defineProperty(exports, "init", { enumerable: true, get: function () { return init_1.init; } });
|
|
21
21
|
var trace_bridge_1 = require("./trace-bridge");
|
|
@@ -32,8 +32,10 @@ Object.defineProperty(exports, "wrapSqsConsumer", { enumerable: true, get: funct
|
|
|
32
32
|
var express_1 = require("./http/express");
|
|
33
33
|
Object.defineProperty(exports, "createExpressMiddleware", { enumerable: true, get: function () { return express_1.createExpressMiddleware; } });
|
|
34
34
|
Object.defineProperty(exports, "createExpressErrorHandler", { enumerable: true, get: function () { return express_1.createExpressErrorHandler; } });
|
|
35
|
+
Object.defineProperty(exports, "getRequestTraceContext", { enumerable: true, get: function () { return express_1.getRequestTraceContext; } });
|
|
35
36
|
var fastify_1 = require("./http/fastify");
|
|
36
37
|
Object.defineProperty(exports, "createFastifyPlugin", { enumerable: true, get: function () { return fastify_1.createFastifyPlugin; } });
|
|
38
|
+
Object.defineProperty(exports, "getFastifyRequestTraceContext", { enumerable: true, get: function () { return fastify_1.getRequestTraceContext; } });
|
|
37
39
|
var winston_format_1 = require("./logs/winston-format");
|
|
38
40
|
Object.defineProperty(exports, "createWinstonFormat", { enumerable: true, get: function () { return winston_format_1.createWinstonFormat; } });
|
|
39
41
|
var pino_mixin_1 = require("./logs/pino-mixin");
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
*/
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
exports.createPinoDestination = createPinoDestination;
|
|
38
|
+
const api_1 = require("@opentelemetry/api");
|
|
38
39
|
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
39
40
|
const node_stream_1 = require("node:stream");
|
|
40
41
|
const PINO_LEVEL_MAP = {
|
|
@@ -95,11 +96,24 @@ function createPinoDestination(loggerProvider, serviceName) {
|
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
}
|
|
99
|
+
// Build an OTel Context carrying the SpanContext so the SDK stamps the
|
|
100
|
+
// native traceId/spanId fields on the exported OTLP LogRecord. Without
|
|
101
|
+
// this, backends can't correlate logs to traces.
|
|
102
|
+
let logContext;
|
|
103
|
+
if (traceId && spanId) {
|
|
104
|
+
logContext = api_1.trace.setSpanContext(api_1.ROOT_CONTEXT, {
|
|
105
|
+
traceId,
|
|
106
|
+
spanId,
|
|
107
|
+
traceFlags: 1,
|
|
108
|
+
isRemote: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
98
111
|
otelLogger.emit({
|
|
99
112
|
body: msg,
|
|
100
113
|
severityNumber: severity,
|
|
101
114
|
severityText,
|
|
102
115
|
attributes,
|
|
116
|
+
...(logContext && { context: logContext }),
|
|
103
117
|
});
|
|
104
118
|
}
|
|
105
119
|
catch {
|
|
@@ -49,11 +49,18 @@ function generateSpanId() {
|
|
|
49
49
|
return (0, node_crypto_1.randomBytes)(8).toString('hex');
|
|
50
50
|
}
|
|
51
51
|
function resolveTraceIds() {
|
|
52
|
-
// 1. Try NR
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
// 1. Try NR (guarded — getTraceMetadata() can throw if the underlying
|
|
53
|
+
// transaction is null, which happens when pino-http logs fire after
|
|
54
|
+
// NR's transaction has ended)
|
|
55
|
+
try {
|
|
56
|
+
const nr = (0, nr_1.getNr)();
|
|
57
|
+
const meta = nr.getTraceMetadata?.() ?? { traceId: '', spanId: '' };
|
|
58
|
+
if (meta.traceId && meta.spanId) {
|
|
59
|
+
return { traceId: meta.traceId, spanId: meta.spanId };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// NR transaction is null or getTraceMetadata threw — fall through
|
|
57
64
|
}
|
|
58
65
|
// 2. Fall back to OTel's own active span
|
|
59
66
|
const activeSpan = api_1.trace.getActiveSpan();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foam-ai/node-cliengo",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
4
|
"description": "Unified observability (traces, logs, metrics) for Cliengo Node.js services, connecting New Relic APM with Foam's OTel collector.",
|
|
5
5
|
"main": "dist/node-cliengo/src/index.js",
|
|
6
6
|
"types": "dist/node-cliengo/src/index.d.ts",
|