# Usage

> **Info:** TypeScript SDK v4 is now in beta. See the v4 docs and migration guide.

Inngest supports OpenTelemetry for distributed tracing and observability across your functions. The `extendedTracesMiddleware` exports OpenTelemetry spans from your functions to Inngest, giving you deep insights into function execution, step timing, and performance.

If you want Inngest to set up OpenTelemetry for you, use [`@inngest/otel`](https://www.npmjs.com/package/@inngest/otel) for a Node.js OpenTelemetry provider and common instrumentation. If your app already configures OpenTelemetry, keep that setup and add the Extended Traces middleware so spans are exported to Inngest.

## Basic Usage

Use this path when your application does not already configure OpenTelemetry. Install and use `@inngest/otel` to set up a Node.js OpenTelemetry provider and common instrumentations before your application code starts, and `extendedTracesMiddleware()` attaches to that provider.

Preload it before your application:

```shell
node --import @inngest/otel/node ./app.js
```

If `--import` is not available, use a small bootstrap file as your process entrypoint. Because ESM static imports are evaluated before the importing module runs, keep the dynamic `await import("./app.js")`; a static `import "./app.js"` in the same file can load app modules before instrumentation is registered.

```ts
import "@inngest/otel/node";

await import("./app.js");
```

Then configure the Inngest client to use the Extended Traces middleware:

```ts
import { Inngest } from "inngest";
import { extendedTracesMiddleware } from "inngest/experimental";

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

Because `@inngest/otel` is preloaded, the middleware's default behavior extends the existing provider.

> **Callout:** Load @inngest/otel/node before importing code that uses libraries you want OpenTelemetry to instrument. Loading it later can miss instrumentation patches for modules that were already imported.

## Advanced Usage

**'Setup an OpenTelemetry client with Inngest or create custom spans'**: [Follow this guide to learn how to add Inngest Extended Traces to an existing OpenTelemetry configuration or to create custom spans.]("/docs-markdown/examples/open-telemetry")

### 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 your platform supports Node.js flags, prefer the `--import @inngest/otel/node` preload shown above. If not, import `@inngest/otel/node` before your Inngest client and functions in the route module.

```ts
// Import instrumentation first
import "@inngest/otel/node";

// Then import your Inngest client and functions
import { inngest } from "@/inngest";
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.

If your application already creates an OpenTelemetry provider, keep that setup. By default, `extendedTracesMiddleware()` extends the existing provider when it can.

```ts
extendedTracesMiddleware();
```

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

> **Note:** This extension should also work for OpenTelemetry providers that originate
> within the runtime, like Deno's OpenTelemetry.

Set `behaviour: "extendProvider"` if you want the middleware to fail when no existing provider is available instead of falling back to provider creation:

```ts
extendedTracesMiddleware({
  behaviour: "extendProvider",
});
```

The options are:

- `"auto"` (default): Attempt to extend a provider if one exists. For backward compatibility, this may create a provider if none exists, but provider creation is deprecated in favor of `@inngest/otel`.
- `"extendProvider"`: Only attempt to extend a provider and fails if none exists
- `"createProvider"` (deprecated): Only attempt to create a provider. Use `@inngest/otel` instead.
- `"off"`: Do nothing

If you only use `extendedTracesMiddleware()` to extend an existing provider, you do not need to call it before other application code. The provider and instrumentation setup remains owned by your existing OpenTelemetry configuration.

### 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 `InngestSpanProcessor` to your provider:

```ts
// 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({
      // The provider below adds InngestSpanProcessor, so keep the middleware from creating or extending another provider.
      behaviour: "off",
    }),
  ],
});

// 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

`@inngest/otel` automatically instruments common Node.js libraries when it is loaded before your application code. It instruments common Node packages, OpenAI, Anthropic, and Google Generative AI.

If you configure OpenTelemetry yourself, continue to manage your own instrumentation list. Check the `@opentelemetry/auto-instrumentations-node` docs for the current supported instrumentation list and default-disabled entries.

### Custom instrumentation

If you need instrumentations that are not covered by `@inngest/otel`, configure them yourself and add `InngestSpanProcessor` to your provider.

For example, here's an example of adding [Prisma
OpenTelemetry](https://www.prisma.io/docs/orm/prisma-client/observability-and-logging/opentelemetry-tracing):

```ts
import { NodeSDK } from "@opentelemetry/sdk-node";
import { PrismaInstrumentation } from "@prisma/instrumentation";
import { Inngest } from "inngest";
import { InngestSpanProcessor, extendedTracesMiddleware } from "inngest/experimental";

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

const sdk = new NodeSDK({
  spanProcessors: [new InngestSpanProcessor(inngest)],
  instrumentations: [new PrismaInstrumentation()],
});

sdk.start();
```