{"version":3,"file":"processor.cjs","names":["debugPrefix","_resourceAttributes: Resource | undefined","#traceParents","appId: string | undefined","functionId: string | undefined","traceRef: string | undefined","TraceStateKey","#checkpointingRoots","#activeStepContext","osDetector","envDetector","hostDetector","processDetector","serviceInstanceIdDetector","#batcher","getAsyncCtx","BatchSpanProcessor","OTLPTraceExporter","hashSigningKey","#spanCleanup","#spansToExport","deterministicSpanID","Attribute"],"sources":["../../../../src/components/execution/otel/processor.ts"],"sourcesContent":["import type { Span } from \"@opentelemetry/api\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport {\n  detectResources,\n  envDetector,\n  hostDetector,\n  osDetector,\n  processDetector,\n  type Resource,\n  serviceInstanceIdDetector,\n} from \"@opentelemetry/resources\";\nimport {\n  BatchSpanProcessor,\n  type ReadableSpan,\n  type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\nimport Debug from \"debug\";\nimport { deterministicSpanID } from \"../../../helpers/deterministicId.ts\";\nimport { hashSigningKey } from \"../../../helpers/strings.ts\";\nimport type { Inngest } from \"../../Inngest.ts\";\nimport { getAsyncCtx } from \"../als.ts\";\nimport { clientProcessorMap } from \"./access.ts\";\nimport { Attribute, debugPrefix, TraceStateKey } from \"./consts.ts\";\n\nconst processorDevDebug = Debug(`${debugPrefix}:InngestSpanProcessor`);\n\n/**\n * A set of resource attributes that are used to identify the Inngest app and\n *  the function that is being executed. This is used to store the resource\n *  attributes for the spans that are exported to the Inngest endpoint, and cache\n *  them for later use.\n */\nlet _resourceAttributes: Resource | undefined;\n\n/**\n * A set of information about an execution that's used to set attributes on\n * userland spans sent to Inngest for proper indexing.\n */\nexport type ParentState = {\n  traceparent: string;\n  runId: string;\n  appId: string | undefined;\n  functionId: string | undefined;\n  traceRef: string | undefined;\n  rootSpanId: string;\n};\n\n/**\n * An OTel span processor that is used to export spans to the Inngest endpoint.\n * This is used to track spans that are created within an Inngest run and export\n * them to the Inngest endpoint for tracing.\n *\n * It's careful to only pick relevant spans to export and will not send any\n * irrelevant spans to the Inngest endpoint.\n *\n * THIS IS THE INTERNAL IMPLEMENTATION OF THE SPAN PROCESSOR AND SHOULD NOT BE\n * USED BY USERS DIRECTLY. USE THE {@link PublicInngestSpanProcessor} CLASS\n * INSTEAD.\n */\nexport class InngestSpanProcessor implements SpanProcessor {\n  /**\n   * An OTel span processor that is used to export spans to the Inngest endpoint.\n   * This is used to track spans that are created within an Inngest run and export\n   * them to the Inngest endpoint for tracing.\n   *\n   * It's careful to only pick relevant spans to export and will not send any\n   * irrelevant spans to the Inngest endpoint.\n   */\n  constructor(\n    /**\n     * The app that this span processor is associated with. This is used to\n     * determine the Inngest endpoint to export spans to.\n     *\n     * It is optional here as this is the private constructor and only used\n     * internally; we set `app` elsewhere as when we create the processor (as\n     * early as possible when the process starts) we don't necessarily have the\n     * app available yet.\n     *\n     * So, internally we can delay setting ths until later.\n     */\n    app?: Inngest.Like,\n  ) {\n    if (app) {\n      clientProcessorMap.set(app as Inngest.Any, this);\n    }\n  }\n\n  /**\n   * A `BatchSpanProcessor` that is used to export spans to the Inngest\n   * endpoint. This is created lazily to avoid creating it until the Inngest App\n   * has been initialized and has had a chance to receive environment variables,\n   * which may be from an incoming request.\n   */\n  #batcher: Promise<BatchSpanProcessor> | undefined;\n\n  /**\n   * A set of spans used to track spans that we care about, so that we can\n   * export them to the OTel endpoint.\n   *\n   * If a span falls out of reference, it will be removed from this set as we'll\n   * never get a chance to export it or remove it anyway.\n   */\n  #spansToExport = new WeakSet<Span>();\n\n  /**\n   * A map of span IDs to their parent state, which includes a block of\n   * information that can be used and pushed back to the Inngest endpoint to\n   * ingest spans.\n   */\n  #traceParents = new Map<string, ParentState>();\n\n  /**\n   * A registry used to clean up items from the `traceParents` map when spans\n   * fall out of reference. This is used to avoid memory leaks in the case where\n   * a span is not exported, remains unended, and is left in memory before being\n   * GC'd.\n   */\n  #spanCleanup = new FinalizationRegistry<string>((spanId) => {\n    if (spanId) {\n      this.#traceParents.delete(spanId);\n    }\n  });\n\n  /**\n   * Tracks the currently-executing step for each execution, keyed by root span\n   * ID. Used to compute deterministic parent span IDs for userland spans when\n   * checkpointing is enabled and multiple steps run in a single invocation.\n   */\n  #activeStepContext = new Map<\n    string,\n    { hashedStepId: string; attempt: number; id: string; index: number }\n  >();\n\n  /**\n   * Root span IDs that have had at least one step execution declared, meaning\n   * they are checkpointing runs. Used to filter out infrastructure spans\n   * (checkpoint POSTs, dev server polls) that fire between steps.\n   */\n  #checkpointingRoots = new Set<string>();\n\n  /**\n   * In order to only capture a subset of spans, we need to declare the initial\n   * span that we care about and then export its children.\n   *\n   * Call this method (ideally just before execution starts) with that initial\n   * span to trigger capturing all following children as well as initialize the\n   * batcher.\n   */\n  public declareStartingSpan({\n    span,\n    runId,\n    traceparent,\n    tracestate,\n  }: {\n    span: Span;\n    runId: string;\n    traceparent: string | undefined;\n    tracestate: string | undefined;\n  }): void {\n    // Upsert the batcher ready for later. We do this here to bootstrap it with\n    // the correct async context as soon as we can. As this method is only\n    // called just before execution, we know we're all set up.\n    //\n    // Waiting to call this until we actually need the batcher would mean that\n    // we might not have the correct async context set up, as we'd likely be in\n    // some span lifecycle method that doesn't have the same chain of execution.\n    void this.ensureBatcherInitialized();\n\n    // If we don't have a traceparent, then we can't track this span. This is\n    // likely a span that we don't care about, so we can ignore it.\n    if (!traceparent) {\n      return processorDevDebug(\n        \"no traceparent found for span\",\n        span.spanContext().spanId,\n        \"so skipping it\",\n      );\n    }\n\n    // We also attempt to use `tracestate`. The values we fetch from these\n    // should be optional, as it's likely the Executor won't need us to parrot\n    // them back in later versions.\n    let appId: string | undefined;\n    let functionId: string | undefined;\n    let traceRef: string | undefined;\n\n    if (tracestate) {\n      try {\n        const entries = Object.fromEntries(\n          tracestate.split(\",\").map((kv) => kv.split(\"=\") as [string, string]),\n        );\n\n        appId = entries[TraceStateKey.AppId];\n        functionId = entries[TraceStateKey.FunctionId];\n        traceRef = entries[TraceStateKey.TraceRef];\n      } catch (err) {\n        processorDevDebug(\n          \"failed to parse tracestate\",\n          tracestate,\n          \"so skipping it;\",\n          err,\n        );\n      }\n    }\n\n    // This is a span that we care about, so let's make sure it and its\n    // children are exported.\n    processorDevDebug.extend(\"declareStartingSpan\")(\n      \"declaring:\",\n      span.spanContext().spanId,\n      \"for traceparent\",\n      traceparent,\n    );\n\n    // Set a load of attributes on this span so that we can nicely identify\n    // runtime, paths, etc. Only this span will have these attributes.\n    span.setAttributes(InngestSpanProcessor.resourceAttributes.attributes);\n\n    this.trackSpan(\n      {\n        appId,\n        functionId,\n        runId,\n        traceparent,\n        traceRef,\n        rootSpanId: span.spanContext().spanId,\n      },\n      span,\n      true,\n    );\n  }\n\n  /**\n   * Declare that a step is currently executing. Userland spans created while\n   * a step context is active will have their `inngest.traceparent` rewritten\n   * to reference a deterministic span ID derived from the step, matching the\n   * span the Go executor will create via checkpoint.\n   */\n  public declareStepExecution(\n    rootSpanId: string,\n    id: string,\n    index: number,\n    hashedStepId: string,\n    attempt: number,\n  ): void {\n    processorDevDebug(\n      \"declareStepExecution: rootSpanId=%s hashedStepId=%s attempt=%d\",\n      rootSpanId,\n      hashedStepId,\n      attempt,\n    );\n    this.#checkpointingRoots.add(rootSpanId);\n    this.#activeStepContext.set(rootSpanId, {\n      hashedStepId,\n      attempt,\n      id,\n      index,\n    });\n  }\n\n  /**\n   * Clear the active step context after a step finishes executing.\n   */\n  public clearStepExecution(rootSpanId: string): void {\n    processorDevDebug(\"clearStepExecution: rootSpanId=%s\", rootSpanId);\n    this.#activeStepContext.delete(rootSpanId);\n  }\n\n  /**\n   * A getter for retrieving resource attributes for the current process. This\n   * is used to set the resource attributes for the spans that are exported to\n   * the Inngest endpoint, and cache them for later use.\n   */\n  static get resourceAttributes(): Resource {\n    if (!_resourceAttributes) {\n      _resourceAttributes = detectResources({\n        detectors: [\n          osDetector,\n          envDetector,\n          hostDetector,\n          processDetector,\n          serviceInstanceIdDetector,\n        ],\n      });\n    }\n\n    return _resourceAttributes;\n  }\n\n  /**\n   * The batcher is a singleton that is used to export spans to the OTel\n   * endpoint. It is created lazily to avoid creating it until the Inngest App\n   * has been initialized and has had a chance to receive environment variables,\n   * which may be from an incoming request.\n   *\n   * The batcher is only referenced once we've found a span we're interested in,\n   * so this should always have everything it needs on the app by then.\n   */\n  private ensureBatcherInitialized(): Promise<BatchSpanProcessor> {\n    if (!this.#batcher) {\n      this.#batcher = new Promise(async (resolve, reject) => {\n        try {\n          // We retrieve the app from the async context, so we must make sure\n          // that this function is called from the correct chain.\n          const store = await getAsyncCtx();\n          if (!store) {\n            throw new Error(\n              \"No async context found; cannot create batcher to export traces\",\n            );\n          }\n\n          const app = store.app as Inngest.Any;\n\n          const path = \"/v1/traces/userland\";\n          const url = new URL(path, app.apiBaseUrl);\n\n          processorDevDebug(\n            \"batcher lazily accessed; creating new batcher with URL\",\n            url,\n          );\n\n          const exporter = new OTLPTraceExporter({\n            url: url.href,\n            headers: {\n              ...app.headers,\n              Authorization: `Bearer ${hashSigningKey(app.signingKey)}`,\n            },\n          });\n\n          resolve(new BatchSpanProcessor(exporter));\n        } catch (err) {\n          reject(err);\n        }\n      });\n    }\n\n    return this.#batcher;\n  }\n\n  /**\n   * Mark a span as being tracked by this processor, meaning it will be exported\n   * to the Inggest endpoint when it ends.\n   */\n  private trackSpan(\n    parentState: ParentState,\n    span: Span,\n    isRoot = false,\n  ): void {\n    const trackDebug = processorDevDebug.extend(\"trackSpan\");\n    const spanId = span.spanContext().spanId;\n\n    this.#spanCleanup.register(span, spanId, span);\n    this.#spansToExport.add(span);\n    this.#traceParents.set(spanId, parentState);\n\n    // For direct children of the root span during step execution, set a\n    // dedicated attribute with the deterministic step span ID. The Go executor\n    // creates executor.step spans with the same deterministic ID (from the same\n    // seed), so the ingestion can parent userland spans under the correct step.\n    if (!isRoot) {\n      const spanParentId =\n        (span as unknown as ReadableSpan).parentSpanContext?.spanId ??\n        (span as unknown as { parentSpanId?: string }).parentSpanId;\n\n      if (spanParentId === parentState.rootSpanId) {\n        const stepCtx = this.#activeStepContext.get(parentState.rootSpanId);\n        if (stepCtx) {\n          const seed = stepCtx.hashedStepId + \":\" + String(stepCtx.attempt);\n          const newSpanId = deterministicSpanID(seed);\n          trackDebug(\n            \"setting inngest.step.parentSpanId=%s (seed=%s) on span %s step %s index %d attempt %d\",\n            newSpanId,\n            seed,\n            spanId,\n            stepCtx.id,\n            stepCtx.index,\n            stepCtx.attempt,\n          );\n          span.setAttribute(Attribute.InngestStepParentSpanId, newSpanId);\n          span.setAttribute(Attribute.InngestStepId, stepCtx.id);\n          span.setAttribute(Attribute.InngestStepIndex, stepCtx.index);\n          span.setAttribute(Attribute.InngestStepHash, stepCtx.hashedStepId);\n          span.setAttribute(Attribute.InngestStepAttempt, stepCtx.attempt);\n        }\n      }\n    }\n\n    span.setAttribute(Attribute.InngestTraceparent, parentState.traceparent);\n    span.setAttribute(Attribute.InngestRunId, parentState.runId);\n\n    // Setting app ID is optional; it's likely in future versions of the\n    // Executor that we don't need to parrot this back.\n    if (parentState.appId) {\n      span.setAttribute(Attribute.InngestAppId1, parentState.appId);\n      span.setAttribute(Attribute.InngestAppId2, parentState.appId);\n    }\n\n    // Setting function ID is optional; it's likely in future versions of the\n    // Executor that we don't need to parrot this back.\n    if (parentState.functionId) {\n      span.setAttribute(Attribute.InngestFunctionId, parentState.functionId);\n    }\n\n    if (parentState.traceRef) {\n      span.setAttribute(Attribute.InngestTraceRef, parentState.traceRef);\n    }\n  }\n\n  /**\n   * Clean up any references to a span that has ended. This is used to avoid\n   * memory leaks in the case where a span is not exported, remains unended, and\n   * is left in memory before being GC'd.\n   */\n  private cleanupSpan(span: Span): void {\n    const spanId = span.spanContext().spanId;\n\n    // This span is no longer in use, so we can remove it from the cleanup\n    // registry.\n    this.#spanCleanup.unregister(span);\n    this.#spansToExport.delete(span);\n    this.#traceParents.delete(spanId);\n  }\n\n  /**\n   * An implementation of the `onStart` method from the `SpanProcessor`\n   * interface. This is called when a span is started, and is used to track\n   * spans that are children of spans we care about.\n   */\n  onStart(span: Span): void {\n    const devDebug = processorDevDebug.extend(\"onStart\");\n    const spanId = span.spanContext().spanId;\n    // Support both OTel SDK v2.x (parentSpanContext.spanId) and v1.x\n    // (parentSpanId as a plain string) since users may have either version.\n    const parentSpanId =\n      (span as unknown as ReadableSpan).parentSpanContext?.spanId ??\n      (span as unknown as { parentSpanId?: string }).parentSpanId;\n\n    // The root span isn't captured here, but we can capture children of it\n    // here.\n\n    if (!parentSpanId) {\n      // All spans that Inngest cares about will have a parent, so ignore this\n      devDebug(\"no parent span ID for\", spanId, \"so skipping it\");\n\n      return;\n    }\n\n    const parentState = this.#traceParents.get(parentSpanId);\n    if (parentState) {\n      // In checkpointing mode, only track spans during active step execution.\n      // This filters out infrastructure spans (checkpoint POSTs, dev server\n      // polls) that fire between steps and would otherwise pollute the tree.\n      if (\n        this.#checkpointingRoots.has(parentState.rootSpanId) &&\n        !this.#activeStepContext.has(parentState.rootSpanId)\n      ) {\n        processorDevDebug(\n          \"skipping span\",\n          spanId,\n          \"- checkpointing between steps\",\n        );\n        return;\n      }\n\n      // This span is a child of a span we care about, so add it to the list of\n      // tracked spans so that we also capture its children\n      devDebug(\n        \"found traceparent\",\n        parentState,\n        \"in span ID\",\n        parentSpanId,\n        \"so adding\",\n        spanId,\n      );\n\n      this.trackSpan(parentState, span);\n    }\n  }\n\n  /**\n   * An implementation of the `onEnd` method from the `SpanProcessor` interface.\n   * This is called when a span ends, and is used to export spans to the Inngest\n   * endpoint.\n   */\n  onEnd(span: ReadableSpan): void {\n    const devDebug = processorDevDebug.extend(\"onEnd\");\n    const spanId = span.spanContext().spanId;\n\n    try {\n      if (this.#spansToExport.has(span as unknown as Span)) {\n        if (!this.#batcher) {\n          return devDebug(\n            \"batcher not initialized, so failed exporting span\",\n            spanId,\n          );\n        }\n\n        devDebug(\"exporting span\", spanId);\n        return void this.#batcher.then((batcher) => batcher.onEnd(span));\n      }\n\n      devDebug(\"not exporting span\", spanId, \"as we don't care about it\");\n    } finally {\n      this.cleanupSpan(span as unknown as Span);\n    }\n  }\n\n  /**\n   * An implementation of the `forceFlush` method from the `SpanProcessor`\n   * interface. This is called to force the processor to flush any spans that\n   * are currently in the batcher. This is used to ensure that spans are\n   * exported to the Inngest endpoint before the process exits.\n   *\n   * Notably, we call this in the `wrapRequest` middleware hook to ensure\n   * that spans for a run as exported as soon as possible and before the\n   * serverless process is killed.\n   */\n  async forceFlush(): Promise<void> {\n    const flushDebug = processorDevDebug.extend(\"forceFlush\");\n    flushDebug(\"force flushing batcher\");\n\n    return this.#batcher\n      ?.then((batcher) => batcher.forceFlush())\n      .catch((err) => {\n        flushDebug(\"error flushing batcher\", err, \"ignoring\");\n      });\n  }\n\n  async shutdown(): Promise<void> {\n    processorDevDebug.extend(\"shutdown\")(\"shutting down batcher\");\n\n    return this.#batcher?.then((batcher) => batcher.shutdown());\n  }\n}\n\n/**\n * An OTel span processor that is used to export spans to the Inngest endpoint.\n * This is used to track spans that are created within an Inngest run and export\n * them to the Inngest endpoint for tracing.\n *\n * It's careful to only pick relevant spans to export and will not send any\n * irrelevant spans to the Inngest endpoint.\n */\nexport class PublicInngestSpanProcessor extends InngestSpanProcessor {\n  constructor(\n    /**\n     * The app that this span processor is associated with. This is used to\n     * determine the Inngest endpoint to export spans to.\n     */\n    app: Inngest.Like,\n  ) {\n    super(app);\n  }\n}\n"],"mappings":"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"}