@embrace-io/web-sdk
Version:
1 lines • 6.68 kB
Source Map (JSON)
{"version":3,"file":"EmbraceSessionPartBatchedSpanProcessor.cjs","names":["diag","BindOnceFuture","isSessionPartSpan","ExportResultCode"],"sources":["../../../src/processors/EmbraceSessionPartBatchedSpanProcessor/EmbraceSessionPartBatchedSpanProcessor.ts"],"sourcesContent":["import type { DiagLogger } from '@opentelemetry/api';\nimport { diag } from '@opentelemetry/api';\nimport type { ExportResult } from '@opentelemetry/core';\nimport {\n BindOnceFuture,\n ExportResultCode,\n // TODO: `internal._export` is an unstable OTel API; find a supported way to export a batch\n internal,\n} from '@opentelemetry/core';\nimport type {\n ReadableSpan,\n SpanExporter,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace';\nimport type {\n LimitManagerInternal,\n UserSessionManagerInternal,\n} from '../../managers/index.ts';\nimport { isSessionPartSpan } from '../../utils/index.ts';\nimport type { EmbraceSessionPartBatchedSpanProcessorArgs } from './types.ts';\n\ntype ExportFailureReason = 'concurrent_limit' | 'fetch_error' | 'unknown';\n\nconst exportFailureAttributeKey = (\n reason: ExportFailureReason,\n session: 'current' | 'previous',\n) =>\n `emb.${session === 'current' ? 'export_failed' : 'previous_export_failed'}.${reason}`;\n\nexport class EmbraceSessionPartBatchedSpanProcessor implements SpanProcessor {\n private readonly _shutdownOnce: BindOnceFuture<void>;\n private _pendingSpans: ReadableSpan[] = [];\n private readonly _exporter: SpanExporter;\n private readonly _limitManager: LimitManagerInternal;\n private readonly _userSessionManager: UserSessionManagerInternal;\n private readonly _diag: DiagLogger;\n\n public constructor({\n exporter,\n limitManager,\n userSessionManager,\n diag: diagParam = diag.createComponentLogger({\n namespace: 'EmbraceSessionPartBatchedSpanProcessor',\n }),\n }: EmbraceSessionPartBatchedSpanProcessorArgs) {\n this._diag = diagParam;\n this._exporter = exporter;\n this._shutdownOnce = new BindOnceFuture(this._shutdown, this);\n this._limitManager = limitManager;\n this._userSessionManager = userSessionManager;\n }\n\n public forceFlush(): Promise<void> {\n this._diag.debug(\n 'forceFlush called for EmbraceSessionPartBatchedSpanProcessor. This is a no op',\n );\n return Promise.resolve(undefined);\n }\n\n public onEnd(span: ReadableSpan): void {\n if (this._shutdownOnce.isCalled) {\n this._diag.debug('span ended after processor shutdown. Ignoring span.');\n return;\n }\n\n if (!isSessionPartSpan(span)) {\n this._diag.debug(\n 'non-session-part span ended. Adding to pending spans queue.',\n );\n if (this._limitManager.dropReadableSpan(span)) {\n return;\n }\n this._pendingSpans.push(span);\n } else {\n this._diag.debug('session part span ended. Exporting all pending spans.');\n this._exportSpans([span, ...this._pendingSpans]);\n this._pendingSpans = [];\n }\n }\n\n private _exportSpans(spans: ReadableSpan[]): void {\n internal\n ._export(this._exporter, spans)\n .then((result: ExportResult) => {\n if (result.code === ExportResultCode.FAILED) {\n const errorMessage = result.error?.message || 'unknown error';\n let failureReason: ExportFailureReason = 'unknown';\n\n if (errorMessage === 'Concurrent export limit reached') {\n failureReason = 'concurrent_limit';\n } else if (errorMessage === 'Fetch request errored') {\n failureReason = 'fetch_error';\n }\n\n this._userSessionManager.incrSessionPartCountForKey(\n exportFailureAttributeKey(failureReason, 'current'),\n );\n this._userSessionManager.incrNextSessionPartCountForKey(\n exportFailureAttributeKey(failureReason, 'previous'),\n );\n this._diag.error(`spans failed to export: ${errorMessage}`);\n }\n })\n // Seems like everything related to the export logic does a good job of catching and only ever resolving with\n // an ExportResult even on failure: https://github.com/open-telemetry/opentelemetry-js/blob/cf6dffeebcf72c42b2cb4d2bf2db720369b53081/packages/opentelemetry-core/src/internal/exporter.ts#L37\n // Keep this block just in case that assumption changes in a future version\n .catch((reason: unknown) => {\n let msg = 'unknown error';\n if (reason && reason instanceof Error) {\n msg = reason.message;\n } else if (typeof reason === 'string') {\n msg = reason;\n }\n\n this._userSessionManager.incrSessionPartCountForKey(\n exportFailureAttributeKey('unknown', 'current'),\n );\n this._userSessionManager.incrNextSessionPartCountForKey(\n exportFailureAttributeKey('unknown', 'previous'),\n );\n this._diag.error(`spans failed to export: ${msg}`);\n });\n }\n\n public onStart(): void {\n // do nothing.\n }\n\n public shutdown(): Promise<void> {\n return this._shutdownOnce.call();\n }\n\n private readonly _shutdown = () => {\n return this._exporter.shutdown();\n };\n}\n"],"mappings":";;;;;AAuBA,MAAM,6BACJ,QACA,YAEA,OAAO,YAAY,YAAY,kBAAkB,yBAAyB,GAAG;AAE/E,IAAa,yCAAb,MAA6E;CAC3E;CACA,gBAAwC,CAAC;CACzC;CACA;CACA;CACA;CAEA,YAAmB,EACjB,UACA,cACA,oBACA,MAAM,YAAYA,mBAAAA,KAAK,sBAAsB,EAC3C,WAAW,yCACb,CAAC,KAC4C;EAC7C,KAAK,QAAQ;EACb,KAAK,YAAY;EACjB,KAAK,gBAAgB,IAAIC,oBAAAA,eAAe,KAAK,WAAW,IAAI;EAC5D,KAAK,gBAAgB;EACrB,KAAK,sBAAsB;CAC7B;CAEA,aAAmC;EACjC,KAAK,MAAM,MACT,+EACF;EACA,OAAO,QAAQ,QAAQ,KAAA,CAAS;CAClC;CAEA,MAAa,MAA0B;EACrC,IAAI,KAAK,cAAc,UAAU;GAC/B,KAAK,MAAM,MAAM,qDAAqD;GACtE;EACF;EAEA,IAAI,CAACC,6BAAAA,kBAAkB,IAAI,GAAG;GAC5B,KAAK,MAAM,MACT,6DACF;GACA,IAAI,KAAK,cAAc,iBAAiB,IAAI,GAC1C;GAEF,KAAK,cAAc,KAAK,IAAI;EAC9B,OAAO;GACL,KAAK,MAAM,MAAM,uDAAuD;GACxE,KAAK,aAAa,CAAC,MAAM,GAAG,KAAK,aAAa,CAAC;GAC/C,KAAK,gBAAgB,CAAC;EACxB;CACF;CAEA,aAAqB,OAA6B;EAChD,oBAAA,SACG,QAAQ,KAAK,WAAW,KAAK,CAAC,CAC9B,MAAM,WAAyB;GAC9B,IAAI,OAAO,SAASC,oBAAAA,iBAAiB,QAAQ;IAC3C,MAAM,eAAe,OAAO,OAAO,WAAW;IAC9C,IAAI,gBAAqC;IAEzC,IAAI,iBAAiB,mCACnB,gBAAgB;SACX,IAAI,iBAAiB,yBAC1B,gBAAgB;IAGlB,KAAK,oBAAoB,2BACvB,0BAA0B,eAAe,SAAS,CACpD;IACA,KAAK,oBAAoB,+BACvB,0BAA0B,eAAe,UAAU,CACrD;IACA,KAAK,MAAM,MAAM,2BAA2B,cAAc;GAC5D;EACF,CAAC,CAAC,CAID,OAAO,WAAoB;GAC1B,IAAI,MAAM;GACV,IAAI,UAAU,kBAAkB,OAC9B,MAAM,OAAO;QACR,IAAI,OAAO,WAAW,UAC3B,MAAM;GAGR,KAAK,oBAAoB,2BACvB,0BAA0B,WAAW,SAAS,CAChD;GACA,KAAK,oBAAoB,+BACvB,0BAA0B,WAAW,UAAU,CACjD;GACA,KAAK,MAAM,MAAM,2BAA2B,KAAK;EACnD,CAAC;CACL;CAEA,UAAuB,CAEvB;CAEA,WAAiC;EAC/B,OAAO,KAAK,cAAc,KAAK;CACjC;CAEA,kBAAmC;EACjC,OAAO,KAAK,UAAU,SAAS;CACjC;AACF"}