@lensmcp/nest-instrumentation 1.24.0 → 1.24.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.
|
@@ -15,3 +15,16 @@ import { Observable } from 'rxjs';
|
|
|
15
15
|
export declare class TraceInterceptor implements NestInterceptor {
|
|
16
16
|
intercept(execCtx: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* What became of a request, for a reader deciding whether something is broken (issues/closed/foodguard-43):
|
|
20
|
+
* - `ok` — it answered below 400;
|
|
21
|
+
* - `refused` — a 4xx: the app turned the request away on purpose (not found, forbidden, invalid). Evidence of the
|
|
22
|
+
* request, not of a fault — a passing abuse or foreign-tenant test is made of these;
|
|
23
|
+
* - `declared` — a 5xx other than 500 the app chose to answer with (503 while a dependency is unavailable);
|
|
24
|
+
* - `fault` — a 500, or a programming error (a `TypeError`, a `ReferenceError`, …) whatever status it was mapped to.
|
|
25
|
+
*
|
|
26
|
+
* Every thrown value used to be an error, so a 404 the app meant read exactly like a crash: the lens's health
|
|
27
|
+
* headline went to "blocking" over a passing negative test.
|
|
28
|
+
*/
|
|
29
|
+
export type RequestOutcome = 'ok' | 'refused' | 'declared' | 'fault';
|
|
30
|
+
export declare function requestOutcome(status: number, err?: unknown): RequestOutcome;
|
package/lib/trace-interceptor.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var U=Object.defineProperty;var u=(e,t)=>U(e,"name",{value:t,configurable:!0});var L=Object.defineProperty,n=u((e,t)=>L(e,"name",{value:t,configurable:!0}),"r");import{__decorate as X}from"tslib";import{Injectable as z}from"@nestjs/common";import{Observable as M}from"rxjs";import{catchError as B,tap as J}from"rxjs/operators";import{fingerprint as A,ulid as g}from"@lensmcp/core";import{activeMemoryOptions as K,onFlowStart as Q,onFlowSettled as V}from"@lensmcp/memory-tracker";import{LENSMCP_CONTEXT_STORAGE as W}from"./context.js";import{attachContextEnd as Y}from"./context-end.js";import{activeOptions as y}from"./state.js";let k=class{static{u(this,"h")}static{n(this,"TraceInterceptor")}intercept(e,t){const r=y();if(!r.trace.requests)return t.handle();const d=e.switchToHttp(),o=d.getRequest(),s=d.getResponse(),i=I(o.headers?.["x-request-id"])??g(),a={sessionId:r.sessionId,requestId:i,parentRequestId:I(o.headers?.["x-lensmcp-parent-request-id"]),flowId:I(o.headers?.["x-lensmcp-flow-id"]),originNodeId:I(o.headers?.["x-lensmcp-origin-node-id"]),traceparent:I(o.headers?.traceparent),dbCallCount:0},c=(o.method??"GET").toUpperCase(),m=o.route?.path??o.url??"<unknown>",p=e.getClass?.()?.name,w=e.getHandler?.()?.name,q=Date.now(),R=r.memory.mode!=="off";R&&Q(i);const $=n(()=>{if(!R)return;const f=K()?.settleMs??1e3;setTimeout(()=>V(i,a.flowId),f).unref?.()},"settleAndCheck"),F=Y(a);let T=!1,v=typeof s?.once!="function";const j=n(()=>{T&&v&&F()},"endIfOver");if(!v){const f=n(()=>{v=!0,j()},"responseOut");s.once?.("finish",f),s.once?.("close",f)}return new M(f=>{let S;return W.run(a,()=>{S=t.handle().pipe(J({next:n(l=>f.next(l),"next"),complete:n(()=>{C(r.projectName,a,c,m,s.statusCode??200,q),x(a,p,w,q,"ok"),$(),f.complete()},"complete")}),B(l=>{const O=E(l);if(O!==void 0||typeof s.once!="function")C(r.projectName,a,c,m,O??b(s),q,l);else{let D=!1;const N=n(G=>{if(D)return;D=!0;const H=G&&s.statusCode&&s.statusCode>=400?s.statusCode:b(s);C(r.projectName,a,c,m,H,q,l)},"settle");s.once("finish",()=>N(!0)),s.once("close",()=>N(!1))}return x(a,p,w,q,"error"),$(),f.error(l),new M})).subscribe()}),()=>{S?.unsubscribe(),T=!0,j()}})}};k=X([z()],k);export{k as TraceInterceptor};function E(e){const t=e;if(typeof t?.getStatus=="function")return t.getStatus();if(typeof t?.status=="number"&&t.status>=100)return t.status;if(typeof t?.statusCode=="number"&&t.statusCode>=100)return t.statusCode}u(E,"N"),n(E,"ownStatus");const Z=new Set(["TypeError","ReferenceError","SyntaxError","RangeError","EvalError","URIError"]);export function requestOutcome(e,t){return t instanceof Error&&Z.has(t.name)&&E(t)===void 0?"fault":e<400?"ok":e<500?"refused":e===500?"fault":"declared"}u(requestOutcome,"requestOutcome"),n(requestOutcome,"requestOutcome");function _(e){return e==="ok"?"info":e==="refused"?"warning":"error"}u(_,"Y"),n(_,"severityOf");function b(e){return e.statusCode&&e.statusCode>=400?e.statusCode:500}u(b,"_"),n(b,"inferStatus");function I(e){if(typeof e=="string")return e;if(Array.isArray(e)&&typeof e[0]=="string")return e[0]}u(I,"w"),n(I,"stringHeader");function x(e,t,r,d,o){if(!t||!r)return;const s=y(),i=Date.now()-d,a=`${t}.${r}`,c={id:g(),sessionId:e.sessionId,timestamp:Date.now(),source:"nestjs",category:"backend",severity:o==="error"?"error":"info",context:{sessionId:e.sessionId,flowId:e.flowId,requestId:e.requestId},fingerprint:A({kind:"method-call",identity:a}),title:`${a} (${i}ms)${o==="error"?" \u2717":""}`,raw:{kind:"span",span:{name:a,role:"controller",flowId:e.flowId,requestId:e.requestId,startTime:d,endTime:Date.now(),durationMs:i,status:o}}};h(c,y().projectName),s.emit(c)}u(x,"A"),n(x,"emitControllerSpan");function P(e){if(!(e instanceof Error))return{message:String(e)};const t=e.stack?e.stack.split(`
|
|
2
2
|
`).slice(0,30).join(`
|
|
3
|
-
`):void 0;return{...
|
|
3
|
+
`):void 0;return{...e.name?{name:e.name}:{},message:e.message,...t?{stack:t}:{}}}u(P,"Z"),n(P,"errorDetail");function h(e,t){if(!t)return;const r=e.raw;r&&r.project===void 0&&(r.project=t)}u(h,"C"),n(h,"stampProject");function C(e,t,r,d,o,s,i){const a=y(),c=Date.now()-s,m=requestOutcome(o,i),p={id:g(),sessionId:t.sessionId,timestamp:Date.now(),source:"nestjs",category:"backend",severity:_(m),context:{sessionId:t.sessionId,flowId:t.flowId,requestId:t.requestId,...t.parentRequestId?{parentRequestId:t.parentRequestId}:{},originNodeId:t.originNodeId,traceparent:t.traceparent},fingerprint:A({kind:"server-request",identity:`${r}:${d}:${Math.floor(o/100)}xx`}),title:`${r} ${d} \u2192 ${o} (${c}ms)`,message:i instanceof Error?i.message:void 0,raw:{kind:"server-request",request:{method:r,route:d,status:o,outcome:m,durationMs:c,startedAt:s,endedAt:Date.now(),flowId:t.flowId,requestId:t.requestId,...t.parentRequestId?{parentRequestId:t.parentRequestId}:{},...i?{error:P(i)}:{}}}},w={...p,id:g(),raw:{kind:"span",span:{name:`nest.request ${r} ${d}`,traceId:t.traceparent,flowId:t.flowId,requestId:t.requestId,startTime:s,endTime:Date.now(),durationMs:c,status:m==="ok"?"ok":"error"}}};h(p,e),h(w,e),a.emit(p),a.emit(w)}u(C,"E"),n(C,"emitRequest");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/nest-instrumentation",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lensmcp/core": "1.24.
|
|
18
|
-
"@lensmcp/memory-tracker": "1.24.
|
|
19
|
-
"@lensmcp/protocol-types": "1.24.
|
|
17
|
+
"@lensmcp/core": "1.24.1",
|
|
18
|
+
"@lensmcp/memory-tracker": "1.24.1",
|
|
19
|
+
"@lensmcp/protocol-types": "1.24.1",
|
|
20
20
|
"tslib": "^2.3.0"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|