Sign Up
Open in ChatGPT Open in Claude Open in Perplexity

AdonisJs Integration Guide

You can integrate your AdonisJs application with Monoscope using OpenTelemetry. This allows you to send logs, metrics, and traces to Monoscope for monitoring and analytics.

To get started, you’ll need the OpenTelemetry Node.js library and some basic configuration.


Prerequisites

Ensure you have completed the first three steps of the onboarding guide.

Install via Claude Code

Use Claude Code? Our skill will instrument this project for you. Add the marketplace, install the skill, and install our CLI:

claude plugin marketplace add monoscope-tech/skills
claude plugin install monoscope-skills@monoscope-skills
curl monoscope.tech/install.sh | sh
monoscope auth login

Then run inside Claude Code:

/monoscope-skills:instrument OpenTelemetry via Monoscope into this project

The skill drives the CLI to wire up the SDK and verify it. Prefer a human? Email us — happy to jump on a call or connect over Slack.

Installation

Run the command below to install the API, SDK, and Instrumentation tools.

npm install --save @monoscopetech/adonis @opentelemetry/api  @opentelemetry/auto-instrumentations-node

Open Telemetery Configuration

This module is highly configurable by setting environment variables. So many aspects of the auto instrumentation’s behavior such as Resource detectors, Exporters, Trace context propagation headers, and many more can be configured based on your needs.

Add the following environment variables to your .env file:

# Specifies the endpoint URL for the OpenTelemetry collector.
OTEL_EXPORTER_OTLP_ENDPOINT="http://otelcol.monoscope.tech:4317"
# Specifies the name of the service.
OTEL_SERVICE_NAME="{YOUR_SERVICE_NAME}"
# Adds your API KEY to the resource.
OTEL_RESOURCE_ATTRIBUTES="x-api-key={YOUR_API_KEY}"
# Specifies the protocol to use for the OpenTelemetry exporter.
OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
# disable some auto instrumentation libraries
OTEL_NODE_DISABLED_INSTRUMENTATIONS=net,connect,dns,fs

Import Order Matters: The @opentelemetry/auto-instrumentations-node/register module reads environment variables at import time. If using a .env file, import dotenv/config first. If not using a .env file, ensure OTEL_* environment variables are set before starting your application (e.g., via command line, Docker, or your deployment platform).

Setup Monoscope Adonis Middleware For HTTP Request Monitoring

Monoscope Adonis Middleware is a middleware that can be used to monitor HTTP requests. It is a wrapper around the Express.js middleware and provides additional functionalities on top of the open telemetry instrumentation which creates a custom span for each request capturing details about the request including request and response bodies.

First configure the @monoscopetech/adonis sdk by running the following command:

node ace configure @monoscopetech/adonis

Then, create an monoscope.js|ts file in the /conf directory and export the defineConfig object with some properties like so:

import { defineConfig } from "@monoscopetech/adonis";
import axios from "axios";

export default defineConfig({
  captureResponseBody: true,
  serviceName: "my-service",
  monitorAxios: axios, // Optional: Use this to monitor all axios requests from your server
});

Then, register the middleware by adding the @monoscopetech/adonis client to your global middleware list in the start/kernel.js|ts file like so:

import "dotenv/config";
import "@opentelemetry/auto-instrumentations-node/register";

import server from "@adonisjs/core/services/server";
import Monoscope from "@monoscopetech/adonis";

const client = new Monoscope();

server.use([
  () => import("#middleware/container_bindings_middleware"),
  () => import("#middleware/force_json_response_middleware"),
  () => import("@adonisjs/cors/cors_middleware"),
  () => client.middleware(),
]);

Quick overview of the configuration parameters

An object with the following optional fields can be passed to the defineConfig function in conf/monoscope.ts to configure it:

Option Description
debug Set to true to enable debug mode.
tags A list of defined tags for your services (used for grouping and filtering data on the dashboard).
serviceName A defined string name of your application
serviceVersion A defined string version of your application (used for further debugging on the dashboard).
redactHeaders A list of HTTP header keys to redact.
redactResponseBody A list of JSONPaths from the response body to redact.
redactRequestBody A list of JSONPaths from the request body to redact.
captureRequestBody default false, set to true if you want to capture the request body.
captureResponseBody default false, set to true if you want to capture the response body.
monitorAxios Axios instance to monitor.

Error Reporting

With Monoscope, you can track and report different unhandled or uncaught errors, API issues, and anomalies at different parts of your application. This will help you associate more detail and context from your backend with any failing customer request.

To report errors, you need to first enable asyncLocalStorage in your AdonisJS project by setting useAsyncLocalStorage to true in your config/app.js|ts file, like so:

export const http = defineConfig({
  useAsyncLocalStorage: true,
  // Other configs...
});

Then, use the reportError() function in your application’s exception handler, passing in the error argument, to report all uncaught errors and service exceptions that happened during a request, like so:

import { HttpContext, ExceptionHandler } from "@adonisjs/core/http";
import { reportError } from "@monoscopetech/adonis";

export default class HttpExceptionHandler extends ExceptionHandler {
  async handle(error: unknown, ctx: HttpContext) {
    return super.handle(error, ctx);
  }

  async report(error: unknown, ctx: HttpContext) {
    // Automatically report all uncaught errors to Monoscope
    reportError(error);
    return super.report(error, ctx);
  }
}

