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 +18 -0
- package/LICENSE +1 -1
- package/README.md +6 -6
- package/dist/index.d.ts +4 -2
- package/dist/index.js +24 -6
- package/dist/trace/trace-monitor.d.ts +1 -0
- package/dist/trace/trace-monitor.js +15 -0
- package/package.json +3 -3
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
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
[](https://nodejs.org)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
The Node.js agent for [
|
|
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
|
|
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
|
|
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 {
|
|
149
|
+
const { Polartrace } = require("polartrace");
|
|
150
150
|
|
|
151
|
-
const agent = new
|
|
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.
|
|
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
|
|
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 {
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
1215
|
+
agent = new Polartrace({
|
|
1198
1216
|
apiKey,
|
|
1199
1217
|
serviceName,
|
|
1200
1218
|
enableConsoleLog: envFlag("POLARTRACE_ENABLE_CONSOLE_LOG", false),
|
|
@@ -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.
|
|
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.
|
|
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": "
|
|
39
|
+
"author": "Polartrace",
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=18"
|
|
42
42
|
},
|