Capture @nestjs/axios traffic
HttpClientWatcher patches global fetch out of the box, but @nestjs/axios calls bypass it. Wire the axios source to capture HttpService and plain axios instances too — no monkey-patching.
HttpClientWatcher instruments the global fetch with no peer dependency. But most NestJS apps call out through @nestjs/axios's HttpService, and in Node axios uses the http adapter, not fetch — so those outbound calls are invisible to the fetch patch. Pass an axios source to capture them too, via axios's public interceptor API (no monkey-patching). Axios and fetch entries share the same content shape, tags, and family-hash, so they're indistinguishable in the dashboard.
@nestjs/axios — resolve HttpService lazily
HttpService isn't constructed until the Nest container is up, so you can't pass its axiosRef at forRoot time. Use the custom-source instrument(attach, ctx) hook: it runs at register time with a ctx.moduleRef, so you resolve HttpService and hand its axiosRef to attach.
import { Module } from '@nestjs/common';
import { HttpModule, HttpService } from '@nestjs/axios';
import { TelescopeModule, HttpClientWatcher } from '@dudousxd/nestjs-telescope';
@Module({
imports: [
HttpModule,
TelescopeModule.forRoot({
watchers: [
new HttpClientWatcher({
slowMs: 1000,
axios: {
instrument(attach, ctx) {
// HttpService is up by register time — grab the real instance.
const http = ctx.moduleRef.get(HttpService, { strict: false });
attach(http.axiosRef); // wire request/response interceptors onto it
},
},
}),
],
}),
],
})
export class AppModule {}Now every call through injected HttpService records an outbound-HTTP entry, correlated to the request or job that made it — alongside any fetch calls, in the same batch.
Plain axios instance
If you hold your own axios client, hand it over directly — no custom source needed:
import axios from 'axios';
import { TelescopeModule, HttpClientWatcher } from '@dudousxd/nestjs-telescope';
const client = axios.create({ baseURL: 'https://api.example.com' });
TelescopeModule.forRoot({
watchers: [new HttpClientWatcher({ axios: client })],
});How it works
- Public interceptors, not patches. The watcher registers request/response interceptors on the instance — nothing is monkey-patched, so it composes with your own interceptors.
- Errors are re-thrown. A non-2xx records
error.response.status; a transport failure (no response) recordsstatusCode: nulland afailedtag. Either way the rejection propagates — your error handling is untouched. - Idempotent per instance. Instrumenting the same axios instance twice (e.g. shared across watchers) never double-records.
Double-capture edge case: if you explicitly configure axios with the fetch adapter (Node's default is the http adapter), one call could record on both the axios and fetch paths. Keep the http adapter, or pass only one source.
See the HttpClientWatcher reference for the full option surface.
Building an extension
Package a watcher, a navigable entry type, a server-side data provider, and a declarative dashboard page into one installable Telescope extension — step by step, using the durable workflows surface as the worked example.
Dashboard login & sessions
Practical dashboardAuth — login mode validating against your own user table with bcrypt, session mode bridging an existing JWT, and role-gating queue mutations via request.telescopeSession.