ReferencesTypeScript SDK

Usage

Inngest supports OpenTelemetry for distributed tracing and observability across your functions. The extendedTracesMiddleware automatically instruments your Inngest functions and integrates with your existing OpenTelemetry providers, giving you deep insights into function execution, step timing, and performance. It includes automatic instrumentation for many popular libraries.

Basic Usage

Import and run the extendedTracesMiddleware() before any other code.

This ensures that the tracer provider and any instrumentation has time to patch code in order to collect traces and spans from all parts of your application. Loading running extendedTracesMiddleware() after any other code risks not instrumenting it.

For example,

// Import this first
import { extendedTracesMiddleware } from "inngest/experimental";
const extendedTraces = extendedTracesMiddleware();

// Then everything else
import { Inngest } from "inngest";

const inngest = new Inngest({
  id: "my-app",
  middleware: [extendedTraces],
});

Serverless

If you're using serverless, the entrypoint of your app will likely be the file for a particular endpoint, for example /api/inngest.

If you have your client set up as in the example above, make sure you import that first so that the provider has a chance to initialize.

// Import the client first
import { inngest } from "@/inngest";

// Then import everything else
import { serve } from "inngest/next";
import { myFn } from "@/inngest/functions";

export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [myFn],
});

Extending existing providers

A JavaScript process can only have a single OpenTelemetry Provider. Some libraries such as Sentry also create their own provider.

extendedTracesMiddleware() will first try to extend an existing provider and will only create one if none has been found. If an existing provider is extended, we won't contribute any automatic instrumentation.

In the case of Sentry, extendedTracesMiddleware() will extend Sentry's provider as long as it's run after Sentry.init().

This behaviour can be changed:

extendedTracesMiddleware({
  behaviour: "auto",
});

The options are:

  • "auto" (default): Attempt to extend a provider if one exists, else create one, fails if neither worked
  • "extendProvider": Only attempt to extend a provider and fails if none exists
  • "createProvider": Only attempt to create a provider and fails if we couldn't
  • "off": Do nothing

If you're intending to only use extendedTracesMiddleware() to extend an existing provider, you no longer need to ensure that it is called before any other code.

Manually extend

If you're already manually creating your own trace provider and import ordering is an issue, you may want to manually add Inngest's InngestSpanProcessor to your existing setup.

Add an InngestSpanExporter to your provider:

// Create your client the same as you would normally
import { Inngest } from "inngest";
import { extendedTracesMiddleware } from "inngest/experimental";

export const inngest = new Inngest({
  id: "my-app",
  middleware: [
    extendedTracesMiddleware({
      // Make sure the middleware doesn't try to automatically instrument
      behaviour: "off",
    }),
  ],
});

```ts
// Then when you create your provider, pass the client to it
import { inngest } from "@/inngest";
import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
import { InngestSpanProcessor } from "inngest/experimental";

const provider = new BasicTracerProvider({
  // Add the span processor when creating your provider
  spanProcessors: [new InngestSpanProcessor(inngest)],
});

// Register the provider globally
provider.register();

Instrumentation

extendedTracesMiddleware() will automatically instrument common code for you if it's used to create your provider.

Here's a list of automatic supported instrumentation:

Custom instrumentation

You can add additional custom instrumentations to gain more insight into your stack.

For example, here's an example of adding Prisma OpenTelemetry:

import { PrismaInstrumentation } from "@prisma/instrumentation";
import { extendedTracesMiddleware } from "inngest/experimental";

const extendedTraces = extendedTracesMiddleware({
  instrumentations: [new PrismaInstrumentation()],
});