Manual Error Reporting

You can also manually report errors to Monoscope by calling the reportError() function, passing in the error argument, like so:

import router from "@adonisjs/core/services/router";
import { reportError } from "@monoscopetech/adonis";
router.get("/", async () => {
  try {
    throw new Error("something went wrong");
    return res.data;
  } catch (error) {
    // report the error to Monoscope
    reportError(error);
    return { message: "something went wrong" };
  }
});

Identifying users & tenants

Attach the authenticated user and tenant to every request span so you can filter, group, and search by identity in the dashboard (e.g. “all errors for user.email = [email protected]”). Call setUser and setTenant from inside a controller or a middleware that runs after auth — the SDK writes them to the active request span using the standard attribute keys (user.id, user.email, user.full_name, tenant.id, tenant.name).

import { setUser, setTenant } from "@monoscopetech/adonis";
import type { HttpContext } from "@adonisjs/core/http";

export default class UsersController {
  async show({ auth }: HttpContext) {
    const user = await auth.authenticate();
    setUser({ id: user.id, email: user.email, name: user.fullName });
    setTenant({ id: user.tenantId, name: user.tenantName });
    // ...
  }
}

Both helpers skip undefined/null fields, so partial info is fine. They must run inside a request handled by the Monoscope middleware — calls outside that scope are no-ops with a debug warning.

Monitoring Axios requests

Monoscope supports monitoring outgoing HTTP requests made using libraries like Axios. This can be done either globally or on a per-request basis.

Global monitoring

To monitor all outgoing Axios requests globally, you can use the monitorAxios option when initializing the Monoscope client.

import { defineConfig } from "@monoscopetech/adonis";
import axios from "axios";

export default defineConfig({
  captureResponseBody: true,
  serviceName: "my-service",
  monitorAxios: axios, // Optional: Use this to monitor all axios requests from your server
});

By adding monitorAxios to config, all axios requests in your server will be monitored by Monoscope.

Per-request monitoring

To monitor a specific Axios request, you can use the observeAxios function provided by the SDK.

import router from "@adonisjs/core/services/router";
import { observeAxios } from "@monoscopetech/adonis";
import axios from "axios";
router.get("/", async () => {
  const res = await observeAxios({
    urlWildcard: "/todos/:todoId",
  }).get("https://jsonplaceholder.typicode.com/todos/1");
  return res.data;
});

The urlWildcard parameter is used for urls that contain dynamic path parameters. This helps Monoscope to identify request to the same endpoint but with different parameters.

All observeAxios options

Below is the full list of options for the observeAxios function:

Option Description
urlWildcard optional The route pattern of the url if it has dynamic path parameters.
redactHeaders A list of HTTP header keys to redact.
redactResponseBody A list of JSONPaths from the response body to redact.
redactRequestBody A list of JSONPaths from the request body to redact.

Example

import router from "@adonisjs/core/services/router";
import { observeAxios } from "@monoscopetech/adonis";
import axios from "axios";
router.get("/", async () => {
  const res = await observeAxios({
    axiosInstance: axios,
    urlWildcard: "/todos/:todoId"
    redactHeaders: ["Authorization"],
    redactResponseBody: ["$.credit_card_number"],
    redactRequestBody: ["$.password"]
  }).get("https://jsonplaceholder.typicode.com/todos/1");
  return res.data;
});

Non-HTTP Entry Points (Background Jobs, Workers, CLIs)

The AdonisJS middleware only covers HTTP requests. @rlanz/bull-queue workers, scheduled commands, and standalone Ace CLI scripts are invisible until you wrap each handler in a span yourself. Always instrument these alongside your HTTP routes.

Use the standard OpenTelemetry tracer API directly inside your queue processor or scheduled command. Auto-instrumentation picks up downstream HTTP/database calls automatically once a parent span is active.

import { trace, SpanStatusCode } from "@opentelemetry/api";
import { JobHandlerContract } from "@rlanz/bull-queue/types";

const tracer = trace.getTracer("my-service-worker");

export default class SendEmail implements JobHandlerContract {
  async handle(payload: { to: string }) {
    return tracer.startActiveSpan(
      "email.send",
      {
        attributes: {
          "messaging.system": "bullmq",
          "messaging.operation": "process",
          "messaging.destination.name": "emails",
          "code.function": "SendEmail.handle",
        },
      },
      async (span) => {
        try {
          await this.sendEmail(payload);
          span.setStatus({ code: SpanStatusCode.OK });
        } catch (err) {
          span.recordException(err as Error);
          span.setStatus({ code: SpanStatusCode.ERROR });
          throw err;
        } finally {
          span.end();
        }
      }
    );
  }
}

The same wrapper goes around scheduled commands and any standalone Ace task. For one-shot CLI commands, ensure the OTel SDK shuts down (await sdk.shutdown()) before the process exits so the BatchSpanProcessor flushes; otherwise spans are dropped silently.

Tips

  1. At the moment, only Traces are supported for environment variable configuration. See the open issues for Metrics and Logs to learn more.
  2. By default, all SDK resource detectors are enabled. However, you can customize this by setting the OTEL_NODE_RESOURCE_DETECTORS environment variable to activate specific detectors or disable them entirely.

Explore the Adonis SDK