Alpha

Node

One middleware for your framework, one line per database driver, and outgoing fetch for free.

Install

npm install @wizeworks/lens-node
import { createWizeLens } from "@wizeworks/lens-node";

const wizelens = createWizeLens({ serviceName: "orders-api" });

WizeLens needs Node 22.13 or newer (24 is best).

Your framework

Framework Code
Express app.use(wizelens.middleware) first, app.use(wizelens.errorMiddleware) last
Fastify await app.register(wizelensFastify(wizelens))
Koa app.use(wizelensKoa(wizelens)) first
Hono (Node) app.use(wizelensHono(wizelens)) first
Plain node:http if (await wizelens.handler(req, res)) return; for the dashboard, and traceDb() for queries
Next.js instrumentation.ts, see Next.js

Outgoing fetch calls (and undici) and Express routing time are traced by themselves. Open http://localhost:<port>/_wizelens.

Databases

Library Code
pg instrumentPg(wizelens, pg)
mysql2 instrumentMysql2(wizelens, mysql)
better-sqlite3 instrumentBetterSqlite3(wizelens, db)
node:sqlite instrumentNodeSqlite(wizelens, db)
Prisma const prisma = new PrismaClient().$extends(prismaExtension(wizelens, { system: "postgresql" }))
TypeORM instrumentTypeOrm(wizelens, dataSource)
Drizzle instrumentDrizzle(wizelens, db) (on pg, mysql2, better-sqlite3, or node:sqlite)
Anything else wizelens.traceDb({ system: "postgresql" }, sql, params, () => run(sql, params))

An ORM and the driver under it never count the same query twice. Queries outside a request (startup, jobs) are skipped unless you set traceQueriesOutsideRequests: true.

gRPC and messaging

Library Code
@grpc/grpc-js instrumentGrpc(wizelens, grpc)
amqplib (RabbitMQ) instrumentAmqplib(wizelens, amqplib)
kafkajs instrumentKafkaJs(wizelens, kafka)
@azure/service-bus instrumentServiceBus(wizelens, client)

Logs

Lines written during a request go into its trace. Lines written outside a request are skipped. Your loggers still write where they wrote before; WizeLens only copies the lines.

Logger How
console.* Automatic. Turn it off with captureConsole: false.
Fastify (request.log, app.log) Automatic with wizelensFastify.
pino (also nestjs-pino) instrumentPino(wizelens, logger)
winston instrumentWinston(wizelens, logger)
bunyan instrumentBunyan(wizelens, logger), before you make child loggers
consola instrumentConsola(wizelens, consola)
log4js appenders: { wizelens: { type: log4jsAppender(wizelens) } }, and list it in your categories
NestJS built-in logger NestFactory.create(AppModule, { logger: nestLogger(wizelens, new ConsoleLogger()) })
OpenTelemetry logs new LoggerProvider({ processors: [wizelensLogProcessor(wizelens)] })
Anything else wizelens.logger.info("message", { key: "value" })

Metrics

Every 10 seconds the add-on samples CPU, memory, the V8 heap, event loop delay, and GC pauses. To keep your own OpenTelemetry metrics too, add the WizeLens exporter:

import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
import { wizelensMetricExporter } from "@wizeworks/lens-node";

const provider = new MeterProvider({
  readers: [new PeriodicExportingMetricReader({ exporter: wizelensMetricExporter(wizelens) })],
});

Metrics are kept in memory for 1 hour (metricsMaxAgeMs). captureMetrics: false turns them off.

Tags and users

wizelens.tag("cache", "hit");
wizelens.setUser(user.id);

The full option list is on Configuration.