@autofleet/outbreak 2.3.0-beta-91bc0ca7.0 → 2.3.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/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var
|
1
|
+
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var node_module=require('node:module'),c=require('node:http'),node_crypto=require('node:crypto'),w=require('node:async_hooks');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var c__default=/*#__PURE__*/_interopDefault(c);var w__default=/*#__PURE__*/_interopDefault(w);var f={HTTP_REQUEST:"httpRequest",WEB_SOCKET:"webSocket",RABBIT:"rabbit"};var p=Symbol("outbreak-wrapped"),H=()=>node_crypto.randomUUID().split("-")[0],S=t=>t instanceof Request||Object.prototype.toString.call(t)==="[object Request]",I=t=>t instanceof Headers||Object.prototype.toString.call(t)==="[object Headers]";function L(t,e,r,s){let o=r.headers[t.correlationIdHeader]??H();e.getCurrentTrace().context.set(t.correlationIdHeader,o),s.setHeader(t.correlationIdHeader,o);}function k(t,e,r,s){t.setAndPropagateCorrelationId&&L(t,e,r,s),Object.entries(r.headers).forEach(([o,n])=>{(t.headersToCollect.has(o)||o.startsWith(t.headersPrefix))&&typeof n<"u"&&e.getCurrentTrace().context.set(o,n);});}function O(t,e,r){return (s,o,n,a)=>{e.newTrace(f.HTTP_REQUEST),k(t,e,s,o),r(s,o,n,a);}}function M(t,e){if(c__default.default.createServer[p])return;let r=c__default.default.createServer;function s(o,n){return n=n||o,r(O(t,e,n))}s[p]=true,c__default.default.createServer=s;}function m(t,e){let r=t.getCurrentTrace().context;r&&(e.headers||={},[...r.keys()].forEach(s=>{e.headers[s]=r.get(s);}));}function v(t,e){if(c__default.default[e][p])return;let r=c__default.default[e];function s(a,i,u){return m(t,i),r(a,i,u)}function o(a,i){return m(t,a),r(a,i)}function n(...a){let i={},u,h;return a.length===3?([u,i,h]=a,s(u,i,h)):([i,h]=a,o(i,h))}n[p]=true,c__default.default[e]=n;}function q(t,e){let r=t.getCurrentTrace()?.context;if(r)for(let s of r.keys())e.set(s,r.get(s));}function P(t){if(globalThis.fetch[p])return;let e=globalThis.fetch;globalThis.fetch=(r,s)=>(S(r)&&r.headers&&!s?.headers?q(t,r.headers):(s??={},s.headers??=new Headers,I(s.headers)||(s.headers=new Headers(s.headers)),q(t,s.headers)),e(r,s)),globalThis.fetch[p]=true;}function g(t,e){M(t,e),v(e,"request"),v(e,"get"),P(e);}var y="x-trace-id",U=t=>{if(!Array.isArray(t))throw new Error("Header list is not an array");let e=/^[\x21-\x7e]+$/i,r=t.filter(s=>typeof s!="string"||!e.test(s));if(r.length>0)throw new Error(`Header list contains invalid headers: ${r}`)},E=(t={})=>{let{setAndPropagateCorrelationId:e=true,headersToPropagate:r=["x-request-id","x-variant-id"],headersPrefix:s="x-af-"}=t;return U(r),{setAndPropagateCorrelationId:e,correlationIdHeader:y,headersToCollect:new Set(r),headersPrefix:s}},R={load:E,correlationIdHeader:y};var T=class{constructor(e){this.type=e;this.id=node_crypto.randomUUID();this.context=new Map;}},l=class{constructor(){this.#t=false;this.#r=new Map;this.#e={currentTrace:null,traces:{}};this.#s=w__default.default.createHook({init:(e,r,s)=>{this.#e.traces[s]&&(this.#e.traces[e]=this.#e.traces[s]);},before:e=>{this.#e.traces[e]&&(this.#r.set(e,this.#e.currentTrace),this.#e.currentTrace=this.#e.traces[e]);},after:e=>{this.#e.traces[e]&&(this.#e.currentTrace=this.#r.get(e));},destroy:e=>{this.#e.traces[e]&&(delete this.#e.traces[e],this.#r.delete(e));}});this.enable=()=>(this.#t||(this.#s.enable(),this.#t=true),this.#s);this.newTrace=e=>{this.#t||this.enable();let r=new T(e);return this.#e.currentTrace=r,this.#e.traces[w__default.default.executionAsyncId()]=r,r};this.getCurrentTrace=()=>this.#e.currentTrace||{};}#t;#r;#e;#s};var x=node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))),d=new l,b=t=>({[t]:d.getCurrentTrace()?.context?.get(R.correlationIdHeader)}),F=(t,e)=>e(r=>Object.assign(r,b(t)));function W(t,e){let{format:r}=x("winston");t.format=r.combine(F(e,r)(),t.format);}function K(t){g(R.load(t),d),d.enable();let e=t.loggerTraceKey||"traceId";t.winstonLogger&&W(t.winstonLogger,e),t.contextMiddlewareGetter?.(()=>b(e));try{x("bluebird").config({asyncHooks:!0});}catch{}}var ee=()=>d.getCurrentTrace(),{newTrace:te}=d;exports.default=K;exports.getCurrentContext=ee;exports.newTrace=te;exports.traceTypes=f;//# sourceMappingURL=index.cjs.map
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/const.ts","../src/http_wrapper.ts","../src/config.ts","../src/tracer.ts","../src/index.ts"],"names":["traceTypes","kOutbreakWrapped","generateShortId","randomUUID","isFetchRequest","headers","isFetchHeaders","setAndCollectCorrelationId","config","tracer","req","res","correlationId","collect","headerName","value","wrappedListener","listener","next","error","wrapHttpCreateServer","http","originalHttpCreateServer","wrappedHttpCreateServer","options","inject","currentTraceContext","header","wrapHttpRequest","originalMethodName","originalMethod","urlFirst","url","cb","optionsFirst","wrappedHttpRequest","args","callback","injectInFetchRequest","wrapFetch","originalFetch","input","init","wrapHttp","correlationIdHeader","validateHeaderList","headerNameRegex","invalidHeaders","h","load","overrides","setAndPropagateCorrelationId","headersToPropagate","headersPrefix","config_default","Trace","type","Tracer","#isTraceEnabled","#prevStates","#tracer","#hook","asyncHooks","asyncId","_type","triggerAsyncId","currentTrace","contextMiddleware","loggerTraceKey","addMetadataToLog","format","info","outbreakInitialize","traceKey","getCurrentContext","newTrace"],"mappings":"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","file":"index.cjs","sourcesContent":["export const traceTypes = {\n HTTP_REQUEST: 'httpRequest',\n WEB_SOCKET: 'webSocket',\n RABBIT: 'rabbit',\n} as const;\nexport type TraceType = typeof traceTypes[keyof typeof traceTypes];\n","import http from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { URL } from 'node:url';\nimport { traceTypes } from './const';\nimport type { Tracer } from './tracer';\nimport type { LoadedConfig } from './config';\n\nexport const kOutbreakWrapped = Symbol('outbreak-wrapped');\nconst generateShortId = () => randomUUID().split('-')[0];\nconst isFetchRequest = (headers: unknown): headers is Request => headers instanceof Request || Object.prototype.toString.call(headers) === '[object Request]';\nconst isFetchHeaders = (headers: unknown): headers is Headers => headers instanceof Headers || Object.prototype.toString.call(headers) === '[object Headers]';\n\nfunction setAndCollectCorrelationId(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n const correlationId = req.headers[config.correlationIdHeader] ?? generateShortId();\n tracer.getCurrentTrace().context.set(config.correlationIdHeader, correlationId as string);\n res.setHeader(config.correlationIdHeader, correlationId);\n}\n\nfunction collect(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n if (config.setAndPropagateCorrelationId) {\n setAndCollectCorrelationId(config, tracer, req, res);\n }\n\n Object.entries(req.headers).forEach(([headerName, value]) => {\n const shouldCollect = config.headersToCollect.has(headerName) || headerName.startsWith(config.headersPrefix);\n if (shouldCollect && typeof value !== 'undefined') {\n tracer.getCurrentTrace().context.set(headerName, value as string);\n }\n });\n}\n\nfunction wrappedListener<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(\n config: LoadedConfig,\n tracer: Tracer,\n listener: http.RequestListener<Request, Response>,\n): http.RequestListener<Request, Response> {\n // @ts-expect-error we add next and error which don't exist on the original type\n return (req: http.IncomingMessage, res: http.ServerResponse, next: unknown, error: unknown): void => {\n tracer.newTrace(traceTypes.HTTP_REQUEST);\n\n collect(config, tracer, req, res);\n\n // @ts-expect-error we add next and error which don't exist on the original type\n listener(req, res, next, error);\n };\n}\n\nfunction wrapHttpCreateServer<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(config: LoadedConfig, tracer: Tracer): void {\n if (http.createServer[kOutbreakWrapped]) {\n return;\n }\n const originalHttpCreateServer = http.createServer;\n // args of http.createServer are ([options<Object>], [listener<Fn>]) Express only sends listener\n function wrappedHttpCreateServer(options: http.ServerOptions<Request, Response>, listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(\n options: http.ServerOptions<Request, Response> | http.RequestListener<Request, Response>,\n listener?: http.RequestListener<Request, Response>,\n ): http.Server<Request, Response> {\n listener = listener || options as http.RequestListener<Request, Response>;\n return originalHttpCreateServer<Request, Response>(wrappedListener(config, tracer, listener));\n }\n wrappedHttpCreateServer[kOutbreakWrapped] = true;\n http.createServer = wrappedHttpCreateServer;\n}\n\nfunction inject(tracer: Tracer, options: http.RequestOptions): void {\n const currentTraceContext = tracer.getCurrentTrace().context;\n if (currentTraceContext) {\n options.headers ||= {};\n [...(currentTraceContext.keys())].forEach((header) => {\n options.headers[header] = currentTraceContext.get(header);\n });\n }\n}\nfunction wrapHttpRequest(tracer: Tracer, originalMethodName: 'request' | 'get'): void {\n if (http[originalMethodName][kOutbreakWrapped]) {\n return;\n }\n const originalMethod = http[originalMethodName];\n function urlFirst(url: string | URL, options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(url, options, cb);\n }\n\n function optionsFirst(options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(options, cb);\n }\n\n function wrappedHttpRequest(options: string | http.RequestOptions | URL, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(url: string | URL, options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(...args): http.ClientRequest {\n let options = {};\n let url: string | URL;\n let callback: (res: http.IncomingMessage) => void;\n\n if (args.length === 3) {\n [url, options, callback] = args;\n return urlFirst(url, options, callback);\n }\n [options, callback] = args;\n return optionsFirst(options, callback);\n }\n wrappedHttpRequest[kOutbreakWrapped] = true;\n http[originalMethodName] = wrappedHttpRequest;\n}\n\nfunction injectInFetchRequest(tracer: Tracer, headers: Headers): void {\n const currentTraceContext = tracer.getCurrentTrace()?.context;\n /* c8 ignore next 3 */\n if (!currentTraceContext) {\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n for (const header of currentTraceContext.keys()) {\n headers.set(header, currentTraceContext.get(header));\n }\n}\n\nfunction wrapFetch(tracer: Tracer): void {\n if (globalThis.fetch[kOutbreakWrapped]) {\n return;\n }\n const originalFetch = globalThis.fetch;\n globalThis.fetch = (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n if (isFetchRequest(input) && input.headers && !init?.headers) {\n injectInFetchRequest(tracer, input.headers);\n } else {\n init ??= {};\n init.headers ??= new Headers();\n if (!isFetchHeaders(init.headers)) {\n init.headers = new Headers(init.headers);\n }\n injectInFetchRequest(tracer, init.headers);\n }\n return originalFetch(input, init);\n };\n globalThis.fetch[kOutbreakWrapped] = true;\n}\n\nexport default function wrapHttp(config: LoadedConfig, tracer: Tracer): void {\n wrapHttpCreateServer(config, tracer);\n wrapHttpRequest(tracer, 'request');\n wrapHttpRequest(tracer, 'get');\n wrapFetch(tracer);\n}\n","const correlationIdHeader = 'x-trace-id';\n\nconst validateHeaderList = (headers: string[]): void => {\n if (!Array.isArray(headers)) {\n throw new Error('Header list is not an array');\n }\n\n // could be tighter - ASCII code between 33 and 126 at the moment\n const headerNameRegex = /^[\\x21-\\x7e]+$/i;\n\n const invalidHeaders = headers.filter((h) => typeof h !== 'string' || !headerNameRegex.test(h));\n\n if (invalidHeaders.length > 0) {\n throw new Error(`Header list contains invalid headers: ${invalidHeaders}`);\n }\n};\n\nexport interface Overrides {\n setAndPropagateCorrelationId?: boolean;\n headersToPropagate?: string[];\n headersPrefix?: string;\n}\n\nexport interface LoadedConfig extends Required<Pick<Overrides, 'setAndPropagateCorrelationId' | 'headersPrefix'>> {\n correlationIdHeader: string;\n headersToCollect: Set<string>;\n}\n\nconst load = (overrides: Overrides = {}): LoadedConfig => {\n const {\n setAndPropagateCorrelationId = true,\n headersToPropagate = [\n 'x-request-id',\n 'x-variant-id',\n ],\n headersPrefix = 'x-af-',\n } = overrides;\n\n validateHeaderList(headersToPropagate);\n\n return {\n setAndPropagateCorrelationId,\n correlationIdHeader,\n headersToCollect: new Set(headersToPropagate),\n headersPrefix,\n };\n};\n\nexport default {\n load,\n correlationIdHeader,\n};\n","import asyncHooks from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\nimport type { TraceType } from './const';\n\ninterface TraceHolder {\n currentTrace: Trace | null;\n traces: Record<number, Trace>;\n}\n\nexport class Trace {\n public readonly id = randomUUID();\n\n public readonly context = new Map<string, string>();\n\n constructor(public type: TraceType) {}\n}\n\nexport class Tracer {\n #isTraceEnabled = false;\n\n #prevStates = new Map<number, Trace>();\n\n #tracer: TraceHolder = {\n currentTrace: null,\n traces: {},\n };\n\n #hook = asyncHooks.createHook({\n init: (asyncId, _type, triggerAsyncId) => {\n if (!this.#tracer.traces[triggerAsyncId]) {\n return;\n }\n this.#tracer.traces[asyncId] = this.#tracer.traces[triggerAsyncId];\n },\n before: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#prevStates.set(asyncId, this.#tracer.currentTrace);\n this.#tracer.currentTrace = this.#tracer.traces[asyncId];\n },\n after: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#tracer.currentTrace = this.#prevStates.get(asyncId);\n },\n destroy: (asyncId) => {\n if (this.#tracer.traces[asyncId]) {\n delete this.#tracer.traces[asyncId];\n this.#prevStates.delete(asyncId);\n }\n },\n });\n\n public enable = (): asyncHooks.AsyncHook => {\n if (!this.#isTraceEnabled) {\n this.#hook.enable();\n this.#isTraceEnabled = true;\n }\n return this.#hook;\n };\n\n public newTrace = (type: TraceType): Trace => {\n if (!this.#isTraceEnabled) {\n this.enable();\n }\n const currentTrace = new Trace(type);\n this.#tracer.currentTrace = currentTrace;\n this.#tracer.traces[asyncHooks.executionAsyncId()] = currentTrace;\n return currentTrace;\n };\n\n public getCurrentTrace = (): Trace | Record<string, never> => this.#tracer.currentTrace || {};\n}\n","import winston, { format } from 'winston';\n\nimport httpWrapper from './http_wrapper';\nimport config, { type Overrides } from './config';\nimport { type Trace, Tracer } from './tracer';\n\nexport { traceTypes } from './const';\n\nconst tracer = new Tracer();\n\ninterface Options extends Overrides {\n winstonLogger?: winston.Logger;\n contextMiddlewareGetter?: (middleware: () => Record<string, unknown>) => void;\n loggerTraceKey? : string;\n}\n\nconst contextMiddleware = (loggerTraceKey: string) => ({\n [loggerTraceKey]: tracer.getCurrentTrace()?.context?.get(config.correlationIdHeader),\n});\nconst addMetadataToLog = (loggerTraceKey: string) => format((info) => Object.assign(info, contextMiddleware(loggerTraceKey)));\n\nexport default function outbreakInitialize(options: Options): void {\n httpWrapper(config.load(options), tracer);\n tracer.enable();\n\n const traceKey = options.loggerTraceKey || 'traceId';\n if (options.winstonLogger) {\n // eslint-disable-next-line no-param-reassign\n options.winstonLogger.format = format.combine(\n addMetadataToLog(traceKey)(),\n options.winstonLogger.format,\n );\n }\n options.contextMiddlewareGetter?.(() => contextMiddleware(traceKey));\n\n // Make an attempt to enable async hooks for bluebird, if available\n try {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n const bluebird = require('bluebird');\n bluebird.config({ asyncHooks: true });\n /* c8 ignore next */\n } catch (e) { /* ignore */ }\n}\n\nexport const getCurrentContext = (): Trace | Record<string, never> => tracer.getCurrentTrace();\n\nexport const { newTrace } = tracer;\n"]}
|
1
|
+
{"version":3,"sources":["../src/const.ts","../src/http_wrapper.ts","../src/config.ts","../src/tracer.ts","../src/index.ts"],"names":["traceTypes","kOutbreakWrapped","generateShortId","randomUUID","isFetchRequest","headers","isFetchHeaders","setAndCollectCorrelationId","config","tracer","req","res","correlationId","collect","headerName","value","wrappedListener","listener","next","error","wrapHttpCreateServer","http","originalHttpCreateServer","wrappedHttpCreateServer","options","inject","currentTraceContext","header","wrapHttpRequest","originalMethodName","originalMethod","urlFirst","url","cb","optionsFirst","wrappedHttpRequest","args","callback","injectInFetchRequest","wrapFetch","originalFetch","input","init","wrapHttp","correlationIdHeader","validateHeaderList","headerNameRegex","invalidHeaders","h","load","overrides","setAndPropagateCorrelationId","headersToPropagate","headersPrefix","config_default","Trace","type","Tracer","#isTraceEnabled","#prevStates","#tracer","#hook","asyncHooks","asyncId","_type","triggerAsyncId","currentTrace","safeRequire","createRequire","contextMiddleware","loggerTraceKey","addMetadataToLog","format","info","lazilySetupWinstonLogger","winstonLogger","traceKey","outbreakInitialize","getCurrentContext","newTrace"],"mappings":"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","file":"index.cjs","sourcesContent":["export const traceTypes = {\n HTTP_REQUEST: 'httpRequest',\n WEB_SOCKET: 'webSocket',\n RABBIT: 'rabbit',\n} as const;\nexport type TraceType = typeof traceTypes[keyof typeof traceTypes];\n","import http from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { URL } from 'node:url';\nimport { traceTypes } from './const';\nimport type { Tracer } from './tracer';\nimport type { LoadedConfig } from './config';\n\nexport const kOutbreakWrapped = Symbol('outbreak-wrapped');\nconst generateShortId = () => randomUUID().split('-')[0];\nconst isFetchRequest = (headers: unknown): headers is Request => headers instanceof Request || Object.prototype.toString.call(headers) === '[object Request]';\nconst isFetchHeaders = (headers: unknown): headers is Headers => headers instanceof Headers || Object.prototype.toString.call(headers) === '[object Headers]';\n\nfunction setAndCollectCorrelationId(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n const correlationId = req.headers[config.correlationIdHeader] ?? generateShortId();\n tracer.getCurrentTrace().context.set(config.correlationIdHeader, correlationId as string);\n res.setHeader(config.correlationIdHeader, correlationId);\n}\n\nfunction collect(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n if (config.setAndPropagateCorrelationId) {\n setAndCollectCorrelationId(config, tracer, req, res);\n }\n\n Object.entries(req.headers).forEach(([headerName, value]) => {\n const shouldCollect = config.headersToCollect.has(headerName) || headerName.startsWith(config.headersPrefix);\n if (shouldCollect && typeof value !== 'undefined') {\n tracer.getCurrentTrace().context.set(headerName, value as string);\n }\n });\n}\n\nfunction wrappedListener<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(\n config: LoadedConfig,\n tracer: Tracer,\n listener: http.RequestListener<Request, Response>,\n): http.RequestListener<Request, Response> {\n // @ts-expect-error we add next and error which don't exist on the original type\n return (req: http.IncomingMessage, res: http.ServerResponse, next: unknown, error: unknown): void => {\n tracer.newTrace(traceTypes.HTTP_REQUEST);\n\n collect(config, tracer, req, res);\n\n // @ts-expect-error we add next and error which don't exist on the original type\n listener(req, res, next, error);\n };\n}\n\nfunction wrapHttpCreateServer<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(config: LoadedConfig, tracer: Tracer): void {\n if (http.createServer[kOutbreakWrapped]) {\n return;\n }\n const originalHttpCreateServer = http.createServer;\n // args of http.createServer are ([options<Object>], [listener<Fn>]) Express only sends listener\n function wrappedHttpCreateServer(options: http.ServerOptions<Request, Response>, listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(\n options: http.ServerOptions<Request, Response> | http.RequestListener<Request, Response>,\n listener?: http.RequestListener<Request, Response>,\n ): http.Server<Request, Response> {\n listener = listener || options as http.RequestListener<Request, Response>;\n return originalHttpCreateServer<Request, Response>(wrappedListener(config, tracer, listener));\n }\n wrappedHttpCreateServer[kOutbreakWrapped] = true;\n http.createServer = wrappedHttpCreateServer;\n}\n\nfunction inject(tracer: Tracer, options: http.RequestOptions): void {\n const currentTraceContext = tracer.getCurrentTrace().context;\n if (currentTraceContext) {\n options.headers ||= {};\n [...(currentTraceContext.keys())].forEach((header) => {\n options.headers[header] = currentTraceContext.get(header);\n });\n }\n}\nfunction wrapHttpRequest(tracer: Tracer, originalMethodName: 'request' | 'get'): void {\n if (http[originalMethodName][kOutbreakWrapped]) {\n return;\n }\n const originalMethod = http[originalMethodName];\n function urlFirst(url: string | URL, options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(url, options, cb);\n }\n\n function optionsFirst(options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(options, cb);\n }\n\n function wrappedHttpRequest(options: string | http.RequestOptions | URL, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(url: string | URL, options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(...args): http.ClientRequest {\n let options = {};\n let url: string | URL;\n let callback: (res: http.IncomingMessage) => void;\n\n if (args.length === 3) {\n [url, options, callback] = args;\n return urlFirst(url, options, callback);\n }\n [options, callback] = args;\n return optionsFirst(options, callback);\n }\n wrappedHttpRequest[kOutbreakWrapped] = true;\n http[originalMethodName] = wrappedHttpRequest;\n}\n\nfunction injectInFetchRequest(tracer: Tracer, headers: Headers): void {\n const currentTraceContext = tracer.getCurrentTrace()?.context;\n /* c8 ignore next 3 */\n if (!currentTraceContext) {\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n for (const header of currentTraceContext.keys()) {\n headers.set(header, currentTraceContext.get(header));\n }\n}\n\nfunction wrapFetch(tracer: Tracer): void {\n if (globalThis.fetch[kOutbreakWrapped]) {\n return;\n }\n const originalFetch = globalThis.fetch;\n globalThis.fetch = (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n if (isFetchRequest(input) && input.headers && !init?.headers) {\n injectInFetchRequest(tracer, input.headers);\n } else {\n init ??= {};\n init.headers ??= new Headers();\n if (!isFetchHeaders(init.headers)) {\n init.headers = new Headers(init.headers);\n }\n injectInFetchRequest(tracer, init.headers);\n }\n return originalFetch(input, init);\n };\n globalThis.fetch[kOutbreakWrapped] = true;\n}\n\nexport default function wrapHttp(config: LoadedConfig, tracer: Tracer): void {\n wrapHttpCreateServer(config, tracer);\n wrapHttpRequest(tracer, 'request');\n wrapHttpRequest(tracer, 'get');\n wrapFetch(tracer);\n}\n","const correlationIdHeader = 'x-trace-id';\n\nconst validateHeaderList = (headers: string[]): void => {\n if (!Array.isArray(headers)) {\n throw new Error('Header list is not an array');\n }\n\n // could be tighter - ASCII code between 33 and 126 at the moment\n const headerNameRegex = /^[\\x21-\\x7e]+$/i;\n\n const invalidHeaders = headers.filter((h) => typeof h !== 'string' || !headerNameRegex.test(h));\n\n if (invalidHeaders.length > 0) {\n throw new Error(`Header list contains invalid headers: ${invalidHeaders}`);\n }\n};\n\nexport interface Overrides {\n setAndPropagateCorrelationId?: boolean;\n headersToPropagate?: string[];\n headersPrefix?: string;\n}\n\nexport interface LoadedConfig extends Required<Pick<Overrides, 'setAndPropagateCorrelationId' | 'headersPrefix'>> {\n correlationIdHeader: string;\n headersToCollect: Set<string>;\n}\n\nconst load = (overrides: Overrides = {}): LoadedConfig => {\n const {\n setAndPropagateCorrelationId = true,\n headersToPropagate = [\n 'x-request-id',\n 'x-variant-id',\n ],\n headersPrefix = 'x-af-',\n } = overrides;\n\n validateHeaderList(headersToPropagate);\n\n return {\n setAndPropagateCorrelationId,\n correlationIdHeader,\n headersToCollect: new Set(headersToPropagate),\n headersPrefix,\n };\n};\n\nexport default {\n load,\n correlationIdHeader,\n};\n","import asyncHooks from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\nimport type { TraceType } from './const';\n\ninterface TraceHolder {\n currentTrace: Trace | null;\n traces: Record<number, Trace>;\n}\n\nexport class Trace {\n public readonly id = randomUUID();\n\n public readonly context = new Map<string, string>();\n\n constructor(public type: TraceType) {}\n}\n\nexport class Tracer {\n #isTraceEnabled = false;\n\n #prevStates = new Map<number, Trace>();\n\n #tracer: TraceHolder = {\n currentTrace: null,\n traces: {},\n };\n\n #hook = asyncHooks.createHook({\n init: (asyncId, _type, triggerAsyncId) => {\n if (!this.#tracer.traces[triggerAsyncId]) {\n return;\n }\n this.#tracer.traces[asyncId] = this.#tracer.traces[triggerAsyncId];\n },\n before: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#prevStates.set(asyncId, this.#tracer.currentTrace);\n this.#tracer.currentTrace = this.#tracer.traces[asyncId];\n },\n after: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#tracer.currentTrace = this.#prevStates.get(asyncId);\n },\n destroy: (asyncId) => {\n if (this.#tracer.traces[asyncId]) {\n delete this.#tracer.traces[asyncId];\n this.#prevStates.delete(asyncId);\n }\n },\n });\n\n public enable = (): asyncHooks.AsyncHook => {\n if (!this.#isTraceEnabled) {\n this.#hook.enable();\n this.#isTraceEnabled = true;\n }\n return this.#hook;\n };\n\n public newTrace = (type: TraceType): Trace => {\n if (!this.#isTraceEnabled) {\n this.enable();\n }\n const currentTrace = new Trace(type);\n this.#tracer.currentTrace = currentTrace;\n this.#tracer.traces[asyncHooks.executionAsyncId()] = currentTrace;\n return currentTrace;\n };\n\n public getCurrentTrace = (): Trace | Record<string, never> => this.#tracer.currentTrace || {};\n}\n","import { createRequire } from 'node:module';\nimport type winston from 'winston';\nimport httpWrapper from './http_wrapper';\nimport config, { type Overrides } from './config';\nimport { type Trace, Tracer } from './tracer';\n\nexport { traceTypes } from './const';\n\nconst safeRequire = createRequire(import.meta.url);\n\nconst tracer = new Tracer();\n\ninterface Options extends Overrides {\n winstonLogger?: winston.Logger;\n contextMiddlewareGetter?: (middleware: () => Record<string, unknown>) => void;\n loggerTraceKey? : string;\n}\n\nconst contextMiddleware = (loggerTraceKey: string) => ({\n [loggerTraceKey]: tracer.getCurrentTrace()?.context?.get(config.correlationIdHeader),\n});\nconst addMetadataToLog = (loggerTraceKey: string, format: typeof winston.format) => format((info) => Object.assign(info, contextMiddleware(loggerTraceKey)));\n\nfunction lazilySetupWinstonLogger(winstonLogger: winston.Logger, traceKey: string): void {\n const { format } = safeRequire('winston');\n winstonLogger.format = format.combine(\n addMetadataToLog(traceKey, format)(),\n winstonLogger.format,\n );\n}\n\nexport default function outbreakInitialize(options: Options): void {\n httpWrapper(config.load(options), tracer);\n tracer.enable();\n\n const traceKey = options.loggerTraceKey || 'traceId';\n if (options.winstonLogger) {\n lazilySetupWinstonLogger(options.winstonLogger, traceKey);\n }\n options.contextMiddlewareGetter?.(() => contextMiddleware(traceKey));\n\n // Make an attempt to enable async hooks for bluebird, if available\n try {\n const bluebird = safeRequire('bluebird');\n bluebird.config({ asyncHooks: true });\n /* c8 ignore next */\n } catch (e) { /* ignore */ }\n}\n\nexport const getCurrentContext = (): Trace | Record<string, never> => tracer.getCurrentTrace();\n\nexport const { newTrace } = tracer;\n"]}
|
package/dist/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
import {
|
1
|
+
import {createRequire}from'node:module';import c from'node:http';import {randomUUID}from'node:crypto';import w from'node:async_hooks';var f={HTTP_REQUEST:"httpRequest",WEB_SOCKET:"webSocket",RABBIT:"rabbit"};var p=Symbol("outbreak-wrapped"),H=()=>randomUUID().split("-")[0],S=t=>t instanceof Request||Object.prototype.toString.call(t)==="[object Request]",I=t=>t instanceof Headers||Object.prototype.toString.call(t)==="[object Headers]";function L(t,e,r,s){let o=r.headers[t.correlationIdHeader]??H();e.getCurrentTrace().context.set(t.correlationIdHeader,o),s.setHeader(t.correlationIdHeader,o);}function k(t,e,r,s){t.setAndPropagateCorrelationId&&L(t,e,r,s),Object.entries(r.headers).forEach(([o,n])=>{(t.headersToCollect.has(o)||o.startsWith(t.headersPrefix))&&typeof n<"u"&&e.getCurrentTrace().context.set(o,n);});}function O(t,e,r){return (s,o,n,a)=>{e.newTrace(f.HTTP_REQUEST),k(t,e,s,o),r(s,o,n,a);}}function M(t,e){if(c.createServer[p])return;let r=c.createServer;function s(o,n){return n=n||o,r(O(t,e,n))}s[p]=true,c.createServer=s;}function m(t,e){let r=t.getCurrentTrace().context;r&&(e.headers||={},[...r.keys()].forEach(s=>{e.headers[s]=r.get(s);}));}function v(t,e){if(c[e][p])return;let r=c[e];function s(a,i,u){return m(t,i),r(a,i,u)}function o(a,i){return m(t,a),r(a,i)}function n(...a){let i={},u,h;return a.length===3?([u,i,h]=a,s(u,i,h)):([i,h]=a,o(i,h))}n[p]=true,c[e]=n;}function q(t,e){let r=t.getCurrentTrace()?.context;if(r)for(let s of r.keys())e.set(s,r.get(s));}function P(t){if(globalThis.fetch[p])return;let e=globalThis.fetch;globalThis.fetch=(r,s)=>(S(r)&&r.headers&&!s?.headers?q(t,r.headers):(s??={},s.headers??=new Headers,I(s.headers)||(s.headers=new Headers(s.headers)),q(t,s.headers)),e(r,s)),globalThis.fetch[p]=true;}function g(t,e){M(t,e),v(e,"request"),v(e,"get"),P(e);}var y="x-trace-id",U=t=>{if(!Array.isArray(t))throw new Error("Header list is not an array");let e=/^[\x21-\x7e]+$/i,r=t.filter(s=>typeof s!="string"||!e.test(s));if(r.length>0)throw new Error(`Header list contains invalid headers: ${r}`)},E=(t={})=>{let{setAndPropagateCorrelationId:e=true,headersToPropagate:r=["x-request-id","x-variant-id"],headersPrefix:s="x-af-"}=t;return U(r),{setAndPropagateCorrelationId:e,correlationIdHeader:y,headersToCollect:new Set(r),headersPrefix:s}},R={load:E,correlationIdHeader:y};var T=class{constructor(e){this.type=e;this.id=randomUUID();this.context=new Map;}},l=class{constructor(){this.#t=false;this.#r=new Map;this.#e={currentTrace:null,traces:{}};this.#s=w.createHook({init:(e,r,s)=>{this.#e.traces[s]&&(this.#e.traces[e]=this.#e.traces[s]);},before:e=>{this.#e.traces[e]&&(this.#r.set(e,this.#e.currentTrace),this.#e.currentTrace=this.#e.traces[e]);},after:e=>{this.#e.traces[e]&&(this.#e.currentTrace=this.#r.get(e));},destroy:e=>{this.#e.traces[e]&&(delete this.#e.traces[e],this.#r.delete(e));}});this.enable=()=>(this.#t||(this.#s.enable(),this.#t=true),this.#s);this.newTrace=e=>{this.#t||this.enable();let r=new T(e);return this.#e.currentTrace=r,this.#e.traces[w.executionAsyncId()]=r,r};this.getCurrentTrace=()=>this.#e.currentTrace||{};}#t;#r;#e;#s};var x=createRequire(import.meta.url),d=new l,b=t=>({[t]:d.getCurrentTrace()?.context?.get(R.correlationIdHeader)}),F=(t,e)=>e(r=>Object.assign(r,b(t)));function W(t,e){let{format:r}=x("winston");t.format=r.combine(F(e,r)(),t.format);}function K(t){g(R.load(t),d),d.enable();let e=t.loggerTraceKey||"traceId";t.winstonLogger&&W(t.winstonLogger,e),t.contextMiddlewareGetter?.(()=>b(e));try{x("bluebird").config({asyncHooks:!0});}catch{}}var ee=()=>d.getCurrentTrace(),{newTrace:te}=d;export{K as default,ee as getCurrentContext,te as newTrace,f as traceTypes};//# sourceMappingURL=index.js.map
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/const.ts","../src/http_wrapper.ts","../src/config.ts","../src/tracer.ts","../src/index.ts"],"names":["traceTypes","kOutbreakWrapped","generateShortId","randomUUID","isFetchRequest","headers","isFetchHeaders","setAndCollectCorrelationId","config","tracer","req","res","correlationId","collect","headerName","value","wrappedListener","listener","next","error","wrapHttpCreateServer","http","originalHttpCreateServer","wrappedHttpCreateServer","options","inject","currentTraceContext","header","wrapHttpRequest","originalMethodName","originalMethod","urlFirst","url","cb","optionsFirst","wrappedHttpRequest","args","callback","injectInFetchRequest","wrapFetch","originalFetch","input","init","wrapHttp","correlationIdHeader","validateHeaderList","headerNameRegex","invalidHeaders","h","load","overrides","setAndPropagateCorrelationId","headersToPropagate","headersPrefix","config_default","Trace","type","Tracer","#isTraceEnabled","#prevStates","#tracer","#hook","asyncHooks","asyncId","_type","triggerAsyncId","currentTrace","contextMiddleware","loggerTraceKey","addMetadataToLog","format","info","outbreakInitialize","traceKey","getCurrentContext","newTrace"],"mappings":"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","file":"index.js","sourcesContent":["export const traceTypes = {\n HTTP_REQUEST: 'httpRequest',\n WEB_SOCKET: 'webSocket',\n RABBIT: 'rabbit',\n} as const;\nexport type TraceType = typeof traceTypes[keyof typeof traceTypes];\n","import http from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { URL } from 'node:url';\nimport { traceTypes } from './const';\nimport type { Tracer } from './tracer';\nimport type { LoadedConfig } from './config';\n\nexport const kOutbreakWrapped = Symbol('outbreak-wrapped');\nconst generateShortId = () => randomUUID().split('-')[0];\nconst isFetchRequest = (headers: unknown): headers is Request => headers instanceof Request || Object.prototype.toString.call(headers) === '[object Request]';\nconst isFetchHeaders = (headers: unknown): headers is Headers => headers instanceof Headers || Object.prototype.toString.call(headers) === '[object Headers]';\n\nfunction setAndCollectCorrelationId(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n const correlationId = req.headers[config.correlationIdHeader] ?? generateShortId();\n tracer.getCurrentTrace().context.set(config.correlationIdHeader, correlationId as string);\n res.setHeader(config.correlationIdHeader, correlationId);\n}\n\nfunction collect(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n if (config.setAndPropagateCorrelationId) {\n setAndCollectCorrelationId(config, tracer, req, res);\n }\n\n Object.entries(req.headers).forEach(([headerName, value]) => {\n const shouldCollect = config.headersToCollect.has(headerName) || headerName.startsWith(config.headersPrefix);\n if (shouldCollect && typeof value !== 'undefined') {\n tracer.getCurrentTrace().context.set(headerName, value as string);\n }\n });\n}\n\nfunction wrappedListener<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(\n config: LoadedConfig,\n tracer: Tracer,\n listener: http.RequestListener<Request, Response>,\n): http.RequestListener<Request, Response> {\n // @ts-expect-error we add next and error which don't exist on the original type\n return (req: http.IncomingMessage, res: http.ServerResponse, next: unknown, error: unknown): void => {\n tracer.newTrace(traceTypes.HTTP_REQUEST);\n\n collect(config, tracer, req, res);\n\n // @ts-expect-error we add next and error which don't exist on the original type\n listener(req, res, next, error);\n };\n}\n\nfunction wrapHttpCreateServer<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(config: LoadedConfig, tracer: Tracer): void {\n if (http.createServer[kOutbreakWrapped]) {\n return;\n }\n const originalHttpCreateServer = http.createServer;\n // args of http.createServer are ([options<Object>], [listener<Fn>]) Express only sends listener\n function wrappedHttpCreateServer(options: http.ServerOptions<Request, Response>, listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(\n options: http.ServerOptions<Request, Response> | http.RequestListener<Request, Response>,\n listener?: http.RequestListener<Request, Response>,\n ): http.Server<Request, Response> {\n listener = listener || options as http.RequestListener<Request, Response>;\n return originalHttpCreateServer<Request, Response>(wrappedListener(config, tracer, listener));\n }\n wrappedHttpCreateServer[kOutbreakWrapped] = true;\n http.createServer = wrappedHttpCreateServer;\n}\n\nfunction inject(tracer: Tracer, options: http.RequestOptions): void {\n const currentTraceContext = tracer.getCurrentTrace().context;\n if (currentTraceContext) {\n options.headers ||= {};\n [...(currentTraceContext.keys())].forEach((header) => {\n options.headers[header] = currentTraceContext.get(header);\n });\n }\n}\nfunction wrapHttpRequest(tracer: Tracer, originalMethodName: 'request' | 'get'): void {\n if (http[originalMethodName][kOutbreakWrapped]) {\n return;\n }\n const originalMethod = http[originalMethodName];\n function urlFirst(url: string | URL, options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(url, options, cb);\n }\n\n function optionsFirst(options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(options, cb);\n }\n\n function wrappedHttpRequest(options: string | http.RequestOptions | URL, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(url: string | URL, options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(...args): http.ClientRequest {\n let options = {};\n let url: string | URL;\n let callback: (res: http.IncomingMessage) => void;\n\n if (args.length === 3) {\n [url, options, callback] = args;\n return urlFirst(url, options, callback);\n }\n [options, callback] = args;\n return optionsFirst(options, callback);\n }\n wrappedHttpRequest[kOutbreakWrapped] = true;\n http[originalMethodName] = wrappedHttpRequest;\n}\n\nfunction injectInFetchRequest(tracer: Tracer, headers: Headers): void {\n const currentTraceContext = tracer.getCurrentTrace()?.context;\n /* c8 ignore next 3 */\n if (!currentTraceContext) {\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n for (const header of currentTraceContext.keys()) {\n headers.set(header, currentTraceContext.get(header));\n }\n}\n\nfunction wrapFetch(tracer: Tracer): void {\n if (globalThis.fetch[kOutbreakWrapped]) {\n return;\n }\n const originalFetch = globalThis.fetch;\n globalThis.fetch = (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n if (isFetchRequest(input) && input.headers && !init?.headers) {\n injectInFetchRequest(tracer, input.headers);\n } else {\n init ??= {};\n init.headers ??= new Headers();\n if (!isFetchHeaders(init.headers)) {\n init.headers = new Headers(init.headers);\n }\n injectInFetchRequest(tracer, init.headers);\n }\n return originalFetch(input, init);\n };\n globalThis.fetch[kOutbreakWrapped] = true;\n}\n\nexport default function wrapHttp(config: LoadedConfig, tracer: Tracer): void {\n wrapHttpCreateServer(config, tracer);\n wrapHttpRequest(tracer, 'request');\n wrapHttpRequest(tracer, 'get');\n wrapFetch(tracer);\n}\n","const correlationIdHeader = 'x-trace-id';\n\nconst validateHeaderList = (headers: string[]): void => {\n if (!Array.isArray(headers)) {\n throw new Error('Header list is not an array');\n }\n\n // could be tighter - ASCII code between 33 and 126 at the moment\n const headerNameRegex = /^[\\x21-\\x7e]+$/i;\n\n const invalidHeaders = headers.filter((h) => typeof h !== 'string' || !headerNameRegex.test(h));\n\n if (invalidHeaders.length > 0) {\n throw new Error(`Header list contains invalid headers: ${invalidHeaders}`);\n }\n};\n\nexport interface Overrides {\n setAndPropagateCorrelationId?: boolean;\n headersToPropagate?: string[];\n headersPrefix?: string;\n}\n\nexport interface LoadedConfig extends Required<Pick<Overrides, 'setAndPropagateCorrelationId' | 'headersPrefix'>> {\n correlationIdHeader: string;\n headersToCollect: Set<string>;\n}\n\nconst load = (overrides: Overrides = {}): LoadedConfig => {\n const {\n setAndPropagateCorrelationId = true,\n headersToPropagate = [\n 'x-request-id',\n 'x-variant-id',\n ],\n headersPrefix = 'x-af-',\n } = overrides;\n\n validateHeaderList(headersToPropagate);\n\n return {\n setAndPropagateCorrelationId,\n correlationIdHeader,\n headersToCollect: new Set(headersToPropagate),\n headersPrefix,\n };\n};\n\nexport default {\n load,\n correlationIdHeader,\n};\n","import asyncHooks from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\nimport type { TraceType } from './const';\n\ninterface TraceHolder {\n currentTrace: Trace | null;\n traces: Record<number, Trace>;\n}\n\nexport class Trace {\n public readonly id = randomUUID();\n\n public readonly context = new Map<string, string>();\n\n constructor(public type: TraceType) {}\n}\n\nexport class Tracer {\n #isTraceEnabled = false;\n\n #prevStates = new Map<number, Trace>();\n\n #tracer: TraceHolder = {\n currentTrace: null,\n traces: {},\n };\n\n #hook = asyncHooks.createHook({\n init: (asyncId, _type, triggerAsyncId) => {\n if (!this.#tracer.traces[triggerAsyncId]) {\n return;\n }\n this.#tracer.traces[asyncId] = this.#tracer.traces[triggerAsyncId];\n },\n before: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#prevStates.set(asyncId, this.#tracer.currentTrace);\n this.#tracer.currentTrace = this.#tracer.traces[asyncId];\n },\n after: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#tracer.currentTrace = this.#prevStates.get(asyncId);\n },\n destroy: (asyncId) => {\n if (this.#tracer.traces[asyncId]) {\n delete this.#tracer.traces[asyncId];\n this.#prevStates.delete(asyncId);\n }\n },\n });\n\n public enable = (): asyncHooks.AsyncHook => {\n if (!this.#isTraceEnabled) {\n this.#hook.enable();\n this.#isTraceEnabled = true;\n }\n return this.#hook;\n };\n\n public newTrace = (type: TraceType): Trace => {\n if (!this.#isTraceEnabled) {\n this.enable();\n }\n const currentTrace = new Trace(type);\n this.#tracer.currentTrace = currentTrace;\n this.#tracer.traces[asyncHooks.executionAsyncId()] = currentTrace;\n return currentTrace;\n };\n\n public getCurrentTrace = (): Trace | Record<string, never> => this.#tracer.currentTrace || {};\n}\n","import winston, { format } from 'winston';\n\nimport httpWrapper from './http_wrapper';\nimport config, { type Overrides } from './config';\nimport { type Trace, Tracer } from './tracer';\n\nexport { traceTypes } from './const';\n\nconst tracer = new Tracer();\n\ninterface Options extends Overrides {\n winstonLogger?: winston.Logger;\n contextMiddlewareGetter?: (middleware: () => Record<string, unknown>) => void;\n loggerTraceKey? : string;\n}\n\nconst contextMiddleware = (loggerTraceKey: string) => ({\n [loggerTraceKey]: tracer.getCurrentTrace()?.context?.get(config.correlationIdHeader),\n});\nconst addMetadataToLog = (loggerTraceKey: string) => format((info) => Object.assign(info, contextMiddleware(loggerTraceKey)));\n\nexport default function outbreakInitialize(options: Options): void {\n httpWrapper(config.load(options), tracer);\n tracer.enable();\n\n const traceKey = options.loggerTraceKey || 'traceId';\n if (options.winstonLogger) {\n // eslint-disable-next-line no-param-reassign\n options.winstonLogger.format = format.combine(\n addMetadataToLog(traceKey)(),\n options.winstonLogger.format,\n );\n }\n options.contextMiddlewareGetter?.(() => contextMiddleware(traceKey));\n\n // Make an attempt to enable async hooks for bluebird, if available\n try {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n const bluebird = require('bluebird');\n bluebird.config({ asyncHooks: true });\n /* c8 ignore next */\n } catch (e) { /* ignore */ }\n}\n\nexport const getCurrentContext = (): Trace | Record<string, never> => tracer.getCurrentTrace();\n\nexport const { newTrace } = tracer;\n"]}
|
1
|
+
{"version":3,"sources":["../src/const.ts","../src/http_wrapper.ts","../src/config.ts","../src/tracer.ts","../src/index.ts"],"names":["traceTypes","kOutbreakWrapped","generateShortId","randomUUID","isFetchRequest","headers","isFetchHeaders","setAndCollectCorrelationId","config","tracer","req","res","correlationId","collect","headerName","value","wrappedListener","listener","next","error","wrapHttpCreateServer","http","originalHttpCreateServer","wrappedHttpCreateServer","options","inject","currentTraceContext","header","wrapHttpRequest","originalMethodName","originalMethod","urlFirst","url","cb","optionsFirst","wrappedHttpRequest","args","callback","injectInFetchRequest","wrapFetch","originalFetch","input","init","wrapHttp","correlationIdHeader","validateHeaderList","headerNameRegex","invalidHeaders","h","load","overrides","setAndPropagateCorrelationId","headersToPropagate","headersPrefix","config_default","Trace","type","Tracer","#isTraceEnabled","#prevStates","#tracer","#hook","asyncHooks","asyncId","_type","triggerAsyncId","currentTrace","safeRequire","createRequire","contextMiddleware","loggerTraceKey","addMetadataToLog","format","info","lazilySetupWinstonLogger","winstonLogger","traceKey","outbreakInitialize","getCurrentContext","newTrace"],"mappings":"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","file":"index.js","sourcesContent":["export const traceTypes = {\n HTTP_REQUEST: 'httpRequest',\n WEB_SOCKET: 'webSocket',\n RABBIT: 'rabbit',\n} as const;\nexport type TraceType = typeof traceTypes[keyof typeof traceTypes];\n","import http from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { URL } from 'node:url';\nimport { traceTypes } from './const';\nimport type { Tracer } from './tracer';\nimport type { LoadedConfig } from './config';\n\nexport const kOutbreakWrapped = Symbol('outbreak-wrapped');\nconst generateShortId = () => randomUUID().split('-')[0];\nconst isFetchRequest = (headers: unknown): headers is Request => headers instanceof Request || Object.prototype.toString.call(headers) === '[object Request]';\nconst isFetchHeaders = (headers: unknown): headers is Headers => headers instanceof Headers || Object.prototype.toString.call(headers) === '[object Headers]';\n\nfunction setAndCollectCorrelationId(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n const correlationId = req.headers[config.correlationIdHeader] ?? generateShortId();\n tracer.getCurrentTrace().context.set(config.correlationIdHeader, correlationId as string);\n res.setHeader(config.correlationIdHeader, correlationId);\n}\n\nfunction collect(config: LoadedConfig, tracer: Tracer, req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): void {\n if (config.setAndPropagateCorrelationId) {\n setAndCollectCorrelationId(config, tracer, req, res);\n }\n\n Object.entries(req.headers).forEach(([headerName, value]) => {\n const shouldCollect = config.headersToCollect.has(headerName) || headerName.startsWith(config.headersPrefix);\n if (shouldCollect && typeof value !== 'undefined') {\n tracer.getCurrentTrace().context.set(headerName, value as string);\n }\n });\n}\n\nfunction wrappedListener<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(\n config: LoadedConfig,\n tracer: Tracer,\n listener: http.RequestListener<Request, Response>,\n): http.RequestListener<Request, Response> {\n // @ts-expect-error we add next and error which don't exist on the original type\n return (req: http.IncomingMessage, res: http.ServerResponse, next: unknown, error: unknown): void => {\n tracer.newTrace(traceTypes.HTTP_REQUEST);\n\n collect(config, tracer, req, res);\n\n // @ts-expect-error we add next and error which don't exist on the original type\n listener(req, res, next, error);\n };\n}\n\nfunction wrapHttpCreateServer<\n Request extends typeof http.IncomingMessage = typeof http.IncomingMessage,\n Response extends typeof http.ServerResponse = typeof http.ServerResponse,\n>(config: LoadedConfig, tracer: Tracer): void {\n if (http.createServer[kOutbreakWrapped]) {\n return;\n }\n const originalHttpCreateServer = http.createServer;\n // args of http.createServer are ([options<Object>], [listener<Fn>]) Express only sends listener\n function wrappedHttpCreateServer(options: http.ServerOptions<Request, Response>, listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(listener?: http.RequestListener<Request, Response>): http.Server<Request, Response>;\n function wrappedHttpCreateServer(\n options: http.ServerOptions<Request, Response> | http.RequestListener<Request, Response>,\n listener?: http.RequestListener<Request, Response>,\n ): http.Server<Request, Response> {\n listener = listener || options as http.RequestListener<Request, Response>;\n return originalHttpCreateServer<Request, Response>(wrappedListener(config, tracer, listener));\n }\n wrappedHttpCreateServer[kOutbreakWrapped] = true;\n http.createServer = wrappedHttpCreateServer;\n}\n\nfunction inject(tracer: Tracer, options: http.RequestOptions): void {\n const currentTraceContext = tracer.getCurrentTrace().context;\n if (currentTraceContext) {\n options.headers ||= {};\n [...(currentTraceContext.keys())].forEach((header) => {\n options.headers[header] = currentTraceContext.get(header);\n });\n }\n}\nfunction wrapHttpRequest(tracer: Tracer, originalMethodName: 'request' | 'get'): void {\n if (http[originalMethodName][kOutbreakWrapped]) {\n return;\n }\n const originalMethod = http[originalMethodName];\n function urlFirst(url: string | URL, options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(url, options, cb);\n }\n\n function optionsFirst(options: http.RequestOptions, cb: (res: http.IncomingMessage) => void): http.ClientRequest {\n inject(tracer, options);\n\n return originalMethod(options, cb);\n }\n\n function wrappedHttpRequest(options: string | http.RequestOptions | URL, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(url: string | URL, options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;\n function wrappedHttpRequest(...args): http.ClientRequest {\n let options = {};\n let url: string | URL;\n let callback: (res: http.IncomingMessage) => void;\n\n if (args.length === 3) {\n [url, options, callback] = args;\n return urlFirst(url, options, callback);\n }\n [options, callback] = args;\n return optionsFirst(options, callback);\n }\n wrappedHttpRequest[kOutbreakWrapped] = true;\n http[originalMethodName] = wrappedHttpRequest;\n}\n\nfunction injectInFetchRequest(tracer: Tracer, headers: Headers): void {\n const currentTraceContext = tracer.getCurrentTrace()?.context;\n /* c8 ignore next 3 */\n if (!currentTraceContext) {\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n for (const header of currentTraceContext.keys()) {\n headers.set(header, currentTraceContext.get(header));\n }\n}\n\nfunction wrapFetch(tracer: Tracer): void {\n if (globalThis.fetch[kOutbreakWrapped]) {\n return;\n }\n const originalFetch = globalThis.fetch;\n globalThis.fetch = (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n if (isFetchRequest(input) && input.headers && !init?.headers) {\n injectInFetchRequest(tracer, input.headers);\n } else {\n init ??= {};\n init.headers ??= new Headers();\n if (!isFetchHeaders(init.headers)) {\n init.headers = new Headers(init.headers);\n }\n injectInFetchRequest(tracer, init.headers);\n }\n return originalFetch(input, init);\n };\n globalThis.fetch[kOutbreakWrapped] = true;\n}\n\nexport default function wrapHttp(config: LoadedConfig, tracer: Tracer): void {\n wrapHttpCreateServer(config, tracer);\n wrapHttpRequest(tracer, 'request');\n wrapHttpRequest(tracer, 'get');\n wrapFetch(tracer);\n}\n","const correlationIdHeader = 'x-trace-id';\n\nconst validateHeaderList = (headers: string[]): void => {\n if (!Array.isArray(headers)) {\n throw new Error('Header list is not an array');\n }\n\n // could be tighter - ASCII code between 33 and 126 at the moment\n const headerNameRegex = /^[\\x21-\\x7e]+$/i;\n\n const invalidHeaders = headers.filter((h) => typeof h !== 'string' || !headerNameRegex.test(h));\n\n if (invalidHeaders.length > 0) {\n throw new Error(`Header list contains invalid headers: ${invalidHeaders}`);\n }\n};\n\nexport interface Overrides {\n setAndPropagateCorrelationId?: boolean;\n headersToPropagate?: string[];\n headersPrefix?: string;\n}\n\nexport interface LoadedConfig extends Required<Pick<Overrides, 'setAndPropagateCorrelationId' | 'headersPrefix'>> {\n correlationIdHeader: string;\n headersToCollect: Set<string>;\n}\n\nconst load = (overrides: Overrides = {}): LoadedConfig => {\n const {\n setAndPropagateCorrelationId = true,\n headersToPropagate = [\n 'x-request-id',\n 'x-variant-id',\n ],\n headersPrefix = 'x-af-',\n } = overrides;\n\n validateHeaderList(headersToPropagate);\n\n return {\n setAndPropagateCorrelationId,\n correlationIdHeader,\n headersToCollect: new Set(headersToPropagate),\n headersPrefix,\n };\n};\n\nexport default {\n load,\n correlationIdHeader,\n};\n","import asyncHooks from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\nimport type { TraceType } from './const';\n\ninterface TraceHolder {\n currentTrace: Trace | null;\n traces: Record<number, Trace>;\n}\n\nexport class Trace {\n public readonly id = randomUUID();\n\n public readonly context = new Map<string, string>();\n\n constructor(public type: TraceType) {}\n}\n\nexport class Tracer {\n #isTraceEnabled = false;\n\n #prevStates = new Map<number, Trace>();\n\n #tracer: TraceHolder = {\n currentTrace: null,\n traces: {},\n };\n\n #hook = asyncHooks.createHook({\n init: (asyncId, _type, triggerAsyncId) => {\n if (!this.#tracer.traces[triggerAsyncId]) {\n return;\n }\n this.#tracer.traces[asyncId] = this.#tracer.traces[triggerAsyncId];\n },\n before: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#prevStates.set(asyncId, this.#tracer.currentTrace);\n this.#tracer.currentTrace = this.#tracer.traces[asyncId];\n },\n after: (asyncId) => {\n if (!this.#tracer.traces[asyncId]) {\n return;\n }\n this.#tracer.currentTrace = this.#prevStates.get(asyncId);\n },\n destroy: (asyncId) => {\n if (this.#tracer.traces[asyncId]) {\n delete this.#tracer.traces[asyncId];\n this.#prevStates.delete(asyncId);\n }\n },\n });\n\n public enable = (): asyncHooks.AsyncHook => {\n if (!this.#isTraceEnabled) {\n this.#hook.enable();\n this.#isTraceEnabled = true;\n }\n return this.#hook;\n };\n\n public newTrace = (type: TraceType): Trace => {\n if (!this.#isTraceEnabled) {\n this.enable();\n }\n const currentTrace = new Trace(type);\n this.#tracer.currentTrace = currentTrace;\n this.#tracer.traces[asyncHooks.executionAsyncId()] = currentTrace;\n return currentTrace;\n };\n\n public getCurrentTrace = (): Trace | Record<string, never> => this.#tracer.currentTrace || {};\n}\n","import { createRequire } from 'node:module';\nimport type winston from 'winston';\nimport httpWrapper from './http_wrapper';\nimport config, { type Overrides } from './config';\nimport { type Trace, Tracer } from './tracer';\n\nexport { traceTypes } from './const';\n\nconst safeRequire = createRequire(import.meta.url);\n\nconst tracer = new Tracer();\n\ninterface Options extends Overrides {\n winstonLogger?: winston.Logger;\n contextMiddlewareGetter?: (middleware: () => Record<string, unknown>) => void;\n loggerTraceKey? : string;\n}\n\nconst contextMiddleware = (loggerTraceKey: string) => ({\n [loggerTraceKey]: tracer.getCurrentTrace()?.context?.get(config.correlationIdHeader),\n});\nconst addMetadataToLog = (loggerTraceKey: string, format: typeof winston.format) => format((info) => Object.assign(info, contextMiddleware(loggerTraceKey)));\n\nfunction lazilySetupWinstonLogger(winstonLogger: winston.Logger, traceKey: string): void {\n const { format } = safeRequire('winston');\n winstonLogger.format = format.combine(\n addMetadataToLog(traceKey, format)(),\n winstonLogger.format,\n );\n}\n\nexport default function outbreakInitialize(options: Options): void {\n httpWrapper(config.load(options), tracer);\n tracer.enable();\n\n const traceKey = options.loggerTraceKey || 'traceId';\n if (options.winstonLogger) {\n lazilySetupWinstonLogger(options.winstonLogger, traceKey);\n }\n options.contextMiddlewareGetter?.(() => contextMiddleware(traceKey));\n\n // Make an attempt to enable async hooks for bluebird, if available\n try {\n const bluebird = safeRequire('bluebird');\n bluebird.config({ asyncHooks: true });\n /* c8 ignore next */\n } catch (e) { /* ignore */ }\n}\n\nexport const getCurrentContext = (): Trace | Record<string, never> => tracer.getCurrentTrace();\n\nexport const { newTrace } = tracer;\n"]}
|