polartrace 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.1] - 2026-10-05
9
+
10
+ ### Changed
11
+
12
+ - Requests for paths the application has no route for are no longer recorded.
13
+ A request (and its trace) is dropped only when the framework matched no route
14
+ AND the response was 404, so scanner probes such as `/vendor/phpunit/...` or
15
+ `/index.php` no longer bury the real endpoints. A matched route returning 404
16
+ and routeless traffic served by middleware (e.g. static files) are still
17
+ recorded. Applies to Express, Fastify and Koa
18
+ - The exported class is now `Polartrace` (was `PolarTrace`), and the homepage
19
+ moved to [polartrace.io](https://www.polartrace.io)
20
+
21
+ ### Added
22
+
23
+ - `recordUnmatchedRoutes` option. Set it to `true` to record unmatched 404s as
24
+ before, e.g. when hunting misrouted traffic
25
+
8
26
  ## [2.0.0] - 2026-09-12
9
27
 
10
28
  The first release of the 2.x line - a ground-up hardening of the 1.x agent.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 PolarTrace
3
+ Copyright (c) 2026 Polartrace
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -4,9 +4,9 @@
4
4
  [![node](https://img.shields.io/node/v/polartrace.svg)](https://nodejs.org)
5
5
  [![license](https://img.shields.io/npm/l/polartrace.svg)](LICENSE)
6
6
 
7
- The Node.js agent for [PolarTrace](https://www.polartrace.com). It collects
7
+ The Node.js agent for [Polartrace](https://www.polartrace.io). It collects
8
8
  distributed traces, request logs and host metrics from your service and ships
9
- them to the PolarTrace collector - without a single line of application code.
9
+ them to the Polartrace collector - without a single line of application code.
10
10
 
11
11
  Built on [OpenTelemetry](https://opentelemetry.io).
12
12
 
@@ -83,7 +83,7 @@ The agent is configured entirely through environment variables.
83
83
  | Variable | Description |
84
84
  | --- | --- |
85
85
  | `POLARTRACE_APP_NAME` | Service name. Must be unique within your organization. |
86
- | `POLARTRACE_LICENSE_KEY` | Your PolarTrace license key. |
86
+ | `POLARTRACE_LICENSE_KEY` | Your Polartrace license key. |
87
87
 
88
88
  ### Optional
89
89
 
@@ -146,9 +146,9 @@ Preloading is the recommended integration. When you need explicit control over
146
146
  configuration, construct the agent yourself:
147
147
 
148
148
  ```js
149
- const { PolarTrace } = require("polartrace");
149
+ const { Polartrace } = require("polartrace");
150
150
 
151
- const agent = new PolarTrace({
151
+ const agent = new Polartrace({
152
152
  apiKey: process.env.POLARTRACE_LICENSE_KEY,
153
153
  serviceName: "checkout-service",
154
154
  captureBody: false, // opt out of request-body capture entirely
@@ -180,7 +180,7 @@ app wired up with the agent.
180
180
 
181
181
  ## Support
182
182
 
183
- - Documentation and dashboards: [polartrace.com](https://www.polartrace.com)
183
+ - Documentation and dashboards: [polartrace.io](https://www.polartrace.io)
184
184
  - Bugs and feature requests: [GitHub issues](https://github.com/polartrace/polartrace-nodejs-agent/issues)
185
185
  - Security reports: see [SECURITY.md](SECURITY.md)
186
186
 
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export interface PolarTraceConfig {
10
10
  captureBody?: boolean;
11
11
  captureQuery?: boolean;
12
12
  captureConsoleLogs?: boolean;
13
+ recordUnmatchedRoutes?: boolean;
13
14
  enableMongoSpanCollection?: boolean;
14
15
  enableRedisSpanCollection?: boolean;
15
16
  enablePostgresSpanCollection?: boolean;
@@ -45,7 +46,7 @@ export interface RequestLog {
45
46
  export interface TraceSpanData extends TraceSpan {
46
47
  serviceVersion?: string;
47
48
  }
48
- declare class PolarTrace {
49
+ declare class Polartrace {
49
50
  private config;
50
51
  private connectionStatus;
51
52
  private connectionError?;
@@ -116,6 +117,7 @@ declare class PolarTrace {
116
117
  private redactSensitive;
117
118
  private getClientIp;
118
119
  private generateRequestId;
120
+ private isUnmatchedRouteProbe;
119
121
  private logRequest;
120
122
  private queueLog;
121
123
  private flushLogs;
@@ -127,5 +129,5 @@ declare class PolarTrace {
127
129
  shutdown(timeoutMs?: number): Promise<void>;
128
130
  destroy(): void;
129
131
  }
130
- export { PolarTrace };
132
+ export { Polartrace };
131
133
  import "./register";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PolarTrace = void 0;
3
+ exports.Polartrace = void 0;
4
4
  const api_1 = require("@opentelemetry/api");
5
5
  const trace_1 = require("./trace");
6
6
  const crypto_1 = require("crypto");
@@ -23,7 +23,7 @@ const mongo_instrumentation_1 = require("./instrumentations/mongo.instrumentatio
23
23
  const redis_instrumentation_1 = require("./instrumentations/redis.instrumentation");
24
24
  const postgres_instrumentation_1 = require("./instrumentations/postgres.instrumentation");
25
25
  const host_metrics_monitor_1 = require("./metrics/host-metrics-monitor");
26
- class PolarTrace {
26
+ class Polartrace {
27
27
  constructor(config) {
28
28
  this.connectionStatus = "pending";
29
29
  this.statusAnnounced = false;
@@ -58,6 +58,7 @@ class PolarTrace {
58
58
  captureBody: true,
59
59
  captureQuery: true,
60
60
  captureConsoleLogs: true,
61
+ recordUnmatchedRoutes: false,
61
62
  enableMongoSpanCollection: true,
62
63
  enableRedisSpanCollection: true,
63
64
  enablePostgresSpanCollection: true,
@@ -160,7 +161,7 @@ class PolarTrace {
160
161
  throw new Error("apiKey is required (set POLARTRACE_LICENSE_KEY)");
161
162
  }
162
163
  if (this.config.apiKey.length < 10) {
163
- throw new Error("apiKey does not look like a PolarTrace license key (set POLARTRACE_LICENSE_KEY)");
164
+ throw new Error("apiKey does not look like a Polartrace license key (set POLARTRACE_LICENSE_KEY)");
164
165
  }
165
166
  }
166
167
  setupFlushTimer() {
@@ -329,6 +330,7 @@ class PolarTrace {
329
330
  serviceName: this.config.serviceName,
330
331
  serviceVersion: version_1.AGENT_VERSION,
331
332
  excludeAgentSpans: true,
333
+ recordUnmatchedRoutes: this.config.recordUnmatchedRoutes,
332
334
  agentEndpoints: agentEndpointPatterns.length > 0 ? agentEndpointPatterns : undefined,
333
335
  sharedSpanIdMap: this.spanIdMap,
334
336
  onSpan: (span) => {
@@ -698,7 +700,10 @@ class PolarTrace {
698
700
  requestLog.consoleLogs = capturedLogs;
699
701
  }
700
702
  }
701
- this.logRequest(requestLog);
703
+ const koaRoute = ctx._matchedRoute ?? ctx.routerPath ?? ctx.router?.match;
704
+ if (!this.isUnmatchedRouteProbe(koaRoute, requestLog.statusCode)) {
705
+ this.logRequest(requestLog);
706
+ }
702
707
  }
703
708
  if (thrown)
704
709
  throw thrown;
@@ -774,6 +779,9 @@ class PolarTrace {
774
779
  name: state.error?.name,
775
780
  };
776
781
  }
782
+ const fastifyRoute = request.routeOptions?.url ?? request.routerPath ?? request.context?.config?.url;
783
+ if (this.isUnmatchedRouteProbe(fastifyRoute, reply.statusCode))
784
+ return;
777
785
  this.logRequest(requestLog);
778
786
  });
779
787
  }
@@ -793,6 +801,9 @@ class PolarTrace {
793
801
  requestLog.consoleLogs = capturedLogs;
794
802
  }
795
803
  }
804
+ if (this.isUnmatchedRouteProbe(req?.route, res.statusCode)) {
805
+ return originalMethod.call(res, data);
806
+ }
796
807
  this.logRequest(requestLog);
797
808
  return originalMethod.call(res, data);
798
809
  }
@@ -871,6 +882,13 @@ class PolarTrace {
871
882
  generateRequestId() {
872
883
  return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
873
884
  }
885
+ isUnmatchedRouteProbe(matchedRoute, statusCode) {
886
+ if (this.config.recordUnmatchedRoutes)
887
+ return false;
888
+ if (statusCode !== 404)
889
+ return false;
890
+ return !matchedRoute;
891
+ }
874
892
  logRequest(log) {
875
893
  this.queueLog(log);
876
894
  }
@@ -1172,7 +1190,7 @@ class PolarTrace {
1172
1190
  diagnostics_1.diagnostics.close();
1173
1191
  }
1174
1192
  }
1175
- exports.PolarTrace = PolarTrace;
1193
+ exports.Polartrace = Polartrace;
1176
1194
  function envFlag(name, fallback) {
1177
1195
  const raw = process.env[name]?.trim().toLowerCase();
1178
1196
  if (raw === undefined || raw === "") {
@@ -1194,7 +1212,7 @@ function autoInitFromEnv() {
1194
1212
  const logFile = process.env.POLARTRACE_LOG_FILE?.trim() || undefined;
1195
1213
  let agent;
1196
1214
  try {
1197
- agent = new PolarTrace({
1215
+ agent = new Polartrace({
1198
1216
  apiKey,
1199
1217
  serviceName,
1200
1218
  enableConsoleLog: envFlag("POLARTRACE_ENABLE_CONSOLE_LOG", false),
@@ -28,6 +28,7 @@ export interface TraceMonitorConfig {
28
28
  serviceVersion?: string;
29
29
  onSpan: (span: TraceSpan) => void;
30
30
  excludeAgentSpans?: boolean;
31
+ recordUnmatchedRoutes?: boolean;
31
32
  agentEndpoints?: string[];
32
33
  sharedSpanIdMap?: Map<string, string>;
33
34
  }
@@ -95,6 +95,9 @@ class CustomSpanProcessor {
95
95
  if (this.config.excludeAgentSpans && this.isAgentSpan(span)) {
96
96
  return;
97
97
  }
98
+ if (this.isUnmatchedRouteSpan(span)) {
99
+ return;
100
+ }
98
101
  if (this.isExpressMiddlewareSpan(span)) {
99
102
  return;
100
103
  }
@@ -175,6 +178,18 @@ class CustomSpanProcessor {
175
178
  spanName.startsWith("pg.") ||
176
179
  spanName.startsWith("pg-pool"));
177
180
  }
181
+ isUnmatchedRouteSpan(span) {
182
+ if (this.config.recordUnmatchedRoutes)
183
+ return false;
184
+ if (span.kind !== api_1.SpanKind.SERVER)
185
+ return false;
186
+ const attributes = span.attributes || {};
187
+ const status = Number(attributes["http.status_code"] ?? attributes["http.response.status_code"]);
188
+ if (status !== 404)
189
+ return false;
190
+ const route = attributes["http.route"];
191
+ return route === undefined || route === null || route === "";
192
+ }
178
193
  isInternalNoiseSpan(span) {
179
194
  const spanName = span.name?.toLowerCase() || "";
180
195
  const attributes = span.attributes || {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polartrace",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Zero-code observability agent for Node.js: distributed tracing, request logs and host metrics for Express, NestJS, Fastify and Koa apps, with automatic MongoDB, PostgreSQL and Redis instrumentation. Built on OpenTelemetry.",
5
5
  "keywords": [
6
6
  "polartrace",
@@ -27,7 +27,7 @@
27
27
  "postgresql",
28
28
  "redis"
29
29
  ],
30
- "homepage": "https://www.polartrace.com",
30
+ "homepage": "https://www.polartrace.io",
31
31
  "repository": {
32
32
  "type": "git",
33
33
  "url": "https://github.com/polartrace/polartrace-nodejs-agent.git"
@@ -36,7 +36,7 @@
36
36
  "url": "https://github.com/polartrace/polartrace-nodejs-agent/issues"
37
37
  },
38
38
  "license": "MIT",
39
- "author": "PolarTrace",
39
+ "author": "Polartrace",
40
40
  "engines": {
41
41
  "node": ">=18"
42
42
  },