@middle-monitor/sdk
v0.1.9
Published
TypeScript SDK for Middle-Monitor error reporting with OpenTelemetry
Downloads
106
Maintainers
Readme
Middle-Monitor TypeScript SDK
TypeScript/JavaScript SDK for capturing and reporting errors to Middle-Monitor.
Documentation: middlemonitor.io/docs#sdk
For a browser frontend (React, Vue, Angular, Svelte), use @middle-monitor/web instead: this package pulls @opentelemetry/sdk-node and does not bundle for a browser.
Installation
From GitHub:
npm install git+https://github.com/middle-monitor/sdk-typescript.gitOr from a local path:
npm installUsage
Basic setup
import { MiddleMonitorClient } from '@middle-monitor/sdk';
const client = new MiddleMonitorClient({
apiUrl: 'https://api.middlemonitor.io',
service: 'my-service'
});
try {
throw new Error('Something went wrong');
} catch (error) {
await client.reportError(error as Error);
}Custom error
await client.reportCustomError(
'DatabaseError',
'Failed to connect to database',
'/path/to/db.ts',
123
);Function wrapper
const riskyFunction = client.wrapFunction(() => {
throw new Error('This will be automatically reported');
});Environment variable setup
import { getClient } from '@middle-monitor/sdk';
// Reads MIDDLE_MONITOR_API_URL, MIDDLE_MONITOR_SERVICE
const client = getClient();Express middleware
One line to enable automatic capture: one trace per request, error status on 4xx/5xx, and 5xx responses reported to the Errors view.
import { initSimple } from '@middle-monitor/sdk';
import { expressMiddleware } from '@middle-monitor/sdk/expressMiddleware';
initSimple();
app.use(expressMiddleware());To only report 5xx errors without tracing, use captureExceptionErrors() instead (do not combine both).
Request logs
expressMiddleware() also writes one log line per failed request, so the Logs view carries traffic without the application calling log itself:
GET /api/orders 500Carried as attributes: http.method, http.route, http.status_code, duration_ms. What gets through is decided by the log sampling rules — the defaults keep 2xx traffic out (that volume is what traces are for) and health probes out of the baseline:
| Response | Level | Logged by default |
|---|---|---|
| 2xx / 3xx | INFO | No |
| 4xx | WARN | Yes |
| 5xx | ERROR | Yes |
| /health, /metrics, /ready | — | No |
const cfg = newConfig(apiUrl, service, token);
cfg.sampling.logs.levels = [LogLevel.INFO]; // every request
cfg.sampling.logs.alwaysCaptureRoutes = ['/api/pay/*']; // every hit on a route
init(cfg);Unlike the Go and Python SDKs, the line carries no cause suffix: Express exposes the response body only to the res.end wrapper of captureExceptionErrors, which runs after this log is emitted. The cause is in the Errors view for the same request.
Caller address
The request log also carries a client.ip attribute, which is what tells a wall of 404s on /wp-login.php apart from a real user hitting a broken page. It is read from CF-Connecting-IP, True-Client-IP, X-Forwarded-For or X-Real-IP before falling back to the socket address, so a service behind Caddy, nginx or Cloudflare records the caller and not the proxy.
An IP address is personal data, so the default keeps the network and drops the host part — 203.0.113.42 is stored as 203.0.113.0, an IPv6 address is cut to its /48. That is enough to recognise a scan, not enough to single out a person.
const cfg = newConfig(apiUrl, service, token);
cfg.clientIp = ClientIpMode.FULL; // whole address: needs its own legal basis
cfg.clientIp = ClientIpMode.OFF; // record nothing
init(cfg);Recording full addresses is a decision about your users' data: give it a legal basis and say so in your privacy policy. An address that does not parse is dropped rather than stored, so a forged header never lands in the attribute.
Correlating with host metrics
Every export is labelled with host.name, which is what lets Middle-Monitor line up a CPU or memory spike on a host with the traffic of the services running on it. Inside a container os.hostname() is the container ID and matches no host, so set the real one:
environment:
MIDDLE_MONITOR_HOSTNAME: host4 # as the host is named in Middle-MonitorEnvironment variables
export MIDDLE_MONITOR_API_URL=https://api.middlemonitor.io
export MIDDLE_MONITOR_SERVICE=my-service
export MIDDLE_MONITOR_TOKEN=your_token
# Host this service runs on, as Middle-Monitor names it. Required in a container,
# where the OS hostname is the container ID and matches no host.
export MIDDLE_MONITOR_HOSTNAME=host4
# Optional: stop the Express middleware from reporting 5xx
export MIDDLE_MONITOR_DISABLE_HTTP_ERROR_REPORTING=true
# Optional: caller address on request logs — anonymized (default), full or off
export MIDDLE_MONITOR_CLIENT_IP=offMIDDLE_MONITOR_TOKEN also acts as the opt-in switch: with no token set, the SDK does not initialize itself and every entry point is a no-op, so an application that never configured Middle-Monitor never sends anything.
Applications that report their own errors
captureExceptionErrors() submits every 5xx to the Errors view, building the message from the response body. If your application already reports its errors from its own error handler, you get two entries per failure — one with the real cause, one generic. Disable the middleware's half:
const cfg = newConfig(apiUrl, service, token);
cfg.disableHttpErrorReporting = true;
init(cfg);