Install with no code change
Turn WizeLens on for Node and ASP.NET Core without touching their code, with a Node --import hook, a .NET startup hook, or a Kubernetes webhook.
Platform teams can turn WizeLens on for a service without a pull request to it. The app keeps its code; WizeLens comes in when the process starts, and environment variables set it up. The code install still works, and wins when both are there.
Node
NODE_OPTIONS="--import @wizeworks/lens-node/auto" node server.js
@wizeworks/lens-node must be where Node can find it: installed in the app (npm install @wizeworks/lens-node, no code),
or anywhere on disk with a path, for example --import /opt/wizelens/node/dist/auto.js. Node 22.13 or newer.
It hooks everything the add-on supports, as the app loads it:
| What | Hooked |
|---|---|
| Requests | Every node:http and node:https server, so every framework. Routes are named for Express, Fastify, Koa (@koa/router), Hono (@hono/node-server), and Next.js |
| Errors | Express (next(err) and unhandled), Fastify, Koa, and Hono errors go on the request span |
| Databases | pg, mysql2, better-sqlite3, node:sqlite, and Prisma Client (@prisma/client). TypeORM and Drizzle through their driver |
| Outgoing calls | fetch and undici |
| gRPC and messaging | @grpc/grpc-js, amqplib, kafkajs, @azure/service-bus |
| Logs | console, pino (also Fastify's logger), winston, and bunyan |
| Metrics | CPU, memory, heap, event loop, and GC |
Nothing starts until the process serves a request or starts a server, so npm, build tools, and scripts that inherit
NODE_OPTIONS stay untouched. Worker threads are skipped. On Node 22.13 and 22.14, the hooks that edit ES modules
(Hono's ES build, the ES build of @azure/service-bus, import "node:sqlite") are off; Node 22.15 and newer have them.
ASP.NET Core
DOTNET_STARTUP_HOOKS=/opt/wizelens/dotnet/WizeLens.AutoInstrumentation.dll dotnet MyApp.dll
The hook is a folder: WizeLens.AutoInstrumentation.dll with its dependencies next to it. Get it from the
wizelens-dotnet-auto-<version>.zip file on each GitHub release, from /wizelens/dotnet in the
ghcr.io/brandonkorous/wizelens-inject image, or build it with
dotnet publish dotnet/src/WizeLens.AutoInstrumentation -c Release -o /opt/wizelens/dotnet.
If the app references the WizeLens.AutoInstrumentation NuGet package (still no code), one variable is enough:
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=WizeLens.AutoInstrumentation.
It does what AddWizeLens() and UseWizeLens() do: requests, routes, outgoing HTTP and gRPC, Npgsql, MySqlConnector, and
SqlClient, every ILogger line, metrics, and the dashboard at /_wizelens. It also records EF Core commands with no
UseWizeLens() on the DbContext, and the exceptions that the exception page or UseExceptionHandler catch. It works with
WebApplication and the generic web host. ASPNETCORE_PREVENTHOSTINGSTARTUP=true turns it off.
Settings
The same variables as the code install, plus the standard OpenTelemetry service name:
| Variable | What |
|---|---|
OTEL_SERVICE_NAME |
Service name. Default: Node, the app's package.json name (no scope); .NET, the application name |
WIZELENS_ENABLED |
On or off. Default: on in development, off in production |
WIZELENS_DASHBOARD |
Serve /_wizelens in the app. Default: on in development, off in production (send-only) |
WIZELENS_HUB, WIZELENS_HUB_TOKEN |
Where to send, see the hub and the cloud |
WIZELENS_PROJECT |
The project on a shared hub |
WIZELENS_SAMPLE_RATE |
Share of traces kept, see Sampling |
WIZELENS_AUTO_SKIP |
Node: hooks to leave off, for example prisma,pino |
In production, set WIZELENS_ENABLED=true and a hub, like any service: see Production.
Kubernetes
A mutating admission webhook adds the hook and the variables to every pod labeled wizelens.dev/inject. Install its
chart once:
helm install wizelens-inject oci://ghcr.io/brandonkorous/charts/wizelens-inject \
--namespace wizelens --create-namespace \
--set hub=http://wizelens-hub.wizelens:5960
Then label a pod template and restart it:
spec:
template:
metadata:
labels:
wizelens.dev/inject: node # or: dotnet
Each new pod gets a small first step that copies the WizeLens files into a shared folder at /wizelens, then
NODE_OPTIONS (Node) or DOTNET_STARTUP_HOOKS (.NET), joined to any value the container already sets, and the settings
above. A variable the container sets itself is kept. The pod's annotations change one pod:
| Annotation | What |
|---|---|
wizelens.dev/service |
Service name. Default: the app.kubernetes.io/name or app label, else the container name |
wizelens.dev/hub |
Hub for this pod |
wizelens.dev/project |
Project. Default: the chart's project, else the namespace |
wizelens.dev/dashboard |
"true" serves /_wizelens in the pod |
wizelens.dev/container-names |
Only these containers, for example api,worker |
Chart values: hub, hubTokenSecret.name and .key (a Secret in each app namespace, read as WIZELENS_HUB_TOKEN),
project, dashboard, namespaceLabels (limit to labeled namespaces), and failurePolicy (default Ignore: a webhook
that is down never blocks a deploy). Injected pods carry wizelens.dev/injected. The chart makes its own TLS certificate.
When the app installs WizeLens too
The code install wins. Node: when the app calls createWizeLens(), the auto install stops its own instance and prints
... installs WizeLens in code, so the auto install steps aside. Libraries it already hooked send to the app's instance,
so nothing is counted twice. .NET: AddWizeLens() takes over the registration with its own options, and
UseWizeLens() adds the middleware once. Both need this version or newer on both sides.
Try it
The samples have no WizeLens code. With a hub running (pnpm dev:hub):
cd samples/auto-node && WIZELENS_HUB=http://localhost:5960 pnpm start:auto
dotnet build dotnet/WizeLens.slnx -c Release
DOTNET_STARTUP_HOOKS=$PWD/dotnet/src/WizeLens.AutoInstrumentation/bin/Release/net10.0/WizeLens.AutoInstrumentation.dll \
WIZELENS_HUB=http://localhost:5960 dotnet samples/auto-dotnet/bin/Release/net10.0/AutoDotnet.dll
Open http://localhost:5960/_wizelens and call /api/products/1/related on either: an N+1 shows up in its trace.