apitally 1.0.0-beta.4 → 1.0.0-beta.6
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/README.md +128 -101
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/activation.cjs +31 -1
- package/dist/activation.cjs.map +1 -1
- package/dist/activation.d.cts +1 -0
- package/dist/activation.d.ts +1 -0
- package/dist/activation.js +29 -2
- package/dist/activation.js.map +1 -1
- package/dist/adonisjs/middleware.cjs +1 -1
- package/dist/adonisjs/middleware.cjs.map +1 -1
- package/dist/adonisjs/middleware.js +1 -1
- package/dist/adonisjs/middleware.js.map +1 -1
- package/dist/config.cjs +6 -3
- package/dist/config.cjs.map +1 -1
- package/dist/config.js +6 -3
- package/dist/config.js.map +1 -1
- package/dist/elysia/index.cjs.map +1 -1
- package/dist/elysia/index.js.map +1 -1
- package/dist/elysia/middleware.cjs +8 -10
- package/dist/elysia/middleware.cjs.map +1 -1
- package/dist/elysia/middleware.js +8 -10
- package/dist/elysia/middleware.js.map +1 -1
- package/dist/elysia/routes.cjs +2 -1
- package/dist/elysia/routes.cjs.map +1 -1
- package/dist/elysia/routes.js +2 -1
- package/dist/elysia/routes.js.map +1 -1
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js.map +1 -1
- package/dist/express/install.cjs +1 -0
- package/dist/express/install.cjs.map +1 -1
- package/dist/express/install.js +2 -1
- package/dist/express/install.js.map +1 -1
- package/dist/express/middleware.cjs +1 -1
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.js +1 -1
- package/dist/express/middleware.js.map +1 -1
- package/dist/fastify/middleware.cjs +1 -1
- package/dist/fastify/middleware.cjs.map +1 -1
- package/dist/fastify/middleware.js +1 -1
- package/dist/fastify/middleware.js.map +1 -1
- package/dist/h3/index.cjs +1 -0
- package/dist/h3/index.cjs.map +1 -1
- package/dist/h3/index.js +2 -1
- package/dist/h3/index.js.map +1 -1
- package/dist/h3/middleware.cjs +1 -1
- package/dist/h3/middleware.cjs.map +1 -1
- package/dist/h3/middleware.js +1 -1
- package/dist/h3/middleware.js.map +1 -1
- package/dist/hapi/middleware.cjs +1 -1
- package/dist/hapi/middleware.cjs.map +1 -1
- package/dist/hapi/middleware.js +1 -1
- package/dist/hapi/middleware.js.map +1 -1
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +2 -1
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.js +3 -2
- package/dist/hono/middleware.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/koa/index.cjs +1 -0
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.js +2 -1
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +1 -1
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.js +1 -1
- package/dist/koa/middleware.js.map +1 -1
- package/dist/metrics.cjs +0 -3
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.js +0 -3
- package/dist/metrics.js.map +1 -1
- package/dist/providers.cjs +10 -3
- package/dist/providers.cjs.map +1 -1
- package/dist/providers.js +10 -3
- package/dist/providers.js.map +1 -1
- package/dist/redaction.cjs +9 -5
- package/dist/redaction.cjs.map +1 -1
- package/dist/redaction.js +9 -5
- package/dist/redaction.js.map +1 -1
- package/dist/requestObservation.cjs +24 -18
- package/dist/requestObservation.cjs.map +1 -1
- package/dist/requestObservation.js +24 -18
- package/dist/requestObservation.js.map +1 -1
- package/dist/spanExporter.cjs +10 -7
- package/dist/spanExporter.cjs.map +1 -1
- package/dist/spanExporter.js +10 -7
- package/dist/spanExporter.js.map +1 -1
- package/dist/spanProcessor.cjs +9 -20
- package/dist/spanProcessor.cjs.map +1 -1
- package/dist/spanProcessor.d.cts +2 -1
- package/dist/spanProcessor.d.ts +2 -1
- package/dist/spanProcessor.js +8 -21
- package/dist/spanProcessor.js.map +1 -1
- package/dist/tracing.cjs +2 -1
- package/dist/tracing.cjs.map +1 -1
- package/dist/tracing.js +2 -1
- package/dist/tracing.js.map +1 -1
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ The SDK is an [OpenTelemetry](https://opentelemetry.io) distribution and works a
|
|
|
33
33
|
Learn more about Apitally on our 🌎 [website](https://apitally.io) or check out the 📚 [documentation](https://docs.apitally.io).
|
|
34
34
|
|
|
35
35
|
> [!IMPORTANT]
|
|
36
|
-
> **Upgrading from 0.x?** Version 1.0 is a full rewrite with a new setup API. See the [migration guide](MIGRATION.md) for
|
|
36
|
+
> **Upgrading from 0.x?** Version 1.0 is a full rewrite with a new setup API. See the [migration guide](MIGRATION.md) for how to upgrade.
|
|
37
37
|
|
|
38
38
|
## Key features
|
|
39
39
|
|
|
@@ -46,7 +46,7 @@ Learn more about Apitally on our 🌎 [website](https://apitally.io) or check ou
|
|
|
46
46
|
|
|
47
47
|
## Supported frameworks
|
|
48
48
|
|
|
49
|
-
The SDK supports **Node.js** `>=
|
|
49
|
+
The SDK supports **Node.js** `^20.16` or `>= 22.3` and **Bun** `>= 1.2.0`.
|
|
50
50
|
|
|
51
51
|
| Framework | Supported versions | Setup guide |
|
|
52
52
|
| --- | --- | --- |
|
|
@@ -62,51 +62,46 @@ The SDK supports **Node.js** `>= 20.6` and **Bun** `>= 1.2.0`.
|
|
|
62
62
|
|
|
63
63
|
\* For Hono on Cloudflare Workers use our [Serverless SDK](https://github.com/apitally/apitally-js-serverless) instead.
|
|
64
64
|
|
|
65
|
-
Apitally also supports many other web frameworks in [Python](https://github.com/apitally/apitally-py), [Go](https://github.com/apitally/apitally-go)
|
|
65
|
+
Apitally also supports many other web frameworks in [Python](https://github.com/apitally/apitally-py), [Go](https://github.com/apitally/apitally-go) and [.NET](https://github.com/apitally/apitally-dotnet) via our other SDKs.
|
|
66
66
|
|
|
67
67
|
## Getting started
|
|
68
68
|
|
|
69
69
|
If you don't have an Apitally account yet, first [sign up here](https://app.apitally.io/?signup). Then create an app in the Apitally dashboard. You'll see detailed setup instructions with code snippets you can copy and paste. These also include your write token.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
Install the SDK in your project:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
npm install apitally
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
See the [SDK reference](https://docs.apitally.io/sdk-reference/javascript/v1/configuration) for all available configuration options, including how to mask sensitive data, capture request and response payloads, and more.
|
|
78
|
-
|
|
79
77
|
### AdonisJS
|
|
80
78
|
|
|
81
|
-
Run the Ace add command from your application directory:
|
|
79
|
+
Run the Ace `add` command from your application directory:
|
|
82
80
|
|
|
83
81
|
```bash
|
|
84
82
|
node ace add apitally
|
|
85
83
|
```
|
|
86
84
|
|
|
87
|
-
The command installs
|
|
88
|
-
|
|
89
|
-
If needed, you can change settings in `config/apitally.ts`.
|
|
85
|
+
The command installs Apitally, asks for your write token and environment, and sets up the provider, middleware, and exception handling. To change settings later, edit `config/apitally.ts`.
|
|
90
86
|
|
|
91
87
|
For further instructions, see our [setup guide for AdonisJS](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/adonisjs).
|
|
92
88
|
|
|
93
89
|
### Elysia
|
|
94
90
|
|
|
95
|
-
Register `apitallyPlugin()` immediately after creating the app, before
|
|
91
|
+
Register `apitallyPlugin()` immediately after creating the app, before registering plugins and routes:
|
|
96
92
|
|
|
97
93
|
```javascript
|
|
98
94
|
import { Elysia } from "elysia";
|
|
99
95
|
import { apitallyPlugin } from "apitally/elysia";
|
|
100
96
|
|
|
101
|
-
const app = new Elysia()
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
.get("/items/:id", ({ params }) => ({ id: params.id }));
|
|
97
|
+
const app = new Elysia().use(
|
|
98
|
+
apitallyPlugin({
|
|
99
|
+
writeToken: "your-write-token",
|
|
100
|
+
env: "dev",
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// register plugins and routes below this point
|
|
110
105
|
```
|
|
111
106
|
|
|
112
107
|
For further instructions, see our [setup guide for Elysia](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/elysia).
|
|
@@ -124,8 +119,8 @@ import { useApitally } from "apitally";
|
|
|
124
119
|
const app = express();
|
|
125
120
|
|
|
126
121
|
useApitally(app, {
|
|
127
|
-
writeToken: "your-write-token",
|
|
128
|
-
env: "dev",
|
|
122
|
+
writeToken: "your-write-token",
|
|
123
|
+
env: "dev",
|
|
129
124
|
});
|
|
130
125
|
```
|
|
131
126
|
|
|
@@ -142,8 +137,8 @@ import { useApitally } from "apitally";
|
|
|
142
137
|
const app = Fastify();
|
|
143
138
|
|
|
144
139
|
useApitally(app, {
|
|
145
|
-
writeToken: "your-write-token",
|
|
146
|
-
env: "dev",
|
|
140
|
+
writeToken: "your-write-token",
|
|
141
|
+
env: "dev",
|
|
147
142
|
});
|
|
148
143
|
|
|
149
144
|
// register plugins and routes below this point
|
|
@@ -151,30 +146,9 @@ useApitally(app, {
|
|
|
151
146
|
|
|
152
147
|
For further instructions, see our [setup guide for Fastify](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/fastify).
|
|
153
148
|
|
|
154
|
-
### NestJS
|
|
155
|
-
|
|
156
|
-
Call `useApitally(app)` immediately after creating the Nest application, before `app.init()` or `app.listen()`:
|
|
157
|
-
|
|
158
|
-
```javascript
|
|
159
|
-
import { NestFactory } from "@nestjs/core";
|
|
160
|
-
import { useApitally } from "apitally/nestjs";
|
|
161
|
-
import { AppModule } from "./app.module.js";
|
|
162
|
-
|
|
163
|
-
const app = await NestFactory.create(AppModule);
|
|
164
|
-
|
|
165
|
-
useApitally(app, {
|
|
166
|
-
writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
|
|
167
|
-
env: "dev", // or "prod" etc.
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
await app.listen(3000);
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
For further instructions, see our [setup guide for NestJS](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/nestjs).
|
|
174
|
-
|
|
175
149
|
### H3
|
|
176
150
|
|
|
177
|
-
Add `apitallyPlugin()`
|
|
151
|
+
Add `apitallyPlugin()` to the `plugins` of your root H3 app:
|
|
178
152
|
|
|
179
153
|
```javascript
|
|
180
154
|
import { H3 } from "h3";
|
|
@@ -183,8 +157,8 @@ import { apitallyPlugin } from "apitally/h3";
|
|
|
183
157
|
const app = new H3({
|
|
184
158
|
plugins: [
|
|
185
159
|
apitallyPlugin({
|
|
186
|
-
writeToken: "your-write-token",
|
|
187
|
-
env: "dev",
|
|
160
|
+
writeToken: "your-write-token",
|
|
161
|
+
env: "dev",
|
|
188
162
|
}),
|
|
189
163
|
],
|
|
190
164
|
});
|
|
@@ -194,7 +168,7 @@ For further instructions, see our [setup guide for H3](https://docs.apitally.io/
|
|
|
194
168
|
|
|
195
169
|
### Hapi
|
|
196
170
|
|
|
197
|
-
Register `apitallyPlugin()`
|
|
171
|
+
Register `apitallyPlugin()` immediately after creating the server, before registering other plugins and routes:
|
|
198
172
|
|
|
199
173
|
```javascript
|
|
200
174
|
import Hapi from "@hapi/hapi";
|
|
@@ -204,12 +178,12 @@ const server = Hapi.server({ port: 3000 });
|
|
|
204
178
|
|
|
205
179
|
await server.register(
|
|
206
180
|
apitallyPlugin({
|
|
207
|
-
writeToken: "your-write-token",
|
|
208
|
-
env: "dev",
|
|
181
|
+
writeToken: "your-write-token",
|
|
182
|
+
env: "dev",
|
|
209
183
|
}),
|
|
210
184
|
);
|
|
211
185
|
|
|
212
|
-
// register
|
|
186
|
+
// register other plugins and routes below this point
|
|
213
187
|
await server.start();
|
|
214
188
|
```
|
|
215
189
|
|
|
@@ -226,8 +200,8 @@ import { useApitally } from "apitally";
|
|
|
226
200
|
const app = new Hono();
|
|
227
201
|
|
|
228
202
|
useApitally(app, {
|
|
229
|
-
writeToken: "your-write-token",
|
|
230
|
-
env: "dev",
|
|
203
|
+
writeToken: "your-write-token",
|
|
204
|
+
env: "dev",
|
|
231
205
|
});
|
|
232
206
|
|
|
233
207
|
// register middleware and routes below this point
|
|
@@ -240,14 +214,14 @@ For further instructions, see our [setup guide for Hono](https://docs.apitally.i
|
|
|
240
214
|
Call `useApitally(app)` immediately after creating the app, before registering middleware and routes:
|
|
241
215
|
|
|
242
216
|
```javascript
|
|
243
|
-
|
|
244
|
-
|
|
217
|
+
import Koa from "koa";
|
|
218
|
+
import { useApitally } from "apitally";
|
|
245
219
|
|
|
246
220
|
const app = new Koa();
|
|
247
221
|
|
|
248
222
|
useApitally(app, {
|
|
249
|
-
writeToken: "your-write-token",
|
|
250
|
-
env: "dev",
|
|
223
|
+
writeToken: "your-write-token",
|
|
224
|
+
env: "dev",
|
|
251
225
|
});
|
|
252
226
|
|
|
253
227
|
// register middleware and routes below this point
|
|
@@ -255,11 +229,42 @@ useApitally(app, {
|
|
|
255
229
|
|
|
256
230
|
For further instructions, see our [setup guide for Koa](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/koa).
|
|
257
231
|
|
|
232
|
+
### NestJS
|
|
233
|
+
|
|
234
|
+
Call `useApitally(app)` immediately after creating the app, before calling `app.init()` or `app.listen()`:
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
import { NestFactory } from "@nestjs/core";
|
|
238
|
+
import { useApitally } from "apitally/nestjs";
|
|
239
|
+
import { AppModule } from "./app.module.js";
|
|
240
|
+
|
|
241
|
+
const app = await NestFactory.create(AppModule);
|
|
242
|
+
|
|
243
|
+
useApitally(app, {
|
|
244
|
+
writeToken: "your-write-token",
|
|
245
|
+
env: "dev",
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
await app.listen(3000);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
For further instructions, see our [setup guide for NestJS](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/nestjs).
|
|
252
|
+
|
|
258
253
|
## Configuration
|
|
259
254
|
|
|
260
|
-
|
|
255
|
+
Pass configuration options to `useApitally()`, or to `apitallyPlugin()` for Elysia, H3, and Hapi. For AdonisJS, set them in `config/apitally.ts`. See the [SDK reference](https://docs.apitally.io/sdk-reference/javascript/v1/configuration) for all available options.
|
|
256
|
+
|
|
257
|
+
### Environment variables
|
|
258
|
+
|
|
259
|
+
To keep configuration out of your code, set these environment variables instead of passing the matching options:
|
|
260
|
+
|
|
261
|
+
- `APITALLY_WRITE_TOKEN`: the write token (`writeToken`)
|
|
262
|
+
- `APITALLY_ENV`: the environment name (`env`), defaults to `dev`
|
|
263
|
+
- `APITALLY_DISABLED`: set to `true` to disable Apitally (`disabled`)
|
|
261
264
|
|
|
262
|
-
|
|
265
|
+
### Request and response data
|
|
266
|
+
|
|
267
|
+
Apitally captures response headers by default. To also capture request headers and request and response bodies, pass these options:
|
|
263
268
|
|
|
264
269
|
```javascript
|
|
265
270
|
useApitally(app, {
|
|
@@ -271,45 +276,78 @@ useApitally(app, {
|
|
|
271
276
|
});
|
|
272
277
|
```
|
|
273
278
|
|
|
274
|
-
|
|
279
|
+
Apitally automatically masks common sensitive values, such as `password` fields and the `Authorization` header. To mask additional values, pass regular expressions to `maskQueryParams`, `maskHeaders`, and `maskBodyFields`. See our [documentation on masking](https://docs.apitally.io/sdk-reference/javascript/v1/masking) for details.
|
|
280
|
+
|
|
281
|
+
### Exclusions and sampling
|
|
282
|
+
|
|
283
|
+
Apitally automatically excludes common health checks and static assets, such as `/healthz` and `/robots.txt`, from logs and traces. To exclude additional paths, pass regular expressions to `excludePaths`.
|
|
284
|
+
|
|
285
|
+
To capture logs and traces for only a fraction of the remaining requests, set `sampleRate`, for example to `0.1` for 10%. To decide for each request individually, pass a callback to `sampleOnRequest` or `sampleOnResponse`.
|
|
286
|
+
|
|
287
|
+
Metrics always include all requests. See our [documentation on sampling](https://docs.apitally.io/sdk-reference/javascript/v1/sampling) for details.
|
|
288
|
+
|
|
289
|
+
### Application logs
|
|
275
290
|
|
|
276
|
-
|
|
291
|
+
Apitally captures logs written with these loggers and correlates them with the requests they belong to:
|
|
277
292
|
|
|
278
|
-
|
|
293
|
+
- `console`
|
|
294
|
+
- Pino
|
|
295
|
+
- Winston
|
|
296
|
+
- NestJS `Logger`
|
|
297
|
+
- Hapi `request.log()`
|
|
279
298
|
|
|
280
|
-
|
|
299
|
+
To mask or drop individual log records, pass a callback to `maskLogRecord`. To turn off log capture, set `captureLogs: false`.
|
|
281
300
|
|
|
282
|
-
|
|
301
|
+
See our [documentation on masking](https://docs.apitally.io/sdk-reference/javascript/v1/masking#log-record-masking-callback) for details.
|
|
283
302
|
|
|
284
|
-
|
|
303
|
+
## Adding context to requests
|
|
304
|
+
|
|
305
|
+
The following functions add context to the current request. Call them while handling a request, for example in a route handler, middleware, or authentication code.
|
|
306
|
+
|
|
307
|
+
### Consumers
|
|
308
|
+
|
|
309
|
+
To associate the request with the API consumer making it, call `setConsumer`. Only `identifier` is required. You can also pass it as a string, for example `setConsumer(user.identifier)`.
|
|
285
310
|
|
|
286
311
|
```javascript
|
|
287
|
-
import { setConsumer
|
|
312
|
+
import { setConsumer } from "apitally";
|
|
288
313
|
|
|
289
|
-
// Associate the current request with an API consumer, with custom attributes
|
|
290
314
|
setConsumer({
|
|
291
315
|
identifier: user.identifier,
|
|
292
316
|
name: user.name,
|
|
293
317
|
group: user.group,
|
|
294
318
|
attributes: { plan: user.plan },
|
|
295
319
|
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Custom attributes
|
|
296
323
|
|
|
297
|
-
|
|
298
|
-
setRequestAttribute("tenant", tenantId);
|
|
324
|
+
To attach custom data to the request's trace, call `setRequestAttribute`. The `sampleOnResponse`, `maskRequestBody`, and `maskResponseBody` callbacks can also read these attributes.
|
|
299
325
|
|
|
300
|
-
|
|
301
|
-
|
|
326
|
+
```javascript
|
|
327
|
+
import { setRequestAttribute } from "apitally";
|
|
328
|
+
|
|
329
|
+
setRequestAttribute("tenant.id", tenantId);
|
|
302
330
|
```
|
|
303
331
|
|
|
304
|
-
|
|
332
|
+
See our [documentation on attributes](https://docs.apitally.io/sdk-reference/javascript/v1/attributes#set-custom-attributes) for details.
|
|
305
333
|
|
|
306
|
-
|
|
334
|
+
### Handled exceptions
|
|
307
335
|
|
|
308
|
-
|
|
336
|
+
To capture an exception that your code handles itself, call `captureException`. Unhandled exceptions are captured automatically.
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
import { captureException } from "apitally";
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
processOrder();
|
|
343
|
+
} catch (error) {
|
|
344
|
+
captureException(error);
|
|
345
|
+
}
|
|
346
|
+
```
|
|
309
347
|
|
|
310
|
-
|
|
348
|
+
## Existing OpenTelemetry setup
|
|
311
349
|
|
|
312
|
-
If your app already registers its own tracer provider
|
|
350
|
+
If your app already registers its own tracer provider, for example with `NodeSDK`, add `ApitallySpanProcessor` to its span processors. Apitally then uses your tracer provider instead of registering its own, and keeps your existing exporters.
|
|
313
351
|
|
|
314
352
|
```javascript
|
|
315
353
|
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
@@ -321,40 +359,29 @@ const sdk = new NodeSDK({
|
|
|
321
359
|
});
|
|
322
360
|
```
|
|
323
361
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
### Elysia's OpenTelemetry plugin
|
|
362
|
+
If you use version 10.x of the Sentry SDK, which registers its own tracer provider, add `ApitallySpanProcessor` to the `openTelemetrySpanProcessors` option in `Sentry.init()` and enable Sentry tracing.
|
|
327
363
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
```javascript
|
|
331
|
-
import { opentelemetry } from "@elysia/opentelemetry";
|
|
332
|
-
import { Elysia } from "elysia";
|
|
333
|
-
import { apitallyPlugin } from "apitally/elysia";
|
|
334
|
-
|
|
335
|
-
const app = new Elysia()
|
|
336
|
-
.use(apitallyPlugin(options))
|
|
337
|
-
.use(opentelemetry());
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
## Trusted proxies
|
|
341
|
-
|
|
342
|
-
If your application runs behind a reverse proxy or load balancer, configure trusted proxies in your framework so Apitally can record the real client IP for GeoIP. Apitally uses the client IP reported by your framework. It does not read forwarding headers itself to determine the client IP.
|
|
364
|
+
Your tracer provider's sampler also applies to Apitally. Requests it drops have no request logs or traces in Apitally, but still count in metrics.
|
|
343
365
|
|
|
344
366
|
## Graceful shutdown
|
|
345
367
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
If your code calls `process.exit()`, await `shutdown()` first to give Apitally time to send buffered telemetry. Close your server and let any remaining requests finish before doing this:
|
|
368
|
+
If your code calls `process.exit()`, await `shutdown()` before it so Apitally can send any remaining telemetry:
|
|
349
369
|
|
|
350
370
|
```javascript
|
|
351
371
|
import { shutdown } from "apitally";
|
|
352
372
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
373
|
+
process.on("SIGTERM", () => {
|
|
374
|
+
server.close(async () => {
|
|
375
|
+
await shutdown();
|
|
376
|
+
process.exit(0);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
356
379
|
```
|
|
357
380
|
|
|
381
|
+
## Trusted proxies
|
|
382
|
+
|
|
383
|
+
If your app runs behind a reverse proxy or load balancer, configure trusted proxies in your framework, for example with Express's `trust proxy` setting or Fastify's `trustProxy` option. Apitally records the client IP your framework reports and uses it for GeoIP.
|
|
384
|
+
|
|
358
385
|
## Getting help
|
|
359
386
|
|
|
360
387
|
If you need help please [create a new discussion](https://github.com/orgs/apitally/discussions/categories/q-a) on GitHub or email us at [support@apitally.io](mailto:support@apitally.io). We'll get back to you as soon as possible.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.__toESM = __toESM;
|
package/dist/activation.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
2
3
|
const require_logger = require("./logger.cjs");
|
|
3
4
|
const require_config = require("./config.cjs");
|
|
4
5
|
const require_packageVersion = require("./packageVersion.cjs");
|
|
@@ -7,15 +8,17 @@ const require_logCapture = require("./logCapture.cjs");
|
|
|
7
8
|
const require_logRecordExporter = require("./logRecordExporter.cjs");
|
|
8
9
|
const require_logRecordProcessor = require("./logRecordProcessor.cjs");
|
|
9
10
|
const require_metrics = require("./metrics.cjs");
|
|
11
|
+
const require_spanProcessor = require("./spanProcessor.cjs");
|
|
10
12
|
const require_providers = require("./providers.cjs");
|
|
11
13
|
const require_redaction = require("./redaction.cjs");
|
|
12
14
|
const require_sentry = require("./sentry.cjs");
|
|
13
15
|
const require_serverErrors = require("./serverErrors.cjs");
|
|
14
|
-
const require_spanProcessor = require("./spanProcessor.cjs");
|
|
15
16
|
const require_spanExporter = require("./spanExporter.cjs");
|
|
16
17
|
const require_spool = require("./spool.cjs");
|
|
17
18
|
const require_startup = require("./startup.cjs");
|
|
18
19
|
const require_validationErrors = require("./validationErrors.cjs");
|
|
20
|
+
let node_diagnostics_channel = require("node:diagnostics_channel");
|
|
21
|
+
node_diagnostics_channel = require_runtime.__toESM(node_diagnostics_channel, 1);
|
|
19
22
|
let node_worker_threads = require("node:worker_threads");
|
|
20
23
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
21
24
|
let _opentelemetry_instrumentation_undici = require("@opentelemetry/instrumentation-undici");
|
|
@@ -28,6 +31,7 @@ const BATCH_MAX_QUEUE_SIZE = 2048;
|
|
|
28
31
|
const BATCH_MAX_EXPORT_BATCH_SIZE = 512;
|
|
29
32
|
const BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;
|
|
30
33
|
const SIGNAL_FLUSH_TIMEOUT_MILLIS = 5e3;
|
|
34
|
+
const NET_SERVER_LISTEN_CHANNEL = "tracing:net.server.listen:asyncEnd";
|
|
31
35
|
const ACTIVATION_STATE_KEY = Symbol.for("apitally.activation");
|
|
32
36
|
function configure(options = {}) {
|
|
33
37
|
const config = require_config.setConfig(options);
|
|
@@ -54,6 +58,25 @@ function activate() {
|
|
|
54
58
|
require_logger.logError(`Apitally activation failed: ${String(error)}`);
|
|
55
59
|
}
|
|
56
60
|
}
|
|
61
|
+
function activateWhenHttpServerListens() {
|
|
62
|
+
const activationState = getActivationState();
|
|
63
|
+
if (activationState.httpServerListenHooks) return;
|
|
64
|
+
const onNetServerListen = (message) => {
|
|
65
|
+
if (message.server.listenerCount("request") > 0) activate();
|
|
66
|
+
};
|
|
67
|
+
node_diagnostics_channel.default.subscribe(NET_SERVER_LISTEN_CHANNEL, onNetServerListen);
|
|
68
|
+
const bun = globalThis.Bun;
|
|
69
|
+
const originalBunServe = bun?.serve;
|
|
70
|
+
if (bun && originalBunServe) bun.serve = function(...args) {
|
|
71
|
+
const server = originalBunServe.apply(this, args);
|
|
72
|
+
activate();
|
|
73
|
+
return server;
|
|
74
|
+
};
|
|
75
|
+
activationState.httpServerListenHooks = {
|
|
76
|
+
onNetServerListen,
|
|
77
|
+
originalBunServe
|
|
78
|
+
};
|
|
79
|
+
}
|
|
57
80
|
function isActivated() {
|
|
58
81
|
return getActivationState().handles !== void 0;
|
|
59
82
|
}
|
|
@@ -94,6 +117,12 @@ async function resetActivation() {
|
|
|
94
117
|
require_serverErrors.resetServerErrors();
|
|
95
118
|
if (!activationState) return;
|
|
96
119
|
removeLifecycleHooks(activationState);
|
|
120
|
+
const listenHooks = activationState.httpServerListenHooks;
|
|
121
|
+
if (listenHooks) {
|
|
122
|
+
node_diagnostics_channel.default.unsubscribe(NET_SERVER_LISTEN_CHANNEL, listenHooks.onNetServerListen);
|
|
123
|
+
const bun = globalThis.Bun;
|
|
124
|
+
if (bun && listenHooks.originalBunServe) bun.serve = listenHooks.originalBunServe;
|
|
125
|
+
}
|
|
97
126
|
const handles = activationState.handles;
|
|
98
127
|
if (!handles) return;
|
|
99
128
|
handles.undiciInstrumentation?.disable();
|
|
@@ -300,6 +329,7 @@ function installBeforeExitHook(activationState) {
|
|
|
300
329
|
}
|
|
301
330
|
//#endregion
|
|
302
331
|
exports.activate = activate;
|
|
332
|
+
exports.activateWhenHttpServerListens = activateWhenHttpServerListens;
|
|
303
333
|
exports.activationFactories = activationFactories;
|
|
304
334
|
exports.configure = configure;
|
|
305
335
|
exports.flushTelemetry = flushTelemetry;
|
package/dist/activation.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activation.cjs","names":["setConfig","Spool","ExportWorker","VALIDATION_ERROR_EVENT_NAME","drainValidationErrors","SERVER_ERROR_EVENT_NAME","drainServerErrors","ROOT_CONTEXT","getDistroVersion","getConfig","isApitallySpanProcessorDeclared","resolveEnvAndCreateResource","ApitallySpanExporter","Redaction","BatchSpanProcessor","SpanPipeline","setupTracerProvider","BatchLogRecordProcessor","ApitallyLogRecordExporter","ApitallyLogRecordProcessor","createLoggerProvider","MetricsPipeline","UndiciInstrumentation","isMainThread"],"sources":["../src/activation.ts"],"sourcesContent":["import { isMainThread } from \"node:worker_threads\";\nimport { ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { type ApitallyConfig, type ApitallyOptions, getConfig, setConfig } from \"./config.js\";\nimport { ExportWorker, type ExportWorkerOptions } from \"./exportWorker.js\";\nimport {\n installConsoleCapture,\n installNestLoggerCapture,\n installPinoCapture,\n installWinstonCapture,\n} from \"./logCapture.js\";\nimport { logDebug, logError, logWarning } from \"./logger.js\";\nimport { ApitallyLogRecordExporter } from \"./logRecordExporter.js\";\nimport { ApitallyLogRecordProcessor } from \"./logRecordProcessor.js\";\nimport { MetricsPipeline } from \"./metrics.js\";\nimport { getDistroVersion } from \"./packageVersion.js\";\nimport {\n createLoggerProvider,\n resolveEnvAndCreateResource,\n setupTracerProvider,\n} from \"./providers.js\";\nimport { Redaction } from \"./redaction.js\";\nimport { installSentryEventIdRecording } from \"./sentry.js\";\nimport { drainServerErrors, resetServerErrors, SERVER_ERROR_EVENT_NAME } from \"./serverErrors.js\";\nimport { ApitallySpanExporter } from \"./spanExporter.js\";\nimport {\n isApitallySpanProcessorDeclared,\n SpanPipeline,\n setActiveSpanPipeline,\n setServerSpanActivationCallback,\n} from \"./spanProcessor.js\";\nimport { Spool } from \"./spool.js\";\nimport { emitStartupEvent, type StartupEventInfo } from \"./startup.js\";\nimport {\n drainValidationErrors,\n resetValidationErrors,\n VALIDATION_ERROR_EVENT_NAME,\n} from \"./validationErrors.js\";\n\n// The worker sends every 15 seconds, so batches only need to reach the spool\n// within that interval.\nconst BATCH_SCHEDULE_DELAY_MILLIS = 1_000;\nconst BATCH_EXPORT_TIMEOUT_MILLIS = 30_000;\nconst BATCH_MAX_QUEUE_SIZE = 2_048;\nconst BATCH_MAX_EXPORT_BATCH_SIZE = 512;\nconst BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;\nconst SIGNAL_FLUSH_TIMEOUT_MILLIS = 5_000;\n\ntype TerminationSignal = \"SIGTERM\" | \"SIGINT\";\ntype SignalListeners = Record<TerminationSignal, () => void>;\n\n// The ESM and CJS builds can load together, so a Symbol.for key gives both\n// copies the same activation state.\nconst ACTIVATION_STATE_KEY = Symbol.for(\"apitally.activation\");\n\ninterface ActivationState {\n sdkVersion: string;\n activationAttempted: boolean;\n startupEventInfo?: StartupEventInfo;\n handles?: ActivationHandles;\n runShutdown?: () => Promise<void>;\n shutdownPromise?: Promise<void>;\n beforeExitListener?: () => void;\n signalListeners?: SignalListeners;\n signalDrainPromise?: Promise<void>;\n}\n\ninterface ActivationHandles {\n spanPipeline: SpanPipeline;\n tracerProvider?: NodeTracerProvider;\n loggerProvider: LoggerProvider;\n // Consumer identifier to the hash of its last emitted consumer update, in LRU order.\n consumerUpdateHashes: Map<string, string>;\n metricsPipeline: MetricsPipeline;\n spool: Spool;\n worker: ExportWorker;\n undiciInstrumentation?: UndiciInstrumentation;\n}\n\n// Configuration stays synchronous; activate() defers timers and I/O.\nexport function configure(options: ApitallyOptions = {}): ApitallyConfig {\n const config = setConfig(options);\n // User instrumentations read this at initialization. `http/dup` adds stable\n // HTTP attributes alongside legacy ones; a user-set value takes precedence.\n if (!config.disabled && process.env.OTEL_SEMCONV_STABILITY_OPT_IN === undefined) {\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN = \"http/dup\";\n }\n setServerSpanActivationCallback(activate);\n return config;\n}\n\n// The first integration registration wins so one process emits one startup event.\nexport function registerStartupEventInfo(info: StartupEventInfo): void {\n const activationState = getActivationState();\n activationState.startupEventInfo ??= info;\n}\n\n// Activation is synchronous and attempted once, so concurrent first requests\n// observe either no activation or completed activation.\nexport function activate(): void {\n const activationState = getActivationState();\n if (activationState.activationAttempted) {\n return;\n }\n activationState.activationAttempted = true;\n if (shouldSkipActivation()) {\n return;\n }\n try {\n const handles = startPipelines(activationState.startupEventInfo);\n activationState.handles = handles;\n activationState.runShutdown = () => drainAndStop(handles);\n installBeforeExitHook(activationState);\n installSignalHooks(activationState);\n } catch (error) {\n logError(`Apitally activation failed: ${String(error)}`);\n }\n}\n\nexport function isActivated(): boolean {\n return getActivationState().handles !== undefined;\n}\n\nexport function getActivationHandles(): ActivationHandles | undefined {\n return getActivationState().handles;\n}\n\nexport async function flushTelemetry(): Promise<void> {\n try {\n await getActivationState().handles?.worker.runCycle();\n } catch (error) {\n logDebug(`Error flushing telemetry: ${String(error)}`);\n }\n}\n\n// Concurrent calls and lifecycle hooks share one final drain; calls before\n// activation are no-ops.\nexport function shutdown(): Promise<void> {\n const activationState = getActivationState();\n const handles = activationState.handles;\n const runShutdown = activationState.runShutdown;\n if (!handles || !runShutdown) {\n return Promise.resolve();\n }\n if (!activationState.shutdownPromise) {\n removeLifecycleHooks(activationState);\n const signalDrainPromise = activationState.signalDrainPromise;\n activationState.shutdownPromise = (\n signalDrainPromise\n ? signalDrainPromise.then(() => handles.worker.waitForIdle())\n : Promise.resolve()\n ).then(runShutdown);\n }\n return activationState.shutdownPromise;\n}\n\n// Tests replace these factories to isolate spool files and worker timing.\nexport const activationFactories = {\n createSpool: (): Spool => new Spool(),\n createExportWorker: (options: ExportWorkerOptions): ExportWorker => new ExportWorker(options),\n};\nconst defaultFactories = { ...activationFactories };\n\n// Tests reset process-global activation and its side effects between cases.\nexport async function resetActivation(): Promise<void> {\n Object.assign(activationFactories, defaultFactories);\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const activationState = holder[ACTIVATION_STATE_KEY];\n delete holder[ACTIVATION_STATE_KEY];\n hasWarnedAboutVersionSkew = false;\n resetValidationErrors();\n resetServerErrors();\n if (!activationState) {\n return;\n }\n removeLifecycleHooks(activationState);\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n handles.undiciInstrumentation?.disable();\n await handles.worker.stop();\n await handles.spanPipeline.shutdown();\n await handles.loggerProvider.shutdown();\n await handles.spool.clear();\n}\n\nlet hasWarnedAboutVersionSkew = false;\n\n// One root-context record per aggregated error, drained right before the log\n// processor flush so the records leave with the same export cycle.\nfunction emitErrorEvents(loggerProvider: LoggerProvider): void {\n const logger = loggerProvider.getLogger(\"apitally\");\n const events: [string, AnyValueMap[]][] = [\n [VALIDATION_ERROR_EVENT_NAME, drainValidationErrors()],\n [SERVER_ERROR_EVENT_NAME, drainServerErrors()],\n ];\n for (const [eventName, bodies] of events) {\n for (const body of bodies) {\n logger.emit({ timestamp: Date.now(), context: ROOT_CONTEXT, eventName, body });\n }\n }\n}\n\nfunction getActivationState(): ActivationState {\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const existing = holder[ACTIVATION_STATE_KEY];\n if (existing) {\n if (!hasWarnedAboutVersionSkew && existing.sdkVersion !== getDistroVersion()) {\n hasWarnedAboutVersionSkew = true;\n logWarning(\n `Two copies of the apitally package with different versions (${existing.sdkVersion} and ${getDistroVersion()}) are loaded in this process; version ${existing.sdkVersion} stays active. To resolve this, deduplicate the apitally installation.`,\n );\n }\n return existing;\n }\n const activationState: ActivationState = {\n sdkVersion: getDistroVersion(),\n activationAttempted: false,\n };\n holder[ACTIVATION_STATE_KEY] = activationState;\n return activationState;\n}\n\nfunction shouldSkipActivation(): boolean {\n return (\n Boolean(process.env.JEST_WORKER_ID) ||\n Boolean(process.env.VITEST) ||\n process.env.NODE_ENV === \"test\" ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(startupEventInfo: StartupEventInfo | undefined): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource();\n const instanceId = resource.attributes[\"service.instance.id\"] as string;\n const spool = activationFactories.createSpool();\n const spanExporter = new ApitallySpanExporter({\n redaction: new Redaction(),\n env,\n instanceId,\n spool,\n maskRequestBody: config.maskRequestBody,\n maskResponseBody: config.maskResponseBody,\n });\n // Concrete options prevent OTel environment variables from changing batch\n // behavior. Each processor gets a fresh object because its config is mutated.\n const batchSpanProcessor = new BatchSpanProcessor(spanExporter, {\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize:\n config.captureRequestBody || config.captureResponseBody\n ? BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE\n : BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const spanPipeline = new SpanPipeline(batchSpanProcessor, () => spanExporter.forceFlush());\n let tracerProvider: NodeTracerProvider | undefined;\n if (!hasUserProvider) {\n tracerProvider = setupTracerProvider(resource, [spanPipeline]);\n if (!tracerProvider) {\n hasUserProvider = true;\n logWarning(\n \"Apitally could not register its OpenTelemetry tracer provider because another provider is already registered. Only metrics and the startup event are sent to Apitally until you add ApitallySpanProcessor (exported by the apitally package) to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n }\n }\n setActiveSpanPipeline(spanPipeline);\n // BatchLogRecordProcessor requires its single-options-object form; positional\n // arguments create a broken processor.\n const batchLogProcessor = new BatchLogRecordProcessor({\n exporter: new ApitallyLogRecordExporter(spool),\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const logRecordProcessor = new ApitallyLogRecordProcessor(\n batchLogProcessor,\n spanPipeline,\n config.maskLogRecord,\n );\n const loggerProvider = createLoggerProvider(resource, [logRecordProcessor]);\n const metricsPipeline = new MetricsPipeline(resource, spool);\n spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);\n const worker = activationFactories.createExportWorker({\n spool,\n otlpEndpoint: config.otlpEndpoint,\n writeToken: config.writeToken,\n env,\n });\n worker.flushCallbacks.push(\n () => metricsPipeline.collectAndExport(),\n () => spanPipeline.forceFlush(),\n () => emitErrorEvents(loggerProvider),\n () => batchLogProcessor.forceFlush(),\n );\n if (config.captureLogs) {\n installConsoleCapture(loggerProvider);\n installNestLoggerCapture(loggerProvider);\n installWinstonCapture(loggerProvider);\n installPinoCapture(loggerProvider);\n }\n installSentryEventIdRecording();\n let undiciInstrumentation: UndiciInstrumentation | undefined;\n if (!hasUserProvider) {\n undiciInstrumentation = createUndiciInstrumentation(config.otlpEndpoint);\n }\n worker.start();\n if (startupEventInfo) {\n emitStartupEvent(loggerProvider, startupEventInfo);\n }\n return {\n spanPipeline,\n tracerProvider,\n loggerProvider,\n consumerUpdateHashes: new Map(),\n metricsPipeline,\n spool,\n worker,\n undiciInstrumentation,\n };\n}\n\n// ignoreRequestHook prevents telemetry for export POSTs. The request origin can\n// be a string or URL at runtime despite its string type.\nfunction createUndiciInstrumentation(otlpEndpoint: string): UndiciInstrumentation {\n const endpointOrigin = new URL(otlpEndpoint).origin;\n return new UndiciInstrumentation({\n ignoreRequestHook: (request) => {\n try {\n return new URL(String(request.origin)).origin === endpointOrigin;\n } catch {\n return false;\n }\n },\n });\n}\n\nasync function drainAndStop(handles: ActivationHandles): Promise<void> {\n try {\n await handles.spanPipeline.shutdown();\n await handles.worker.finalDrain();\n await handles.loggerProvider.shutdown();\n await handles.worker.stop();\n } catch (error) {\n logWarning(`Error draining telemetry on shutdown: ${String(error)}`);\n }\n}\n\nfunction installSignalHooks(activationState: ActivationState): void {\n if (process.platform === \"win32\" || !isMainThread) {\n return;\n }\n let listeners: SignalListeners;\n listeners = {\n SIGTERM: () => handleTerminationSignal(activationState, listeners, \"SIGTERM\"),\n SIGINT: () => handleTerminationSignal(activationState, listeners, \"SIGINT\"),\n };\n activationState.signalListeners = listeners;\n try {\n process.prependOnceListener(\"SIGTERM\", listeners.SIGTERM);\n process.prependOnceListener(\"SIGINT\", listeners.SIGINT);\n } catch (error) {\n removeSignalHooks(activationState, listeners);\n logWarning(`Unable to install Apitally signal handlers: ${String(error)}`);\n }\n}\n\nfunction handleTerminationSignal(\n activationState: ActivationState,\n listeners: SignalListeners,\n signal: TerminationSignal,\n): void {\n const hasApplicationListener = process\n .listeners(signal)\n .some((listener) => listener !== listeners[signal]);\n removeSignalHooks(activationState, listeners);\n const drainPromise = flushAfterTerminationSignal(activationState, signal, hasApplicationListener);\n activationState.signalDrainPromise = drainPromise;\n void drainPromise.catch((error: unknown) => {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n });\n}\n\nasync function flushAfterTerminationSignal(\n activationState: ActivationState,\n signal: TerminationSignal,\n hasApplicationListener: boolean,\n): Promise<void> {\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n try {\n if (activationState.shutdownPromise) {\n await waitForSignalDeadline(activationState.shutdownPromise);\n } else {\n await handles.worker.finalDrain(SIGNAL_FLUSH_TIMEOUT_MILLIS);\n }\n } catch (error) {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n }\n if (hasApplicationListener || process.listeners(signal).length > 0) {\n return;\n }\n const exitCode = signal === \"SIGTERM\" ? 143 : 130;\n if (process.platform === \"linux\" && process.pid === 1) {\n process.exit(exitCode);\n }\n try {\n process.kill(process.pid, signal);\n } catch {\n process.exit(exitCode);\n }\n}\n\nasync function waitForSignalDeadline(promise: Promise<void>): Promise<void> {\n let deadlineTimer: NodeJS.Timeout | undefined;\n const deadlineReached = new Promise<void>((resolve) => {\n deadlineTimer = setTimeout(resolve, SIGNAL_FLUSH_TIMEOUT_MILLIS);\n });\n try {\n await Promise.race([promise, deadlineReached]);\n } finally {\n if (deadlineTimer) {\n clearTimeout(deadlineTimer);\n }\n }\n}\n\nfunction removeSignalHooks(\n activationState: ActivationState,\n listeners = activationState.signalListeners,\n): void {\n if (!listeners) {\n return;\n }\n process.removeListener(\"SIGTERM\", listeners.SIGTERM);\n process.removeListener(\"SIGINT\", listeners.SIGINT);\n if (activationState.signalListeners === listeners) {\n activationState.signalListeners = undefined;\n }\n}\n\nfunction removeLifecycleHooks(activationState: ActivationState): void {\n removeSignalHooks(activationState);\n if (activationState.beforeExitListener) {\n process.removeListener(\"beforeExit\", activationState.beforeExitListener);\n activationState.beforeExitListener = undefined;\n }\n}\n\nfunction installBeforeExitHook(activationState: ActivationState): void {\n const listener = () => {\n // The drain keeps the event loop alive until shutdown settles.\n void shutdown().catch((error: unknown) => {\n logDebug(`Error draining telemetry on shutdown: ${String(error)}`);\n });\n };\n activationState.beforeExitListener = listener;\n process.on(\"beforeExit\", listener);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"activation.cjs","names":["setConfig","Spool","ExportWorker","VALIDATION_ERROR_EVENT_NAME","drainValidationErrors","SERVER_ERROR_EVENT_NAME","drainServerErrors","ROOT_CONTEXT","getDistroVersion","getConfig","isApitallySpanProcessorDeclared","resolveEnvAndCreateResource","ApitallySpanExporter","Redaction","BatchSpanProcessor","SpanPipeline","setupTracerProvider","BatchLogRecordProcessor","ApitallyLogRecordExporter","ApitallyLogRecordProcessor","createLoggerProvider","MetricsPipeline","UndiciInstrumentation","isMainThread"],"sources":["../src/activation.ts"],"sourcesContent":["import diagnosticsChannel from \"node:diagnostics_channel\";\nimport type { Server } from \"node:net\";\nimport { isMainThread } from \"node:worker_threads\";\nimport { ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { type ApitallyConfig, type ApitallyOptions, getConfig, setConfig } from \"./config.js\";\nimport { ExportWorker, type ExportWorkerOptions } from \"./exportWorker.js\";\nimport {\n installConsoleCapture,\n installNestLoggerCapture,\n installPinoCapture,\n installWinstonCapture,\n} from \"./logCapture.js\";\nimport { logDebug, logError, logWarning } from \"./logger.js\";\nimport { ApitallyLogRecordExporter } from \"./logRecordExporter.js\";\nimport { ApitallyLogRecordProcessor } from \"./logRecordProcessor.js\";\nimport { MetricsPipeline } from \"./metrics.js\";\nimport { getDistroVersion } from \"./packageVersion.js\";\nimport {\n createLoggerProvider,\n resolveEnvAndCreateResource,\n setupTracerProvider,\n} from \"./providers.js\";\nimport { Redaction } from \"./redaction.js\";\nimport { installSentryEventIdRecording } from \"./sentry.js\";\nimport { drainServerErrors, resetServerErrors, SERVER_ERROR_EVENT_NAME } from \"./serverErrors.js\";\nimport { ApitallySpanExporter } from \"./spanExporter.js\";\nimport {\n isApitallySpanProcessorDeclared,\n SpanPipeline,\n setActiveSpanPipeline,\n setServerSpanActivationCallback,\n} from \"./spanProcessor.js\";\nimport { Spool } from \"./spool.js\";\nimport { emitStartupEvent, type StartupEventInfo } from \"./startup.js\";\nimport {\n drainValidationErrors,\n resetValidationErrors,\n VALIDATION_ERROR_EVENT_NAME,\n} from \"./validationErrors.js\";\n\n// The worker sends every 15 seconds, so batches only need to reach the spool\n// within that interval.\nconst BATCH_SCHEDULE_DELAY_MILLIS = 1_000;\nconst BATCH_EXPORT_TIMEOUT_MILLIS = 30_000;\nconst BATCH_MAX_QUEUE_SIZE = 2_048;\nconst BATCH_MAX_EXPORT_BATCH_SIZE = 512;\nconst BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;\nconst SIGNAL_FLUSH_TIMEOUT_MILLIS = 5_000;\n\n// Published by Node >= 20.16 and >= 22.3 once a net.Server is listening.\nconst NET_SERVER_LISTEN_CHANNEL = \"tracing:net.server.listen:asyncEnd\";\n\ntype TerminationSignal = \"SIGTERM\" | \"SIGINT\";\ntype BunServe = (this: unknown, ...args: unknown[]) => unknown;\ntype SignalListeners = Record<TerminationSignal, () => void>;\n\n// The ESM and CJS builds can load together, so a Symbol.for key gives both\n// copies the same activation state.\nconst ACTIVATION_STATE_KEY = Symbol.for(\"apitally.activation\");\n\ninterface ActivationState {\n sdkVersion: string;\n activationAttempted: boolean;\n startupEventInfo?: StartupEventInfo;\n handles?: ActivationHandles;\n runShutdown?: () => Promise<void>;\n shutdownPromise?: Promise<void>;\n beforeExitListener?: () => void;\n signalListeners?: SignalListeners;\n signalDrainPromise?: Promise<void>;\n httpServerListenHooks?: HttpServerListenHooks;\n}\n\ninterface HttpServerListenHooks {\n onNetServerListen: (message: unknown) => void;\n originalBunServe?: BunServe;\n}\n\ninterface ActivationHandles {\n spanPipeline: SpanPipeline;\n tracerProvider?: NodeTracerProvider;\n loggerProvider: LoggerProvider;\n // Consumer identifier to the hash of its last emitted consumer update, in LRU order.\n consumerUpdateHashes: Map<string, string>;\n metricsPipeline: MetricsPipeline;\n spool: Spool;\n worker: ExportWorker;\n undiciInstrumentation?: UndiciInstrumentation;\n}\n\n// Configuration stays synchronous; activate() defers timers and I/O.\nexport function configure(options: ApitallyOptions = {}): ApitallyConfig {\n const config = setConfig(options);\n // User instrumentations read this at initialization. `http/dup` adds stable\n // HTTP attributes alongside legacy ones; a user-set value takes precedence.\n if (!config.disabled && process.env.OTEL_SEMCONV_STABILITY_OPT_IN === undefined) {\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN = \"http/dup\";\n }\n setServerSpanActivationCallback(activate);\n return config;\n}\n\n// The first integration registration wins so one process emits one startup event.\nexport function registerStartupEventInfo(info: StartupEventInfo): void {\n const activationState = getActivationState();\n activationState.startupEventInfo ??= info;\n}\n\n// Activation is synchronous and attempted once, so concurrent first requests\n// observe either no activation or completed activation.\nexport function activate(): void {\n const activationState = getActivationState();\n if (activationState.activationAttempted) {\n return;\n }\n activationState.activationAttempted = true;\n if (shouldSkipActivation()) {\n return;\n }\n try {\n const handles = startPipelines(activationState.startupEventInfo);\n activationState.handles = handles;\n activationState.runShutdown = () => drainAndStop(handles);\n installBeforeExitHook(activationState);\n installSignalHooks(activationState);\n } catch (error) {\n logError(`Apitally activation failed: ${String(error)}`);\n }\n}\n\n// For integrations without a framework startup hook. A server that started\n// listening before this call is missed and activates on its first request.\nexport function activateWhenHttpServerListens(): void {\n const activationState = getActivationState();\n if (activationState.httpServerListenHooks) {\n return;\n }\n // HTTP servers carry the app as a request listener; a cluster primary's\n // internal round-robin server has none, so only workers activate.\n const onNetServerListen = (message: unknown) => {\n if ((message as { server: Server }).server.listenerCount(\"request\") > 0) {\n activate();\n }\n };\n diagnosticsChannel.subscribe(NET_SERVER_LISTEN_CHANNEL, onNetServerListen);\n // Bun publishes no net listen channel, but every Bun HTTP server starts through Bun.serve.\n const bun = (globalThis as { Bun?: { serve: BunServe } }).Bun;\n const originalBunServe = bun?.serve;\n if (bun && originalBunServe) {\n bun.serve = function (this: unknown, ...args: unknown[]) {\n const server = originalBunServe.apply(this, args);\n activate();\n return server;\n };\n }\n activationState.httpServerListenHooks = { onNetServerListen, originalBunServe };\n}\n\nexport function isActivated(): boolean {\n return getActivationState().handles !== undefined;\n}\n\nexport function getActivationHandles(): ActivationHandles | undefined {\n return getActivationState().handles;\n}\n\nexport async function flushTelemetry(): Promise<void> {\n try {\n await getActivationState().handles?.worker.runCycle();\n } catch (error) {\n logDebug(`Error flushing telemetry: ${String(error)}`);\n }\n}\n\n// Concurrent calls and lifecycle hooks share one final drain; calls before\n// activation are no-ops.\nexport function shutdown(): Promise<void> {\n const activationState = getActivationState();\n const handles = activationState.handles;\n const runShutdown = activationState.runShutdown;\n if (!handles || !runShutdown) {\n return Promise.resolve();\n }\n if (!activationState.shutdownPromise) {\n removeLifecycleHooks(activationState);\n const signalDrainPromise = activationState.signalDrainPromise;\n activationState.shutdownPromise = (\n signalDrainPromise\n ? signalDrainPromise.then(() => handles.worker.waitForIdle())\n : Promise.resolve()\n ).then(runShutdown);\n }\n return activationState.shutdownPromise;\n}\n\n// Tests replace these factories to isolate spool files and worker timing.\nexport const activationFactories = {\n createSpool: (): Spool => new Spool(),\n createExportWorker: (options: ExportWorkerOptions): ExportWorker => new ExportWorker(options),\n};\nconst defaultFactories = { ...activationFactories };\n\n// Tests reset process-global activation and its side effects between cases.\nexport async function resetActivation(): Promise<void> {\n Object.assign(activationFactories, defaultFactories);\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const activationState = holder[ACTIVATION_STATE_KEY];\n delete holder[ACTIVATION_STATE_KEY];\n hasWarnedAboutVersionSkew = false;\n resetValidationErrors();\n resetServerErrors();\n if (!activationState) {\n return;\n }\n removeLifecycleHooks(activationState);\n const listenHooks = activationState.httpServerListenHooks;\n if (listenHooks) {\n diagnosticsChannel.unsubscribe(NET_SERVER_LISTEN_CHANNEL, listenHooks.onNetServerListen);\n const bun = (globalThis as { Bun?: { serve: BunServe } }).Bun;\n if (bun && listenHooks.originalBunServe) {\n bun.serve = listenHooks.originalBunServe;\n }\n }\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n handles.undiciInstrumentation?.disable();\n await handles.worker.stop();\n await handles.spanPipeline.shutdown();\n await handles.loggerProvider.shutdown();\n await handles.spool.clear();\n}\n\nlet hasWarnedAboutVersionSkew = false;\n\n// One root-context record per aggregated error, drained right before the log\n// processor flush so the records leave with the same export cycle.\nfunction emitErrorEvents(loggerProvider: LoggerProvider): void {\n const logger = loggerProvider.getLogger(\"apitally\");\n const events: [string, AnyValueMap[]][] = [\n [VALIDATION_ERROR_EVENT_NAME, drainValidationErrors()],\n [SERVER_ERROR_EVENT_NAME, drainServerErrors()],\n ];\n for (const [eventName, bodies] of events) {\n for (const body of bodies) {\n logger.emit({ timestamp: Date.now(), context: ROOT_CONTEXT, eventName, body });\n }\n }\n}\n\nfunction getActivationState(): ActivationState {\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const existing = holder[ACTIVATION_STATE_KEY];\n if (existing) {\n if (!hasWarnedAboutVersionSkew && existing.sdkVersion !== getDistroVersion()) {\n hasWarnedAboutVersionSkew = true;\n logWarning(\n `Two copies of the apitally package with different versions (${existing.sdkVersion} and ${getDistroVersion()}) are loaded in this process; version ${existing.sdkVersion} stays active. To resolve this, deduplicate the apitally installation.`,\n );\n }\n return existing;\n }\n const activationState: ActivationState = {\n sdkVersion: getDistroVersion(),\n activationAttempted: false,\n };\n holder[ACTIVATION_STATE_KEY] = activationState;\n return activationState;\n}\n\nfunction shouldSkipActivation(): boolean {\n return (\n Boolean(process.env.JEST_WORKER_ID) ||\n Boolean(process.env.VITEST) ||\n process.env.NODE_ENV === \"test\" ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(startupEventInfo: StartupEventInfo | undefined): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource();\n const instanceId = resource.attributes[\"service.instance.id\"] as string;\n const spool = activationFactories.createSpool();\n const spanExporter = new ApitallySpanExporter({\n redaction: new Redaction(),\n env,\n instanceId,\n spool,\n maskRequestBody: config.maskRequestBody,\n maskResponseBody: config.maskResponseBody,\n });\n // Concrete options prevent OTel environment variables from changing batch\n // behavior. Each processor gets a fresh object because its config is mutated.\n const batchSpanProcessor = new BatchSpanProcessor(spanExporter, {\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize:\n config.captureRequestBody || config.captureResponseBody\n ? BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE\n : BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const spanPipeline = new SpanPipeline(batchSpanProcessor, () => spanExporter.forceFlush());\n let tracerProvider: NodeTracerProvider | undefined;\n if (!hasUserProvider) {\n tracerProvider = setupTracerProvider(resource, [spanPipeline]);\n if (!tracerProvider) {\n hasUserProvider = true;\n logWarning(\n \"Apitally could not register its OpenTelemetry tracer provider because another provider is already registered. Only metrics and the startup event are sent to Apitally until you add ApitallySpanProcessor (exported by the apitally package) to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n }\n }\n setActiveSpanPipeline(spanPipeline);\n // BatchLogRecordProcessor requires its single-options-object form; positional\n // arguments create a broken processor.\n const batchLogProcessor = new BatchLogRecordProcessor({\n exporter: new ApitallyLogRecordExporter(spool),\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const logRecordProcessor = new ApitallyLogRecordProcessor(\n batchLogProcessor,\n spanPipeline,\n config.maskLogRecord,\n );\n const loggerProvider = createLoggerProvider(resource, [logRecordProcessor]);\n const metricsPipeline = new MetricsPipeline(resource, spool);\n spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);\n const worker = activationFactories.createExportWorker({\n spool,\n otlpEndpoint: config.otlpEndpoint,\n writeToken: config.writeToken,\n env,\n });\n worker.flushCallbacks.push(\n () => metricsPipeline.collectAndExport(),\n () => spanPipeline.forceFlush(),\n () => emitErrorEvents(loggerProvider),\n () => batchLogProcessor.forceFlush(),\n );\n if (config.captureLogs) {\n installConsoleCapture(loggerProvider);\n installNestLoggerCapture(loggerProvider);\n installWinstonCapture(loggerProvider);\n installPinoCapture(loggerProvider);\n }\n installSentryEventIdRecording();\n let undiciInstrumentation: UndiciInstrumentation | undefined;\n if (!hasUserProvider) {\n undiciInstrumentation = createUndiciInstrumentation(config.otlpEndpoint);\n }\n worker.start();\n if (startupEventInfo) {\n emitStartupEvent(loggerProvider, startupEventInfo);\n }\n return {\n spanPipeline,\n tracerProvider,\n loggerProvider,\n consumerUpdateHashes: new Map(),\n metricsPipeline,\n spool,\n worker,\n undiciInstrumentation,\n };\n}\n\n// ignoreRequestHook prevents telemetry for export POSTs. The request origin can\n// be a string or URL at runtime despite its string type.\nfunction createUndiciInstrumentation(otlpEndpoint: string): UndiciInstrumentation {\n const endpointOrigin = new URL(otlpEndpoint).origin;\n return new UndiciInstrumentation({\n ignoreRequestHook: (request) => {\n try {\n return new URL(String(request.origin)).origin === endpointOrigin;\n } catch {\n return false;\n }\n },\n });\n}\n\nasync function drainAndStop(handles: ActivationHandles): Promise<void> {\n try {\n await handles.spanPipeline.shutdown();\n await handles.worker.finalDrain();\n await handles.loggerProvider.shutdown();\n await handles.worker.stop();\n } catch (error) {\n logWarning(`Error draining telemetry on shutdown: ${String(error)}`);\n }\n}\n\nfunction installSignalHooks(activationState: ActivationState): void {\n if (process.platform === \"win32\" || !isMainThread) {\n return;\n }\n let listeners: SignalListeners;\n listeners = {\n SIGTERM: () => handleTerminationSignal(activationState, listeners, \"SIGTERM\"),\n SIGINT: () => handleTerminationSignal(activationState, listeners, \"SIGINT\"),\n };\n activationState.signalListeners = listeners;\n try {\n process.prependOnceListener(\"SIGTERM\", listeners.SIGTERM);\n process.prependOnceListener(\"SIGINT\", listeners.SIGINT);\n } catch (error) {\n removeSignalHooks(activationState, listeners);\n logWarning(`Unable to install Apitally signal handlers: ${String(error)}`);\n }\n}\n\nfunction handleTerminationSignal(\n activationState: ActivationState,\n listeners: SignalListeners,\n signal: TerminationSignal,\n): void {\n const hasApplicationListener = process\n .listeners(signal)\n .some((listener) => listener !== listeners[signal]);\n removeSignalHooks(activationState, listeners);\n const drainPromise = flushAfterTerminationSignal(activationState, signal, hasApplicationListener);\n activationState.signalDrainPromise = drainPromise;\n void drainPromise.catch((error: unknown) => {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n });\n}\n\nasync function flushAfterTerminationSignal(\n activationState: ActivationState,\n signal: TerminationSignal,\n hasApplicationListener: boolean,\n): Promise<void> {\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n try {\n if (activationState.shutdownPromise) {\n await waitForSignalDeadline(activationState.shutdownPromise);\n } else {\n await handles.worker.finalDrain(SIGNAL_FLUSH_TIMEOUT_MILLIS);\n }\n } catch (error) {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n }\n if (hasApplicationListener || process.listeners(signal).length > 0) {\n return;\n }\n const exitCode = signal === \"SIGTERM\" ? 143 : 130;\n if (process.platform === \"linux\" && process.pid === 1) {\n process.exit(exitCode);\n }\n try {\n process.kill(process.pid, signal);\n } catch {\n process.exit(exitCode);\n }\n}\n\nasync function waitForSignalDeadline(promise: Promise<void>): Promise<void> {\n let deadlineTimer: NodeJS.Timeout | undefined;\n const deadlineReached = new Promise<void>((resolve) => {\n deadlineTimer = setTimeout(resolve, SIGNAL_FLUSH_TIMEOUT_MILLIS);\n });\n try {\n await Promise.race([promise, deadlineReached]);\n } finally {\n if (deadlineTimer) {\n clearTimeout(deadlineTimer);\n }\n }\n}\n\nfunction removeSignalHooks(\n activationState: ActivationState,\n listeners = activationState.signalListeners,\n): void {\n if (!listeners) {\n return;\n }\n process.removeListener(\"SIGTERM\", listeners.SIGTERM);\n process.removeListener(\"SIGINT\", listeners.SIGINT);\n if (activationState.signalListeners === listeners) {\n activationState.signalListeners = undefined;\n }\n}\n\nfunction removeLifecycleHooks(activationState: ActivationState): void {\n removeSignalHooks(activationState);\n if (activationState.beforeExitListener) {\n process.removeListener(\"beforeExit\", activationState.beforeExitListener);\n activationState.beforeExitListener = undefined;\n }\n}\n\nfunction installBeforeExitHook(activationState: ActivationState): void {\n const listener = () => {\n // The drain keeps the event loop alive until shutdown settles.\n void shutdown().catch((error: unknown) => {\n logDebug(`Error draining telemetry on shutdown: ${String(error)}`);\n });\n };\n activationState.beforeExitListener = listener;\n process.on(\"beforeExit\", listener);\n}\n"],"mappings":"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"}
|
package/dist/activation.d.cts
CHANGED
|
@@ -21,6 +21,7 @@ interface ActivationHandles {
|
|
|
21
21
|
export declare function configure(options?: ApitallyOptions): ApitallyConfig;
|
|
22
22
|
export declare function registerStartupEventInfo(info: StartupEventInfo): void;
|
|
23
23
|
export declare function activate(): void;
|
|
24
|
+
export declare function activateWhenHttpServerListens(): void;
|
|
24
25
|
export declare function isActivated(): boolean;
|
|
25
26
|
export declare function getActivationHandles(): ActivationHandles | undefined;
|
|
26
27
|
export declare function flushTelemetry(): Promise<void>;
|
package/dist/activation.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ interface ActivationHandles {
|
|
|
21
21
|
export declare function configure(options?: ApitallyOptions): ApitallyConfig;
|
|
22
22
|
export declare function registerStartupEventInfo(info: StartupEventInfo): void;
|
|
23
23
|
export declare function activate(): void;
|
|
24
|
+
export declare function activateWhenHttpServerListens(): void;
|
|
24
25
|
export declare function isActivated(): boolean;
|
|
25
26
|
export declare function getActivationHandles(): ActivationHandles | undefined;
|
|
26
27
|
export declare function flushTelemetry(): Promise<void>;
|