8.5. Configure Instrumentation

In this chapter, you'll learn about observability in Medusa and how to configure instrumentation with OpenTelemetry.

What is Instrumentation?#

Instrumentation is the collection of data about your application's performance and errors. It helps you debug issues, monitor performance, and gain insights into how your application behaves in production.

Instrumentation and observability are crucial as you build customizations in your application. They allow you to optimize performance, identify bottlenecks, and ensure your application runs smoothly.


Instrumentation and Observability with OpenTelemetry#

Medusa uses OpenTelemetry for instrumentation and reporting. When configured, it reports traces for:

  • HTTP requests
  • Workflow executions
  • Query usages
  • Database queries and operations
  • Cache operations

How to Configure Instrumentation in Medusa?#

Install Dependencies#

Note: As of Medusa v2.11.0, OpenTelemetry dependencies are installed by default in new Medusa projects. If you're using an older version of Medusa, you need to install the @opentelemetry/sdk-node, @opentelemetry/resources, @opentelemetry/sdk-trace-node, and @opentelemetry/instrumentation-pg dependencies.

Before you start, you must install the dependencies relevant for the exporter you use. If you're using Zipkin, install the following dependencies:

Add instrumentation.ts#

Next, create the file instrumentation.ts with the following content:

instrumentation.ts
import { registerOtel } from "@medusajs/medusa"
import { ZipkinExporter } from "@opentelemetry/exporter-zipkin"

// If using an exporter other than Zipkin, initialize it here.
const exporter = new ZipkinExporter({
  serviceName: "my-medusa-project",
})

export function register() {
  registerOtel({
    serviceName: "medusajs",
    // pass exporter
    exporter,
    instrument: {
      http: true,
      workflows: true,
      query: true,
      db: true,
      cache: true,
    },
  })
}

In the instrumentation.ts file, you export a register function that uses Medusa's registerOtel utility function. You also initialize an instance of the exporter, such as Zipkin, and pass it to the registerOtel function.

registerOtel accepts an object where you can pass any NodeSDKConfiguration property along with the following properties:

Note: The NodeSDKConfiguration properties are accepted since Medusa v2.5.1.
Loading...

Configure HTTP Tracing#

Note: HTTP tracing options are available since Medusa v2.22.0.

When Medusa traces an HTTP request, it reports the request's URL path, method, route, status code, and headers as span attributes. To avoid leaking sensitive data to your exporter, Medusa:

  • Removes the query string from the http.url attribute and from span names.
  • Reports the query string in a separate url.query attribute, replacing the values of query parameters that aren't allowed with REDACTED. By default, Medusa only reports the values of the fields, expand, limit, offset, order, and with_deleted query parameters.
  • Doesn't report request headers whose names contain authorization, cookie, key, token, secret, session, password, or credential. For example, Medusa doesn't report the authorization, cookie, and x-publishable-api-key headers.

For example, Medusa reports a request to /store/products?q=shoes&limit=10 with the url.query attribute set to q=REDACTED&limit=10.

To change the query parameters whose values Medusa reports, pass an object with the allowedQueryParams property to the instrument.http option:

instrumentation.ts
export function register() {
  registerOtel({
    serviceName: "medusajs",
    exporter,
    instrument: {
      http: {
        allowedQueryParams: ["q", "limit", "offset"],
      },
      workflows: true,
      query: true,
      db: true,
      cache: true,
    },
  })
}

In this example, Medusa reports the values of the q, limit, and offset query parameters, and replaces the values of other query parameters with REDACTED. Medusa matches array parameters by their base name, so category_id also allows category_id[].

To report the full query string without redaction, set allowedQueryParams to "*":

instrumentation.ts
export function register() {
  registerOtel({
    serviceName: "medusajs",
    exporter,
    instrument: {
      http: {
        allowedQueryParams: "*",
      },
      workflows: true,
      query: true,
      db: true,
      cache: true,
    },
  })
}
Warning: Query parameters can hold personal data or secrets, such as search terms, email addresses, or OAuth codes. Only allow query parameters whose values are safe to send to your exporter.

Test it Out#

To test it out, start your exporter, such as Zipkin.

Then, start your Medusa application:

Try to open the Medusa Admin or send a request to an API route.

If you check traces in your exporter, you'll find new traces reported.

Trace Span Names#

Trace span names start with the following keywords based on what it's reporting:

  • {methodName} {URL} when reporting HTTP requests, where {methodName} is the HTTP method, and {URL} is the URL path the request is sent to, without the query string.
  • route: when reporting route handlers running on an HTTP request.
  • middleware: when reporting a middleware running on an HTTP request.
  • workflow: when reporting a workflow execution.
  • step: when reporting a step in a workflow execution.
  • query.graph: when reporting Query usages.
  • pg.query: when reporting database queries and operations.

Was this chapter helpful?
Ask Bloom
For assistance in your development, use Claude Code Plugins or Docs MCP server in Cursor, VSCode, etc...FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break
⇧↵