{"version":3,"file":"EmbraceSessionBatchedSpanProcessor.cjs","names":["KEY_EMB_TYPE","diag","BindOnceFuture","EmbraceSpanStorage","ExportResultCode"],"sources":["../../../src/processors/EmbraceSessionBatchedSpanProcessor/EmbraceSessionBatchedSpanProcessor.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  internal,\n} from '@opentelemetry/core';\nimport type {\n  ReadableSpan,\n  SpanExporter,\n  SpanProcessor,\n} from '@opentelemetry/sdk-trace-web'; // TODO: don't rely on internal API\nimport { EMB_TYPES, KEY_EMB_TYPE } from '../../constants/index.ts';\nimport type { SessionSpan } from '../../instrumentations/index.ts';\nimport type {\n  LimitManagerInternal,\n  SpanSessionManagerInternal,\n} from '../../managers/index.ts';\nimport { EmbraceSpanStorage } from '../../utils/index.ts';\nimport type { EmbraceSessionBatchedSpanProcessorArgs } from './types.ts';\n\nconst isSessionSpan = (span: ReadableSpan | SessionSpan): span is SessionSpan =>\n  span.attributes[KEY_EMB_TYPE] === EMB_TYPES.Session;\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 EmbraceSessionBatchedSpanProcessor 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 _spanStorage: EmbraceSpanStorage;\n  private readonly _spanSessionManager: SpanSessionManagerInternal;\n  private readonly _diag: DiagLogger;\n\n  public constructor({\n    resource,\n    exporter,\n    limitManager,\n    spanSessionManager,\n    storage = window.localStorage,\n    storedSpansExpireTimeoutMS,\n    diag: diagParam = diag.createComponentLogger({\n      namespace: 'EmbraceSessionBatchedSpanProcessor',\n    }),\n  }: EmbraceSessionBatchedSpanProcessorArgs) {\n    this._diag = diagParam;\n    this._exporter = exporter;\n    this._shutdownOnce = new BindOnceFuture(this._shutdown, this);\n    this._limitManager = limitManager;\n    this._spanSessionManager = spanSessionManager;\n    this._spanStorage = new EmbraceSpanStorage({\n      resource,\n      storage,\n      diag: diagParam,\n      onExpiredSpansExport: (spans: ReadableSpan[]) => {\n        this._exportSpans(spans);\n      },\n      storedSpansExpireTimeoutMS,\n      spanSessionManager,\n    });\n  }\n\n  public forceFlush(): Promise<void> {\n    this._diag.debug(\n      'forceFlush called for EmbraceSessionBatchedSpanProcessor. 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 (!isSessionSpan(span)) {\n      this._diag.debug(\n        'non-session 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 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._spanSessionManager.incrSessionCountForKey(\n            exportFailureAttributeKey(failureReason, 'current'),\n          );\n          this._spanSessionManager.incrNextSessionCountForKey(\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._spanSessionManager.incrSessionCountForKey(\n          exportFailureAttributeKey('unknown', 'current'),\n        );\n        this._spanSessionManager.incrNextSessionCountForKey(\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 getPendingSpansCount(): number {\n    return this._pendingSpans.length;\n  }\n\n  public storePendingSpans(sessionId: string, sessionSpan: ReadableSpan): void {\n    this._spanStorage.storePendingSpans(\n      sessionId,\n      sessionSpan,\n      this._pendingSpans,\n    );\n  }\n\n  public clearStoredSpans(sessionId: string): void {\n    this._spanStorage.clearStoredSpans(sessionId);\n  }\n\n  public shutdown(): Promise<void> {\n    return this._shutdownOnce.call();\n  }\n\n  private readonly _shutdown = () => {\n    this._spanStorage.destroy();\n    return this._exporter.shutdown();\n  };\n}\n"],"mappings":";;;;;;;AAsBA,MAAM,iBAAiB,SACrB,KAAK,WAAWA,6BAAAA,kBAAAA;AAIlB,MAAM,6BACJ,QACA,YAEA,OAAO,YAAY,YAAY,kBAAkB,yBAAyB,GAAG;AAE/E,IAAa,qCAAb,MAAyE;CACvE;CACA,gBAAwC,EAAE;CAC1C;CACA;CACA;CACA;CACA;CAEA,YAAmB,EACjB,UACA,UACA,cACA,oBACA,UAAU,OAAO,cACjB,4BACA,MAAM,YAAYC,mBAAAA,KAAK,sBAAsB,EAC3C,WAAW,sCACZ,CAAC,IACuC;AACzC,OAAK,QAAQ;AACb,OAAK,YAAY;AACjB,OAAK,gBAAgB,IAAIC,oBAAAA,eAAe,KAAK,WAAW,KAAK;AAC7D,OAAK,gBAAgB;AACrB,OAAK,sBAAsB;AAC3B,OAAK,eAAe,IAAIC,oDAAAA,mBAAmB;GACzC;GACA;GACA,MAAM;GACN,uBAAuB,UAA0B;AAC/C,SAAK,aAAa,MAAM;;GAE1B;GACA;GACD,CAAC;;CAGJ,aAAmC;AACjC,OAAK,MAAM,MACT,4EACD;AACD,SAAO,QAAQ,QAAQ,KAAA,EAAU;;CAGnC,MAAa,MAA0B;AACrC,MAAI,KAAK,cAAc,UAAU;AAC/B,QAAK,MAAM,MAAM,sDAAsD;AACvE;;AAGF,MAAI,CAAC,cAAc,KAAK,EAAE;AACxB,QAAK,MAAM,MACT,yDACD;AACD,OAAI,KAAK,cAAc,iBAAiB,KAAK,CAC3C;AAEF,QAAK,cAAc,KAAK,KAAK;SACxB;AACL,QAAK,MAAM,MAAM,mDAAmD;AACpE,QAAK,aAAa,CAAC,MAAM,GAAG,KAAK,cAAc,CAAC;AAChD,QAAK,gBAAgB,EAAE;;;CAI3B,aAAqB,OAA6B;AAChD,sBAAA,SACG,QAAQ,KAAK,WAAW,MAAM,CAC9B,MAAM,WAAyB;AAC9B,OAAI,OAAO,SAASC,oBAAAA,iBAAiB,QAAQ;IAC3C,MAAM,eAAe,OAAO,OAAO,WAAW;IAC9C,IAAI,gBAAqC;AAEzC,QAAI,iBAAiB,kCACnB,iBAAgB;aACP,iBAAiB,wBAC1B,iBAAgB;AAGlB,SAAK,oBAAoB,uBACvB,0BAA0B,eAAe,UAAU,CACpD;AACD,SAAK,oBAAoB,2BACvB,0BAA0B,eAAe,WAAW,CACrD;AACD,SAAK,MAAM,MAAM,2BAA2B,eAAe;;IAE7D,CAID,OAAO,WAAoB;GAC1B,IAAI,MAAM;AACV,OAAI,UAAU,kBAAkB,MAC9B,OAAM,OAAO;YACJ,OAAO,WAAW,SAC3B,OAAM;AAGR,QAAK,oBAAoB,uBACvB,0BAA0B,WAAW,UAAU,CAChD;AACD,QAAK,oBAAoB,2BACvB,0BAA0B,WAAW,WAAW,CACjD;AACD,QAAK,MAAM,MAAM,2BAA2B,MAAM;IAClD;;CAGN,UAAuB;CAIvB,uBAAsC;AACpC,SAAO,KAAK,cAAc;;CAG5B,kBAAyB,WAAmB,aAAiC;AAC3E,OAAK,aAAa,kBAChB,WACA,aACA,KAAK,cACN;;CAGH,iBAAwB,WAAyB;AAC/C,OAAK,aAAa,iBAAiB,UAAU;;CAG/C,WAAiC;AAC/B,SAAO,KAAK,cAAc,MAAM;;CAGlC,kBAAmC;AACjC,OAAK,aAAa,SAAS;AAC3B,SAAO,KAAK,UAAU,UAAU"}