polartrace 2.0.0
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 +113 -0
- package/LICENSE +21 -0
- package/README.md +189 -0
- package/dist/diagnostics.d.ts +20 -0
- package/dist/diagnostics.js +105 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +1391 -0
- package/dist/instrumentations/instrumentation-manager.d.ts +12 -0
- package/dist/instrumentations/instrumentation-manager.js +50 -0
- package/dist/instrumentations/instrumentation.d.ts +4 -0
- package/dist/instrumentations/instrumentation.js +2 -0
- package/dist/instrumentations/mongo.instrumentation.d.ts +32 -0
- package/dist/instrumentations/mongo.instrumentation.js +131 -0
- package/dist/instrumentations/postgres.instrumentation.d.ts +29 -0
- package/dist/instrumentations/postgres.instrumentation.js +142 -0
- package/dist/instrumentations/redis.instrumentation.d.ts +31 -0
- package/dist/instrumentations/redis.instrumentation.js +183 -0
- package/dist/metrics/host-metrics-monitor.d.ts +57 -0
- package/dist/metrics/host-metrics-monitor.js +189 -0
- package/dist/module-hook.d.ts +3 -0
- package/dist/module-hook.js +82 -0
- package/dist/register.d.ts +1 -0
- package/dist/register.js +16 -0
- package/dist/trace/index.d.ts +1 -0
- package/dist/trace/index.js +5 -0
- package/dist/trace/trace-monitor.d.ts +42 -0
- package/dist/trace/trace-monitor.js +376 -0
- package/dist/ts-loader.d.ts +1 -0
- package/dist/ts-loader.js +75 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +12 -0
- package/package.json +118 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [2.0.0] - 2026-09-12
|
|
9
|
+
|
|
10
|
+
The first release of the 2.x line - a ground-up hardening of the 1.x agent.
|
|
11
|
+
Everything below ships together as 2.0.0.
|
|
12
|
+
|
|
13
|
+
### Breaking
|
|
14
|
+
|
|
15
|
+
- The agent no longer creates `polartrace_agent.log` in the working directory.
|
|
16
|
+
Diagnostics are off by default; set `POLARTRACE_LOG_FILE=<path>` to get an
|
|
17
|
+
append-only diagnostics file at a location you control
|
|
18
|
+
- Conditions that cause silent data loss (unrecognised license key, unreachable
|
|
19
|
+
collector, batches the collector rejects) are now reported on **stderr** as a
|
|
20
|
+
single `[polartrace] ...` line, once per condition. Nothing is ever written to
|
|
21
|
+
stdout
|
|
22
|
+
- A misconfigured agent under `-r polartrace` now disables itself and reports
|
|
23
|
+
why, instead of throwing during preload and preventing the host application
|
|
24
|
+
from starting
|
|
25
|
+
- `express` is no longer a required peer dependency. `express`, `fastify`, `koa`
|
|
26
|
+
and `mongoose` are all optional peers, so a Fastify- or Koa-only application no
|
|
27
|
+
longer pulls in Express
|
|
28
|
+
- `mongodb`, `mongoose` and `axios` are no longer runtime dependencies; the agent
|
|
29
|
+
patches the host application's own drivers and uses native `fetch`
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Fastify (4.x, 5.x) and Koa (2.x, 3.x) request-log capture, attached
|
|
34
|
+
automatically at instance creation
|
|
35
|
+
- PostgreSQL span collection via the `pg` driver, with `db.system`,
|
|
36
|
+
`db.operation`, `db.sql.table` and `db.statement` attributes
|
|
37
|
+
(opt-out: `POLARTRACE_DISABLE_POSTGRES_SPANS`)
|
|
38
|
+
- Redis span collection for `ioredis` and node-redis v4+
|
|
39
|
+
(opt-out: `POLARTRACE_DISABLE_REDIS_SPANS`)
|
|
40
|
+
- Host metrics sampling: process CPU/memory, event-loop lag percentiles, host
|
|
41
|
+
load and memory, container cgroup limits
|
|
42
|
+
(opt-out: `POLARTRACE_DISABLE_HOST_METRICS`)
|
|
43
|
+
- TypeScript entry points run under `-r polartrace` by picking up `tsx` or
|
|
44
|
+
`ts-node` from the host application
|
|
45
|
+
- Queued telemetry is flushed on `SIGTERM`, `SIGINT` and `beforeExit`, deferring
|
|
46
|
+
to the application's own signal handlers when it has them
|
|
47
|
+
- `POLARTRACE_ENDPOINT` to override the collector URL
|
|
48
|
+
- `POLARTRACE_LOG_FILE` and the `logFile` config option
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- OpenTelemetry upgraded to the 2.x core line. HTTP spans carry both the stable
|
|
53
|
+
semantic conventions (`http.request.method`, `url.path`, ...) and their legacy
|
|
54
|
+
equivalents (`http.method`, `http.target`, ...), so the collector's wire format
|
|
55
|
+
is unchanged by the upgrade
|
|
56
|
+
- `@types/express` moved to devDependencies; it is no longer installed by
|
|
57
|
+
consumers that do not use Express
|
|
58
|
+
- Batches are retried only on 429/5xx/network errors, and dropped with a warning
|
|
59
|
+
on other 4xx responses (401/402/400/413) that can never succeed on retry
|
|
60
|
+
- Retained failures back off exponentially (10s doubling to a 5 minute ceiling)
|
|
61
|
+
and honour the collector's `Retry-After` header on 429
|
|
62
|
+
- Log and trace queues are bounded at 5000 items (drop-oldest), matching host
|
|
63
|
+
metrics, so a long collector outage cannot grow memory without limit
|
|
64
|
+
- Flushes ship at most 500 items per tick instead of the entire queue
|
|
65
|
+
- Flush timers are `unref()`ed, so the agent never keeps the host process alive
|
|
66
|
+
- Spans now report the agent's real version as `service.version` instead of a
|
|
67
|
+
hardcoded `1.0.0`
|
|
68
|
+
- The published package no longer contains internal implementation comments
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- NestJS route exceptions now carry their message and stack in the request
|
|
73
|
+
log on both Nest platforms (Express and Fastify). Nest's exception layer
|
|
74
|
+
catches every route error and responds itself, so nothing ever reached the
|
|
75
|
+
underlying framework's error paths; the agent now records the exception
|
|
76
|
+
from `BaseExceptionFilter.catch` before Nest responds. 4xx `HttpException`s
|
|
77
|
+
(`NotFoundException`, validation 400s...) are expected control flow and are
|
|
78
|
+
deliberately not recorded as errors
|
|
79
|
+
- Express thrown/`next(err)` route errors now carry their message and stack in
|
|
80
|
+
the request log. They travel Express's error-middleware chain (never the
|
|
81
|
+
req/res `error` events the agent listened on), so a 500 was recorded with an
|
|
82
|
+
empty error. The agent now appends a pass-through error middleware at
|
|
83
|
+
`listen()` time, after the user's stack is complete; Koa and Fastify already
|
|
84
|
+
captured these via their own hooks
|
|
85
|
+
- Request headers are redacted before transmission. `Authorization`, `Cookie` and
|
|
86
|
+
`X-API-Key` were previously shipped to the collector in clear text on every
|
|
87
|
+
request, despite the documented redaction policy. `cookie` and `api-key` were
|
|
88
|
+
added to the sensitive-field list, which now covers bodies and headers alike
|
|
89
|
+
- Express now captures the request body. It was read at middleware entry, before
|
|
90
|
+
`express.json()` had parsed anything, so the `body` field was always absent -
|
|
91
|
+
Fastify and Koa were unaffected
|
|
92
|
+
- node-redis (v4+) commands now produce spans. The patch targeted the public
|
|
93
|
+
`client.sendCommand`, which node-redis' generated commands never call - they
|
|
94
|
+
reach the connection through a private method - so the instrumentation was
|
|
95
|
+
silently inert. The generated command methods are now wrapped directly
|
|
96
|
+
- Fastify 5 and Koa 3 spans carry `http.route` again. The pinned OpenTelemetry
|
|
97
|
+
bundle predated both, so every endpoint collapsed into a bare `GET`/`POST` span
|
|
98
|
+
with no route. The OpenTelemetry stack was upgraded and Fastify's
|
|
99
|
+
instrumentation, no longer part of the auto-instrumentations bundle, is
|
|
100
|
+
registered explicitly
|
|
101
|
+
- ESM entry points now produce request logs and database spans. Auto-attach was
|
|
102
|
+
installed on `Module.prototype.require`, which `import` never reaches, so an
|
|
103
|
+
ESM application silently lost all request logging. Hooks now go through
|
|
104
|
+
`Module._load`, which both module systems use
|
|
105
|
+
- Inline SQL string literals in `db.statement` are replaced with `'?'`
|
|
106
|
+
- Agent ingest paths are excluded from tracing by exact path. The previous bare
|
|
107
|
+
`/log` / `/logs` / `/traces` fragments matched any application route
|
|
108
|
+
containing them and erased those routes from tracing
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
Releases before 2.0.0 (the 1.x line) predate the public repository and are
|
|
113
|
+
intentionally not documented here.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PolarTrace
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# polartrace
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/polartrace)
|
|
4
|
+
[](https://nodejs.org)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
The Node.js agent for [PolarTrace](https://www.polartrace.com). It collects
|
|
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.
|
|
10
|
+
|
|
11
|
+
Built on [OpenTelemetry](https://opentelemetry.io).
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install polartrace
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires Node.js 18 or later.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
Preload the agent and give it a service name and license key:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
POLARTRACE_APP_NAME=checkout-service \
|
|
27
|
+
POLARTRACE_LICENSE_KEY=<your-license-key> \
|
|
28
|
+
node -r polartrace server.js
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
That's it. The agent starts before your application, instruments the frameworks
|
|
32
|
+
and drivers it finds, and begins reporting. If your entry point is TypeScript,
|
|
33
|
+
run it the same way - the agent picks up `tsx` or `ts-node` from your
|
|
34
|
+
dependencies automatically.
|
|
35
|
+
|
|
36
|
+
### Docker
|
|
37
|
+
|
|
38
|
+
```dockerfile
|
|
39
|
+
FROM node:20-slim
|
|
40
|
+
WORKDIR /app
|
|
41
|
+
COPY package*.json ./
|
|
42
|
+
RUN npm ci --omit=dev
|
|
43
|
+
COPY . .
|
|
44
|
+
|
|
45
|
+
ENV POLARTRACE_APP_NAME=checkout-service
|
|
46
|
+
# Supply POLARTRACE_LICENSE_KEY at runtime, not in the image.
|
|
47
|
+
CMD ["node", "-r", "polartrace", "server.js"]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
services:
|
|
52
|
+
app:
|
|
53
|
+
build: .
|
|
54
|
+
environment:
|
|
55
|
+
POLARTRACE_APP_NAME: checkout-service
|
|
56
|
+
POLARTRACE_LICENSE_KEY: ${POLARTRACE_LICENSE_KEY}
|
|
57
|
+
command: node -r polartrace server.js
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## What gets instrumented
|
|
61
|
+
|
|
62
|
+
| Area | Support | Notes |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| HTTP server & client | Automatic | Inbound and outbound requests, via OpenTelemetry |
|
|
65
|
+
| Express | 4.x | Middleware attached automatically at app creation |
|
|
66
|
+
| Fastify | 4.x, 5.x | Hooks attached automatically at instance creation |
|
|
67
|
+
| Koa | 2.x, 3.x | Middleware prepended automatically |
|
|
68
|
+
| NestJS | 9.x, 10.x | Via its Express/Fastify platform; route exceptions captured from Nest's exception layer |
|
|
69
|
+
| MongoDB / Mongoose | mongoose ≥ 6 | Query spans with collection and operation |
|
|
70
|
+
| PostgreSQL | `pg` | Query spans with `db.operation`, `db.sql.table`, `db.statement` |
|
|
71
|
+
| Redis | `ioredis`, `redis` ≥ 4 | Command spans |
|
|
72
|
+
| Host metrics | Automatic | Process CPU/memory, event-loop lag, host load, cgroup limits |
|
|
73
|
+
|
|
74
|
+
Every framework and driver above is optional. The agent patches only what your
|
|
75
|
+
application actually loads, and installs nothing on your behalf.
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
The agent is configured entirely through environment variables.
|
|
80
|
+
|
|
81
|
+
### Required
|
|
82
|
+
|
|
83
|
+
| Variable | Description |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `POLARTRACE_APP_NAME` | Service name. Must be unique within your organization. |
|
|
86
|
+
| `POLARTRACE_LICENSE_KEY` | Your PolarTrace license key. |
|
|
87
|
+
|
|
88
|
+
### Optional
|
|
89
|
+
|
|
90
|
+
| Variable | Default | Description |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `POLARTRACE_ENDPOINT` | `https://collector.polartrace.io/api/log` | Collector URL. |
|
|
93
|
+
| `POLARTRACE_LOG_FILE` | *(none)* | Append the agent's own diagnostics to this path. |
|
|
94
|
+
| `POLARTRACE_ENABLE_CONSOLE_LOG` | `false` | Mirror verbose agent diagnostics to stderr. |
|
|
95
|
+
| `POLARTRACE_DISABLE_HOST_METRICS` | `false` | Turn off CPU/memory/event-loop sampling. |
|
|
96
|
+
| `POLARTRACE_DISABLE_MONGO_SPANS` | `false` | Turn off MongoDB span collection. |
|
|
97
|
+
| `POLARTRACE_DISABLE_POSTGRES_SPANS` | `false` | Turn off PostgreSQL span collection. |
|
|
98
|
+
| `POLARTRACE_DISABLE_REDIS_SPANS` | `false` | Turn off Redis span collection. |
|
|
99
|
+
|
|
100
|
+
Boolean variables accept `1` or `true`.
|
|
101
|
+
|
|
102
|
+
## Data collection and redaction
|
|
103
|
+
|
|
104
|
+
For each request the agent records method, path, status code, duration, client
|
|
105
|
+
IP, user agent, headers, query parameters, body and any console output produced
|
|
106
|
+
while handling it, along with the trace the request belongs to.
|
|
107
|
+
|
|
108
|
+
Fields whose names contain `password`, `token`, `secret`, `apiKey`, `api-key`,
|
|
109
|
+
`authorization`, `creditCard`, `ssn` or `cookie` are replaced with `[REDACTED]`
|
|
110
|
+
before anything leaves the process - in nested objects and in **request headers**
|
|
111
|
+
as well as at the top level, so `Authorization`, `Cookie` and `X-API-Key` never
|
|
112
|
+
leave in the clear. Redaction happens client-side; the original values are never
|
|
113
|
+
transmitted.
|
|
114
|
+
|
|
115
|
+
SQL captured in `db.statement` has inline string literals replaced with `'?'`, so
|
|
116
|
+
a query that interpolates a secret does not ship it. Parameterised queries are
|
|
117
|
+
unaffected - the driver never hands the agent the values.
|
|
118
|
+
|
|
119
|
+
If your payloads carry sensitive data under names outside that list, turn off
|
|
120
|
+
body capture with the programmatic API below.
|
|
121
|
+
|
|
122
|
+
## Agent diagnostics
|
|
123
|
+
|
|
124
|
+
The agent is quiet by design. It writes nothing to stdout and creates no files.
|
|
125
|
+
|
|
126
|
+
Problems that would otherwise cause silent data loss - an unrecognised license
|
|
127
|
+
key, an unreachable collector, a rejected batch - are reported on **stderr** as a
|
|
128
|
+
single line, once per condition:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
[polartrace] collector unavailable: license key not recognised
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For a full diagnostic trail, point `POLARTRACE_LOG_FILE` at a path you control:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
POLARTRACE_LOG_FILE=/var/log/polartrace-agent.log node -r polartrace server.js
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
A misconfigured agent disables itself and reports why. It will not stop your
|
|
141
|
+
application from starting.
|
|
142
|
+
|
|
143
|
+
## Programmatic usage
|
|
144
|
+
|
|
145
|
+
Preloading is the recommended integration. When you need explicit control over
|
|
146
|
+
configuration, construct the agent yourself:
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
const { PolarTrace } = require("polartrace");
|
|
150
|
+
|
|
151
|
+
const agent = new PolarTrace({
|
|
152
|
+
apiKey: process.env.POLARTRACE_LICENSE_KEY,
|
|
153
|
+
serviceName: "checkout-service",
|
|
154
|
+
captureBody: false, // opt out of request-body capture entirely
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
app.use(agent.middleware()); // Express
|
|
158
|
+
// agent.instrumentFastify(app); // Fastify
|
|
159
|
+
// app.use(agent.koaMiddleware()); // Koa
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Call `await agent.shutdown()` to flush anything still queued before exiting.
|
|
163
|
+
Under `-r polartrace` this is wired up for you: the agent flushes on `SIGTERM`,
|
|
164
|
+
`SIGINT` and `beforeExit`, and defers to your own signal handlers if you have
|
|
165
|
+
them.
|
|
166
|
+
|
|
167
|
+
## Reliability
|
|
168
|
+
|
|
169
|
+
Telemetry is queued and flushed every 10 seconds, at most 500 items per batch.
|
|
170
|
+
Queues are bounded and drop oldest-first, so a collector outage cannot grow
|
|
171
|
+
memory without limit. Failed batches are retried with exponential backoff up to
|
|
172
|
+
5 minutes and honour the collector's `Retry-After`; batches the collector
|
|
173
|
+
rejects outright are dropped rather than retried forever. Timers are `unref`ed,
|
|
174
|
+
so the agent never keeps your process alive on its own.
|
|
175
|
+
|
|
176
|
+
## Examples
|
|
177
|
+
|
|
178
|
+
[`examples/express-basic`](examples/express-basic) is a minimal runnable Express
|
|
179
|
+
app wired up with the agent.
|
|
180
|
+
|
|
181
|
+
## Support
|
|
182
|
+
|
|
183
|
+
- Documentation and dashboards: [polartrace.com](https://www.polartrace.com)
|
|
184
|
+
- Bugs and feature requests: [GitHub issues](https://github.com/polartrace/polartrace-nodejs-agent/issues)
|
|
185
|
+
- Security reports: see [SECURITY.md](SECURITY.md)
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type DiagnosticLevel = "error" | "warn" | "info" | "debug";
|
|
2
|
+
export interface DiagnosticsOptions {
|
|
3
|
+
verbose?: boolean;
|
|
4
|
+
filePath?: string;
|
|
5
|
+
}
|
|
6
|
+
declare class Diagnostics {
|
|
7
|
+
private verbose;
|
|
8
|
+
private stream?;
|
|
9
|
+
private readonly announced;
|
|
10
|
+
configure(options: DiagnosticsOptions): void;
|
|
11
|
+
error(message: string): void;
|
|
12
|
+
warn(message: string): void;
|
|
13
|
+
info(message: string): void;
|
|
14
|
+
debug(message: string): void;
|
|
15
|
+
warnOnce(key: string, message: string): void;
|
|
16
|
+
private emit;
|
|
17
|
+
close(): void;
|
|
18
|
+
}
|
|
19
|
+
export declare const diagnostics: Diagnostics;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.diagnostics = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const PREFIX = "[polartrace]";
|
|
39
|
+
class Diagnostics {
|
|
40
|
+
constructor() {
|
|
41
|
+
this.verbose = false;
|
|
42
|
+
this.announced = new Set();
|
|
43
|
+
}
|
|
44
|
+
configure(options) {
|
|
45
|
+
if (options.verbose !== undefined) {
|
|
46
|
+
this.verbose = options.verbose;
|
|
47
|
+
}
|
|
48
|
+
const filePath = options.filePath?.trim();
|
|
49
|
+
if (!filePath || this.stream) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
this.stream = fs.createWriteStream(filePath, { flags: "a" });
|
|
54
|
+
this.stream.on("error", () => {
|
|
55
|
+
this.stream = undefined;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
process.stderr.write(`${PREFIX} could not open log file ${filePath}: ${error.message}\n`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
error(message) {
|
|
63
|
+
this.emit("error", message);
|
|
64
|
+
}
|
|
65
|
+
warn(message) {
|
|
66
|
+
this.emit("warn", message);
|
|
67
|
+
}
|
|
68
|
+
info(message) {
|
|
69
|
+
this.emit("info", message);
|
|
70
|
+
}
|
|
71
|
+
debug(message) {
|
|
72
|
+
this.emit("debug", message);
|
|
73
|
+
}
|
|
74
|
+
warnOnce(key, message) {
|
|
75
|
+
const alreadyAnnounced = this.announced.has(key);
|
|
76
|
+
this.announced.add(key);
|
|
77
|
+
this.emit("warn", message, { toStderr: !alreadyAnnounced });
|
|
78
|
+
}
|
|
79
|
+
emit(level, message, options) {
|
|
80
|
+
if (this.stream) {
|
|
81
|
+
try {
|
|
82
|
+
this.stream.write(`${new Date().toISOString()} ${level.toUpperCase().padEnd(5)} ${message}\n`);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const isProblem = level === "error" || level === "warn";
|
|
88
|
+
const toStderr = options?.toStderr ?? true;
|
|
89
|
+
if (toStderr && (isProblem || this.verbose)) {
|
|
90
|
+
process.stderr.write(`${PREFIX} ${message}\n`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
close() {
|
|
94
|
+
if (!this.stream) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
this.stream.end();
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
}
|
|
102
|
+
this.stream = undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.diagnostics = new Diagnostics();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { TraceSpan } from "./trace";
|
|
3
|
+
export interface PolarTraceConfig {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
serviceName: string;
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
enableConsoleLog?: boolean;
|
|
8
|
+
logFile?: string;
|
|
9
|
+
captureHeaders?: boolean;
|
|
10
|
+
captureBody?: boolean;
|
|
11
|
+
captureQuery?: boolean;
|
|
12
|
+
captureConsoleLogs?: boolean;
|
|
13
|
+
enableMongoSpanCollection?: boolean;
|
|
14
|
+
enableRedisSpanCollection?: boolean;
|
|
15
|
+
enablePostgresSpanCollection?: boolean;
|
|
16
|
+
enableHostMetrics?: boolean;
|
|
17
|
+
mongoose?: any;
|
|
18
|
+
}
|
|
19
|
+
export interface RequestLog {
|
|
20
|
+
timestamp: string;
|
|
21
|
+
method: string;
|
|
22
|
+
path: string;
|
|
23
|
+
statusCode?: number;
|
|
24
|
+
duration: number;
|
|
25
|
+
startTime?: string;
|
|
26
|
+
endTime?: string;
|
|
27
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
28
|
+
query?: Record<string, any>;
|
|
29
|
+
body?: any;
|
|
30
|
+
userAgent?: string;
|
|
31
|
+
ip?: string;
|
|
32
|
+
host?: string;
|
|
33
|
+
consoleLogs?: Array<{
|
|
34
|
+
timestamp: string;
|
|
35
|
+
level: string;
|
|
36
|
+
args: any[];
|
|
37
|
+
}>;
|
|
38
|
+
traceId?: string;
|
|
39
|
+
error?: {
|
|
40
|
+
message: string;
|
|
41
|
+
stack?: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export interface TraceSpanData extends TraceSpan {
|
|
46
|
+
serviceVersion?: string;
|
|
47
|
+
}
|
|
48
|
+
declare class PolarTrace {
|
|
49
|
+
private config;
|
|
50
|
+
private connectionStatus;
|
|
51
|
+
private connectionError?;
|
|
52
|
+
private statusAnnounced;
|
|
53
|
+
private logQueue;
|
|
54
|
+
private flushTimer?;
|
|
55
|
+
private defaultHeaders;
|
|
56
|
+
private originalConsoleLog?;
|
|
57
|
+
private originalConsoleError?;
|
|
58
|
+
private originalConsoleWarn?;
|
|
59
|
+
private originalConsoleInfo?;
|
|
60
|
+
private isFlushing;
|
|
61
|
+
private isTraceFlushing;
|
|
62
|
+
private isHostMetricsFlushing;
|
|
63
|
+
private traceMonitor?;
|
|
64
|
+
private traceQueue;
|
|
65
|
+
private traceFlushTimer?;
|
|
66
|
+
private hostMetricsMonitor?;
|
|
67
|
+
private readonly hostMetricsQueue;
|
|
68
|
+
private hostMetricsFlushTimer?;
|
|
69
|
+
private readonly HOST_METRICS_QUEUE_LIMIT;
|
|
70
|
+
private readonly LOG_QUEUE_LIMIT;
|
|
71
|
+
private readonly TRACE_QUEUE_LIMIT;
|
|
72
|
+
private readonly MAX_BATCH_SIZE;
|
|
73
|
+
private readonly FLUSH_INTERVAL;
|
|
74
|
+
private readonly API_TIMEOUT;
|
|
75
|
+
private readonly MAX_BACKOFF_MS;
|
|
76
|
+
private logConsecutiveFailures;
|
|
77
|
+
private logBackoffUntil;
|
|
78
|
+
private traceConsecutiveFailures;
|
|
79
|
+
private traceBackoffUntil;
|
|
80
|
+
private hostMetricsConsecutiveFailures;
|
|
81
|
+
private hostMetricsBackoffUntil;
|
|
82
|
+
private traceCache;
|
|
83
|
+
private parentSpanTracker;
|
|
84
|
+
private traceTimestamps;
|
|
85
|
+
private readonly TRACE_CACHE_TIMEOUT;
|
|
86
|
+
private spanIdMap;
|
|
87
|
+
constructor(config: PolarTraceConfig);
|
|
88
|
+
private postJson;
|
|
89
|
+
private shouldRetainBatch;
|
|
90
|
+
private nextBackoffMs;
|
|
91
|
+
private getBaseUrl;
|
|
92
|
+
private validateApiKey;
|
|
93
|
+
private setupFlushTimer;
|
|
94
|
+
private initializeHostMetricsMonitoring;
|
|
95
|
+
private queueHostMetricSample;
|
|
96
|
+
private describeNetworkError;
|
|
97
|
+
private validateConnection;
|
|
98
|
+
private showConnectionStatus;
|
|
99
|
+
private initializeTraceMonitoringSync;
|
|
100
|
+
private queueTraceSpan;
|
|
101
|
+
private isParentSpan;
|
|
102
|
+
private flushTrace;
|
|
103
|
+
private cleanupOldTraces;
|
|
104
|
+
private convertMongoSpanToTraceSpan;
|
|
105
|
+
private convertRedisSpanToTraceSpan;
|
|
106
|
+
private convertPostgresSpanToTraceSpan;
|
|
107
|
+
private convertSpanIdToUUID;
|
|
108
|
+
private generateUUID;
|
|
109
|
+
private getActiveTraceId;
|
|
110
|
+
middleware(): (req: Request, res: Response, next: NextFunction) => void;
|
|
111
|
+
koaMiddleware(): (ctx: any, next: () => Promise<any>) => Promise<void>;
|
|
112
|
+
instrumentFastify(app: any): void;
|
|
113
|
+
private handleResponse;
|
|
114
|
+
private interceptConsole;
|
|
115
|
+
private restoreConsole;
|
|
116
|
+
private redactSensitive;
|
|
117
|
+
private getClientIp;
|
|
118
|
+
private generateRequestId;
|
|
119
|
+
private logRequest;
|
|
120
|
+
private queueLog;
|
|
121
|
+
private flushLogs;
|
|
122
|
+
private sendLogsToAPI;
|
|
123
|
+
private flushTraces;
|
|
124
|
+
private sendTracesToAPI;
|
|
125
|
+
private flushHostMetrics;
|
|
126
|
+
private sendHostMetricsToAPI;
|
|
127
|
+
shutdown(timeoutMs?: number): Promise<void>;
|
|
128
|
+
destroy(): void;
|
|
129
|
+
}
|
|
130
|
+
export { PolarTrace };
|
|
131
|
+
import "./register";
|