apitally 1.0.0-alpha.1 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +122 -79
  2. package/dist/activation.cjs +24 -2
  3. package/dist/activation.cjs.map +1 -1
  4. package/dist/activation.d.cts +2 -1
  5. package/dist/activation.d.ts +2 -1
  6. package/dist/activation.js +28 -2
  7. package/dist/activation.js.map +1 -1
  8. package/dist/adonisjs/configure.cjs +8 -9
  9. package/dist/adonisjs/configure.cjs.map +1 -1
  10. package/dist/adonisjs/configure.js +8 -9
  11. package/dist/adonisjs/configure.js.map +1 -1
  12. package/dist/adonisjs/index.cjs +36 -0
  13. package/dist/adonisjs/index.cjs.map +1 -1
  14. package/dist/adonisjs/index.d.cts +4 -1
  15. package/dist/adonisjs/index.d.ts +4 -1
  16. package/dist/adonisjs/index.js +38 -0
  17. package/dist/adonisjs/index.js.map +1 -1
  18. package/dist/config.cjs +41 -23
  19. package/dist/config.cjs.map +1 -1
  20. package/dist/config.d.cts +10 -7
  21. package/dist/config.d.ts +10 -7
  22. package/dist/config.js +41 -23
  23. package/dist/config.js.map +1 -1
  24. package/dist/consumer.cjs.map +1 -1
  25. package/dist/consumer.d.cts +5 -3
  26. package/dist/consumer.d.ts +5 -3
  27. package/dist/consumer.js.map +1 -1
  28. package/dist/context.cjs.map +1 -1
  29. package/dist/context.d.cts +4 -0
  30. package/dist/context.d.ts +4 -0
  31. package/dist/context.js.map +1 -1
  32. package/dist/elysia/index.d.cts +1 -0
  33. package/dist/elysia/index.d.ts +1 -0
  34. package/dist/elysia/middleware.cjs +14 -1
  35. package/dist/elysia/middleware.cjs.map +1 -1
  36. package/dist/elysia/middleware.d.cts +1 -0
  37. package/dist/elysia/middleware.d.ts +1 -0
  38. package/dist/elysia/middleware.js +14 -1
  39. package/dist/elysia/middleware.js.map +1 -1
  40. package/dist/exceptions.cjs +9 -3
  41. package/dist/exceptions.cjs.map +1 -1
  42. package/dist/exceptions.js +10 -4
  43. package/dist/exceptions.js.map +1 -1
  44. package/dist/exportWorker.cjs +1 -1
  45. package/dist/exportWorker.cjs.map +1 -1
  46. package/dist/exportWorker.js +1 -1
  47. package/dist/exportWorker.js.map +1 -1
  48. package/dist/express/index.d.cts +1 -0
  49. package/dist/express/index.d.ts +1 -0
  50. package/dist/express/install.d.cts +1 -0
  51. package/dist/express/install.d.ts +1 -0
  52. package/dist/express/middleware.cjs +10 -3
  53. package/dist/express/middleware.cjs.map +1 -1
  54. package/dist/express/middleware.js +14 -3
  55. package/dist/express/middleware.js.map +1 -1
  56. package/dist/express/routes.cjs +27 -17
  57. package/dist/express/routes.cjs.map +1 -1
  58. package/dist/express/routes.js +27 -17
  59. package/dist/express/routes.js.map +1 -1
  60. package/dist/fastify/index.d.cts +1 -0
  61. package/dist/fastify/index.d.ts +1 -0
  62. package/dist/fastify/install.d.cts +1 -0
  63. package/dist/fastify/install.d.ts +1 -0
  64. package/dist/fastify/middleware.cjs +18 -1
  65. package/dist/fastify/middleware.cjs.map +1 -1
  66. package/dist/fastify/middleware.js +18 -1
  67. package/dist/fastify/middleware.js.map +1 -1
  68. package/dist/h3/index.d.cts +1 -0
  69. package/dist/h3/index.d.ts +1 -0
  70. package/dist/h3/middleware.cjs +11 -5
  71. package/dist/h3/middleware.cjs.map +1 -1
  72. package/dist/h3/middleware.js +11 -5
  73. package/dist/h3/middleware.js.map +1 -1
  74. package/dist/hapi/index.d.cts +1 -0
  75. package/dist/hapi/index.d.ts +1 -0
  76. package/dist/hapi/install.d.cts +1 -0
  77. package/dist/hapi/install.d.ts +1 -0
  78. package/dist/hono/index.d.cts +1 -0
  79. package/dist/hono/index.d.ts +1 -0
  80. package/dist/hono/middleware.cjs +15 -7
  81. package/dist/hono/middleware.cjs.map +1 -1
  82. package/dist/hono/middleware.js +19 -7
  83. package/dist/hono/middleware.js.map +1 -1
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.d.cts +4 -3
  86. package/dist/index.d.ts +4 -3
  87. package/dist/index.js.map +1 -1
  88. package/dist/koa/index.d.cts +1 -0
  89. package/dist/koa/index.d.ts +1 -0
  90. package/dist/koa/middleware.cjs +12 -2
  91. package/dist/koa/middleware.cjs.map +1 -1
  92. package/dist/koa/middleware.js +12 -2
  93. package/dist/koa/middleware.js.map +1 -1
  94. package/dist/logCapture.cjs +14 -7
  95. package/dist/logCapture.cjs.map +1 -1
  96. package/dist/logCapture.d.cts +2 -0
  97. package/dist/logCapture.d.ts +2 -0
  98. package/dist/logCapture.js +14 -7
  99. package/dist/logCapture.js.map +1 -1
  100. package/dist/logRecordExporter.cjs +1 -33
  101. package/dist/logRecordExporter.cjs.map +1 -1
  102. package/dist/logRecordExporter.js +1 -33
  103. package/dist/logRecordExporter.js.map +1 -1
  104. package/dist/logRecordProcessor.cjs +30 -13
  105. package/dist/logRecordProcessor.cjs.map +1 -1
  106. package/dist/logRecordProcessor.d.cts +7 -3
  107. package/dist/logRecordProcessor.d.ts +7 -3
  108. package/dist/logRecordProcessor.js +30 -13
  109. package/dist/logRecordProcessor.js.map +1 -1
  110. package/dist/metrics.d.cts +2 -0
  111. package/dist/metrics.d.ts +2 -0
  112. package/dist/nestjs/index.cjs +20 -0
  113. package/dist/nestjs/index.cjs.map +1 -1
  114. package/dist/nestjs/index.d.cts +1 -0
  115. package/dist/nestjs/index.d.ts +1 -0
  116. package/dist/nestjs/index.js +20 -0
  117. package/dist/nestjs/index.js.map +1 -1
  118. package/dist/redaction.cjs +1 -1
  119. package/dist/redaction.cjs.map +1 -1
  120. package/dist/redaction.js +1 -1
  121. package/dist/redaction.js.map +1 -1
  122. package/dist/requestAttributes.d.cts +2 -0
  123. package/dist/requestAttributes.d.ts +2 -0
  124. package/dist/requestObservation.cjs +20 -2
  125. package/dist/requestObservation.cjs.map +1 -1
  126. package/dist/requestObservation.d.cts +2 -0
  127. package/dist/requestObservation.d.ts +2 -0
  128. package/dist/requestObservation.js +20 -2
  129. package/dist/requestObservation.js.map +1 -1
  130. package/dist/requestObservationNode.cjs +1 -1
  131. package/dist/requestObservationNode.cjs.map +1 -1
  132. package/dist/requestObservationNode.d.cts +3 -1
  133. package/dist/requestObservationNode.d.ts +3 -1
  134. package/dist/requestObservationNode.js +1 -1
  135. package/dist/requestObservationNode.js.map +1 -1
  136. package/dist/requestObservationWeb.cjs +1 -1
  137. package/dist/requestObservationWeb.cjs.map +1 -1
  138. package/dist/requestObservationWeb.d.cts +2 -0
  139. package/dist/requestObservationWeb.d.ts +2 -0
  140. package/dist/requestObservationWeb.js +1 -1
  141. package/dist/requestObservationWeb.js.map +1 -1
  142. package/dist/serverErrors.cjs +118 -0
  143. package/dist/serverErrors.cjs.map +1 -0
  144. package/dist/serverErrors.d.cts +8 -0
  145. package/dist/serverErrors.d.ts +8 -0
  146. package/dist/serverErrors.js +91 -0
  147. package/dist/serverErrors.js.map +1 -0
  148. package/dist/spanExporter.cjs +1 -2
  149. package/dist/spanExporter.cjs.map +1 -1
  150. package/dist/spanExporter.d.cts +1 -0
  151. package/dist/spanExporter.d.ts +1 -0
  152. package/dist/spanExporter.js +1 -2
  153. package/dist/spanExporter.js.map +1 -1
  154. package/dist/spanProcessor.cjs +12 -0
  155. package/dist/spanProcessor.cjs.map +1 -1
  156. package/dist/spanProcessor.d.cts +3 -0
  157. package/dist/spanProcessor.d.ts +3 -0
  158. package/dist/spanProcessor.js +12 -0
  159. package/dist/spanProcessor.js.map +1 -1
  160. package/dist/startup.cjs +8 -3
  161. package/dist/startup.cjs.map +1 -1
  162. package/dist/startup.js +8 -3
  163. package/dist/startup.js.map +1 -1
  164. package/dist/validationErrors.cjs +229 -0
  165. package/dist/validationErrors.cjs.map +1 -0
  166. package/dist/validationErrors.d.cts +21 -0
  167. package/dist/validationErrors.d.ts +21 -0
  168. package/dist/validationErrors.js +195 -0
  169. package/dist/validationErrors.js.map +1 -0
  170. package/package.json +23 -22
  171. package/dist/logRecordTruncation.cjs +0 -32
  172. package/dist/logRecordTruncation.cjs.map +0 -1
  173. package/dist/logRecordTruncation.d.cts +0 -6
  174. package/dist/logRecordTruncation.d.ts +0 -6
  175. package/dist/logRecordTruncation.js +0 -8
  176. package/dist/logRecordTruncation.js.map +0 -1
package/README.md CHANGED
@@ -25,33 +25,40 @@
25
25
  [![Codecov](https://codecov.io/gh/apitally/apitally-js/graph/badge.svg?token=j5jqlrL7Pd)](https://codecov.io/gh/apitally/apitally-js)
26
26
  [![npm](https://img.shields.io/npm/v/apitally?logo=npm&color=%23cb0000)](https://www.npmjs.com/package/apitally)
27
27
 
28
- API monitoring, analytics and request logging for [AdonisJS](https://github.com/adonisjs/core), [Elysia](https://github.com/elysiajs/elysia), [Express](https://github.com/expressjs/express), [Fastify](https://github.com/fastify/fastify), [H3](https://github.com/h3js/h3), [Hapi](https://github.com/hapijs/hapi), [Hono](https://github.com/honojs/hono), [Koa](https://github.com/koajs/koa) and [NestJS](https://github.com/nestjs/nest), built on OpenTelemetry. One line of setup instruments your app and streams traces, logs and metrics to Apitally. No OpenTelemetry knowledge, infrastructure changes or dashboards are required.
28
+ Apitally is a simple API monitoring and analytics tool that makes it easy to understand API usage, monitor performance, and troubleshoot issues.
29
+ Get started in minutes by just adding a few lines of code. No infrastructure changes required, no dashboards to build.
30
+
31
+ The SDK is an [OpenTelemetry](https://opentelemetry.io) distribution and works alongside an existing OpenTelemetry setup.
29
32
 
30
33
  Learn more about Apitally on our 🌎 [website](https://apitally.io) or check out the 📚 [documentation](https://docs.apitally.io).
31
34
 
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 a full 0.x to 1.x mapping.
37
+
32
38
  ## Key features
33
39
 
34
- - **API analytics**: Traffic, error and performance metrics for your API, each endpoint, and individual API consumers.
35
- - **Request logging**: Every request as a searchable log entry, with optional capture of headers and request/response bodies.
36
- - **Application logs**: Logs written via `console`, winston, pino, Hapi's `request.log()` or Nest's default `ConsoleLogger` are captured automatically and correlated with the request they belong to.
37
- - **Distributed tracing**: Requests are exported as OpenTelemetry spans, including spans from any other instrumentations you run.
38
- - **Error tracking**: Exceptions with stack traces for server errors, automatically linked to Sentry events if you use Sentry.
39
- - **Server metrics**: CPU, memory and uptime of your app's processes.
40
- - **Data privacy built in**: Sensitive headers and query parameters are masked by default, with configurable masking for anything else, plus sampling to control data volume.
40
+ - **API analytics**: Traffic, error and performance metrics for your API, each endpoint, and per API consumer. Drill down from metrics to individual API requests.
41
+ - **Request logs and traces**: Every request as a searchable log entry, with optional capture of headers and request/response bodies. Requests are exported as OpenTelemetry spans, including spans from any other instrumentations you have.
42
+ - **Application logs**: Logs written via `console` and other supported loggers are captured automatically and correlated with the requests they belong to.
43
+ - **Error tracking**: Validation errors and exceptions with stack traces for server errors, automatically linked to Sentry events if you use Sentry.
44
+ - **Server metrics**: CPU and memory usage of your app's processes.
45
+ - **API monitoring & alerts**: Get notified if something isn't right using custom alerts, synthetic uptime checks and heartbeat monitoring. Alert notifications can be delivered via email, Slack and Microsoft Teams.
41
46
 
42
47
  ## Supported frameworks
43
48
 
49
+ The SDK supports **Node.js** `>= 20.6` and **Bun** `>= 1.1.13`.
50
+
44
51
  | Framework | Supported versions | Setup guide |
45
52
  | --- | --- | --- |
46
- | [**AdonisJS**](https://github.com/adonisjs/core) | `>= 6.3`, `< 8` | [Link](https://docs.apitally.io/setup-guides/adonisjs) |
47
- | [**Elysia**](https://github.com/elysiajs/elysia) | `>= 1.1`, `< 2` | [Link](https://docs.apitally.io/setup-guides/elysia) |
48
- | [**Express**](https://github.com/expressjs/express) | `>= 4.18.2`, `< 6` | [Link](https://docs.apitally.io/setup-guides/express) |
49
- | [**Fastify**](https://github.com/fastify/fastify) | `>= 4.10.2`, `< 6` | [Link](https://docs.apitally.io/setup-guides/fastify) |
50
- | [**H3**](https://github.com/h3js/h3) \* | `>= 2.0.1-rc.26`, `< 3` | [Link](https://docs.apitally.io/setup-guides/h3) |
51
- | [**Hapi**](https://github.com/hapijs/hapi) | `21.x` | [Link](https://docs.apitally.io/setup-guides/hapi) |
52
- | [**Hono**](https://github.com/honojs/hono) \* | `>= 4.8.4`, `< 5` | [Link](https://docs.apitally.io/setup-guides/hono) |
53
- | [**Koa**](https://github.com/koajs/koa) | `2.x`, `3.x` | [Link](https://docs.apitally.io/setup-guides/koa) |
54
- | [**NestJS**](https://github.com/nestjs/nest) | `10.x`, `11.x` | [Link](https://docs.apitally.io/setup-guides/nestjs) |
53
+ | [**AdonisJS**](https://github.com/adonisjs/core) | `>= 6.3`, `< 8` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/adonisjs) |
54
+ | [**Elysia**](https://github.com/elysiajs/elysia) | `>= 1.1`, `< 2` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/elysia) |
55
+ | [**Express**](https://github.com/expressjs/express) | `>= 4.18.2`, `< 6` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/express) |
56
+ | [**Fastify**](https://github.com/fastify/fastify) | `>= 4.10.2`, `< 6` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/fastify) |
57
+ | [**H3**](https://github.com/h3js/h3) | `>= 2.0.1-rc.26`, `< 3` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/h3) |
58
+ | [**Hapi**](https://github.com/hapijs/hapi) | `21.x` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/hapi) |
59
+ | [**Hono**](https://github.com/honojs/hono) \* | `>= 4.8.4`, `< 5` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/hono) |
60
+ | [**Koa**](https://github.com/koajs/koa) | `2.x`, `3.x` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/koa) |
61
+ | [**NestJS**](https://github.com/nestjs/nest) | `10.x`, `11.x`, `12.x` | [Link](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/nestjs) |
55
62
 
56
63
  \* For Hono on Cloudflare Workers use our [Serverless SDK](https://github.com/apitally/apitally-js-serverless) instead.
57
64
 
@@ -59,15 +66,15 @@ Apitally also supports many other web frameworks in [Python](https://github.com/
59
66
 
60
67
  ## Getting started
61
68
 
62
- 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, including your write token.
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.
63
70
 
64
- Install the SDK. AdonisJS applications should use the Ace command in the next section instead.
71
+ To install the SDK as a dependency in your project run:
65
72
 
66
73
  ```bash
67
74
  npm install apitally
68
75
  ```
69
76
 
70
- Pass the write token via the `writeToken` option, or set the `APITALLY_WRITE_TOKEN` environment variable. See the [SDK reference](https://docs.apitally.io/sdk-reference/javascript) for all available configuration options, including how to mask sensitive data, customize request logging, and more.
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.
71
78
 
72
79
  ### AdonisJS
73
80
 
@@ -77,19 +84,11 @@ Run the Ace add command from your application directory:
77
84
  node ace add apitally
78
85
  ```
79
86
 
80
- The command installs and configures Apitally. It creates `config/apitally.ts`, adds the required environment declarations, registers the service provider and server middleware, and updates the conventional exception handler to report unhandled 5xx errors.
81
-
82
- If Apitally is already installed, or to rerun setup, use:
83
-
84
- ```bash
85
- node ace configure apitally
86
- ```
87
+ The command installs and configures Apitally. It creates `config/apitally.ts`, adds the required environment declarations, registers the service provider and server middleware, and updates the conventional exception handler to capture validation and server errors.
87
88
 
88
- Request headers, request bodies, and response bodies are opt-in prompts during setup. Response headers are enabled by default. You can change these settings later in `config/apitally.ts`.
89
+ If needed, you can change settings in `config/apitally.ts`.
89
90
 
90
- The SDK-wide environment default is `dev`. `APITALLY_ENV` is deployment-specific, so set it appropriately for staging and production.
91
-
92
- For further instructions, see our [setup guide for AdonisJS](https://docs.apitally.io/setup-guides/adonisjs).
91
+ For further instructions, see our [setup guide for AdonisJS](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/adonisjs).
93
92
 
94
93
  ### Elysia
95
94
 
@@ -110,7 +109,7 @@ const app = new Elysia()
110
109
  .get("/items/:id", ({ params }) => ({ id: params.id }));
111
110
  ```
112
111
 
113
- For further instructions, see our [setup guide for Elysia](https://docs.apitally.io/setup-guides/elysia).
112
+ For further instructions, see our [setup guide for Elysia](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/elysia).
114
113
 
115
114
  ### Express
116
115
 
@@ -126,13 +125,11 @@ const app = express();
126
125
 
127
126
  useApitally(app, {
128
127
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
129
- env: "dev", // optional, defaults to "dev"
128
+ env: "dev", // or "prod" etc.
130
129
  });
131
130
  ```
132
131
 
133
- The register import ensures routes are captured no matter where they are registered — including routers assembled at module scope. It's one rule for every app shape: first line of your entry module.
134
-
135
- For further instructions, see our [setup guide for Express](https://docs.apitally.io/setup-guides/express).
132
+ For further instructions, see our [setup guide for Express](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/express).
136
133
 
137
134
  ### Fastify
138
135
 
@@ -146,17 +143,17 @@ const app = Fastify();
146
143
 
147
144
  useApitally(app, {
148
145
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
149
- env: "dev", // optional, defaults to "dev"
146
+ env: "dev", // or "prod" etc.
150
147
  });
151
148
 
152
149
  // register plugins and routes below this point
153
150
  ```
154
151
 
155
- For further instructions, see our [setup guide for Fastify](https://docs.apitally.io/setup-guides/fastify).
152
+ For further instructions, see our [setup guide for Fastify](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/fastify).
156
153
 
157
154
  ### NestJS
158
155
 
159
- Call the synchronous `useApitally(app)` immediately after creating the Nest application, before `app.init()` or `app.listen()`:
156
+ Call `useApitally(app)` immediately after creating the Nest application, before `app.init()` or `app.listen()`:
160
157
 
161
158
  ```javascript
162
159
  import { NestFactory } from "@nestjs/core";
@@ -167,13 +164,13 @@ const app = await NestFactory.create(AppModule);
167
164
 
168
165
  useApitally(app, {
169
166
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
170
- env: "dev", // optional, defaults to "dev"
167
+ env: "dev", // or "prod" etc.
171
168
  });
172
169
 
173
170
  await app.listen(3000);
174
171
  ```
175
172
 
176
- For further instructions, see our [setup guide for NestJS](https://docs.apitally.io/setup-guides/nestjs).
173
+ For further instructions, see our [setup guide for NestJS](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/nestjs).
177
174
 
178
175
  ### H3
179
176
 
@@ -187,13 +184,13 @@ const app = new H3({
187
184
  plugins: [
188
185
  apitallyPlugin({
189
186
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
190
- env: "dev", // optional, defaults to "dev"
187
+ env: "dev", // or "prod" etc.
191
188
  }),
192
189
  ],
193
190
  });
194
191
  ```
195
192
 
196
- For further instructions, see our [setup guide for H3](https://docs.apitally.io/setup-guides/h3).
193
+ For further instructions, see our [setup guide for H3](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/h3).
197
194
 
198
195
  ### Hapi
199
196
 
@@ -208,7 +205,7 @@ const server = Hapi.server({ port: 3000 });
208
205
  await server.register(
209
206
  apitallyPlugin({
210
207
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
211
- env: "dev", // optional, defaults to "dev"
208
+ env: "dev", // or "prod" etc.
212
209
  }),
213
210
  );
214
211
 
@@ -216,11 +213,11 @@ await server.register(
216
213
  await server.start();
217
214
  ```
218
215
 
219
- For further instructions, see our [setup guide for Hapi](https://docs.apitally.io/setup-guides/hapi).
216
+ For further instructions, see our [setup guide for Hapi](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/hapi).
220
217
 
221
218
  ### Hono
222
219
 
223
- Call `useApitally(app)` immediately after creating the app — before registering middleware and routes, and before `app.fetch` is handed to the server:
220
+ Call `useApitally(app)` immediately after creating the app, before registering middleware and routes:
224
221
 
225
222
  ```javascript
226
223
  import { Hono } from "hono";
@@ -230,13 +227,13 @@ const app = new Hono();
230
227
 
231
228
  useApitally(app, {
232
229
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
233
- env: "dev", // optional, defaults to "dev"
230
+ env: "dev", // or "prod" etc.
234
231
  });
235
232
 
236
233
  // register middleware and routes below this point
237
234
  ```
238
235
 
239
- For further instructions, see our [setup guide for Hono](https://docs.apitally.io/setup-guides/hono).
236
+ For further instructions, see our [setup guide for Hono](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/hono).
240
237
 
241
238
  ### Koa
242
239
 
@@ -250,36 +247,64 @@ const app = new Koa();
250
247
 
251
248
  useApitally(app, {
252
249
  writeToken: "your-write-token", // or set APITALLY_WRITE_TOKEN
253
- env: "dev", // optional, defaults to "dev"
250
+ env: "dev", // or "prod" etc.
254
251
  });
255
252
 
256
253
  // register middleware and routes below this point
257
254
  ```
258
255
 
259
- For further instructions, see our [setup guide for Koa](https://docs.apitally.io/setup-guides/koa).
260
-
261
- ## Trusted proxies
256
+ For further instructions, see our [setup guide for Koa](https://docs.apitally.io/sdk-reference/javascript/v1/setup-guides/koa).
262
257
 
263
- When your application runs behind a reverse proxy, configure the framework's trusted-proxy setting so Apitally can record the client IP for GeoIP. The SDK uses the client address resolved by Express, Fastify, Koa, AdonisJS, or the corresponding NestJS adapter. It does not trust forwarding headers directly.
258
+ ## Configuration
264
259
 
265
- ## Using Sentry
260
+ The write token and environment can also be provided via the `APITALLY_WRITE_TOKEN` and `APITALLY_ENV` environment variables instead of the `writeToken` and `env` options. The environment defaults to `dev`.
266
261
 
267
- Sentry's Node.js SDK registers an OpenTelemetry tracer provider by default. If you use Sentry for error monitoring without performance tracing, let Apitally configure OpenTelemetry by disabling Sentry's setup:
262
+ By default, Apitally captures response headers but not request headers or request and response bodies. You can opt in with options:
268
263
 
269
264
  ```javascript
270
- Sentry.init({
271
- dsn: "your-sentry-dsn",
272
- skipOpenTelemetrySetup: true,
265
+ useApitally(app, {
266
+ writeToken: "your-write-token",
267
+ env: "dev",
268
+ captureRequestHeaders: true,
269
+ captureRequestBody: true,
270
+ captureResponseBody: true,
273
271
  });
274
272
  ```
275
273
 
276
- This keeps Sentry error reporting and Apitally's request logs and traces working together. If you use Sentry performance tracing, configure a shared OpenTelemetry provider and include `ApitallySpanProcessor` as described below.
274
+ Sensitive values in query parameters, headers, and body fields are masked automatically based on built-in patterns, and you can add your own via the `maskQueryParams`, `maskHeaders`, and `maskBodyFields` options.
275
+
276
+ On high-traffic applications you can capture logs and traces for only a fraction of requests by setting `sampleRate` (e.g. `0.1` for 10%), or decide per request with the `sampleOnRequest` and `sampleOnResponse` callbacks. Metrics always count every request, regardless of sampling.
277
+
278
+ Application logs written via `console` and other supported loggers are captured and correlated with requests by default. Use `maskLogRecord` to transform or drop Apitally's captured copy, or opt out with `captureLogs: false`.
279
+
280
+ See the [SDK reference](https://docs.apitally.io/sdk-reference/javascript/v1/configuration) for all configuration options.
281
+
282
+ ## Identifying consumers and more
283
+
284
+ The top-level `apitally` package provides functions you can call from anywhere in your request handling code:
285
+
286
+ ```javascript
287
+ import { setConsumer, setRequestAttribute, captureException } from "apitally";
288
+
289
+ // Associate the current request with an API consumer
290
+ setConsumer({ identifier: user.identifier, name: user.name, group: user.group });
291
+
292
+ // Attach a custom attribute to the current request
293
+ setRequestAttribute("tenant", tenantId);
294
+
295
+ // Capture a handled exception for the current request
296
+ captureException(error);
297
+ ```
298
+
299
+ `setConsumer()` also accepts an identifier string, for example `setConsumer(user.identifier)`.
300
+
301
+ For further details, check out our [documentation](https://docs.apitally.io).
277
302
 
278
- ## Works with your existing OpenTelemetry setup
303
+ ## Existing OpenTelemetry setup
279
304
 
280
- If your app doesn't use OpenTelemetry, you don't need to know it's there — the SDK sets up a private, fully configured pipeline.
305
+ If your app doesn't already use OpenTelemetry, you don't need to know it's there. The Apitally SDK configures OpenTelemetry automatically.
281
306
 
282
- If your app already registers its own tracer provider (e.g. via `NodeSDK`), Apitally never replaces it. Instead, add the `ApitallySpanProcessor` to your provider's span processors:
307
+ If your app already registers its own tracer provider (e.g. via `NodeSDK`), Apitally does not replace it. Instead, you need to add the `ApitallySpanProcessor` to your provider's span processors:
283
308
 
284
309
  ```javascript
285
310
  import { NodeSDK } from "@opentelemetry/sdk-node";
@@ -291,7 +316,32 @@ const sdk = new NodeSDK({
291
316
  });
292
317
  ```
293
318
 
294
- Your existing exporters keep seeing everything they already see: Apitally adopts the spans your instrumentation produces instead of creating duplicates, and its meter and logger providers stay private, so nothing leaks into your own pipelines.
319
+ Your tracer provider's sampling settings also affect Apitally. Requests excluded by the sampler will not have request logs or traces in Apitally. Metrics still include all requests, regardless of sampling.
320
+
321
+ ### Sentry
322
+
323
+ Sentry's Node.js SDK configures OpenTelemetry automatically. To use Apitally alongside Sentry, add `ApitallySpanProcessor` to Sentry's configuration and call `Sentry.init()` before `useApitally()`:
324
+
325
+ ```javascript
326
+ import * as Sentry from "@sentry/node";
327
+ import { ApitallySpanProcessor } from "apitally";
328
+
329
+ Sentry.init({
330
+ dsn: "your-sentry-dsn",
331
+ // Enable tracing
332
+ tracesSampleRate: 1.0,
333
+ // Add Apitally's span processor
334
+ openTelemetrySpanProcessors: [new ApitallySpanProcessor()],
335
+ // Optional: send only errors to Sentry
336
+ beforeSendTransaction: () => null,
337
+ });
338
+ ```
339
+
340
+ Apitally uses the spans recorded by Sentry, so tracing must be enabled in Sentry. Requests excluded by Sentry's sampler will also be missing from Apitally's request logs and traces.
341
+
342
+ Returning `null` from `beforeSendTransaction` prevents traces from being sent to Sentry without affecting Apitally's request logs and traces.
343
+
344
+ ### Elysia's OpenTelemetry plugin
295
345
 
296
346
  When using Elysia's `@elysia/opentelemetry` plugin, register Apitally first so it adopts the OpenTelemetry SERVER span:
297
347
 
@@ -305,31 +355,24 @@ const app = new Elysia()
305
355
  .use(opentelemetry());
306
356
  ```
307
357
 
308
- ## Graceful shutdown
358
+ ## Trusted proxies
309
359
 
310
- Telemetry is exported in the background roughly every 15 seconds. After successful activation, Apitally installs `SIGTERM` and `SIGINT` listeners by default on supported POSIX main-thread processes. There is no opt-out, and the fixed five-second timeout is not configurable.
360
+ 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.
311
361
 
312
- On either signal, Apitally makes a non-destructive best-effort final drain of completed telemetry for up to five seconds. If another listener exists for that signal, that listener retains application lifecycle ownership. It must eventually terminate the process or allow it to drain naturally. If Apitally is the sole listener, it removes its listeners before draining and then restores the signal's original termination behavior. A repeated signal is therefore not delayed by another Apitally drain.
362
+ ## Graceful shutdown
363
+
364
+ Apitally sends telemetry in batches and automatically attempts a final export during normal process shutdown.
313
365
 
314
- Use the `shutdown()` function for the coordinated full teardown path. Stop traffic and wait for in-flight work before awaiting it:
366
+ 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:
315
367
 
316
368
  ```javascript
317
369
  import { shutdown } from "apitally";
318
370
 
319
- process.on("SIGTERM", () => {
320
- server.close(async () => {
321
- await shutdown();
322
- });
323
- });
371
+ // After the server has closed and requests have finished:
372
+ await shutdown();
373
+ process.exit(0);
324
374
  ```
325
375
 
326
- ## Runtime support
327
-
328
- - **Node.js** `>= 20.6`
329
- - **Bun** is supported for Elysia, H3 and Hono apps
330
-
331
- For edge and serverless runtimes like Cloudflare Workers, use our [Serverless SDK](https://github.com/apitally/apitally-js-serverless) instead.
332
-
333
376
  ## Getting help
334
377
 
335
378
  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.
@@ -30,6 +30,7 @@ __export(activation_exports, {
30
30
  });
31
31
  module.exports = __toCommonJS(activation_exports);
32
32
  var import_node_worker_threads = require("node:worker_threads");
33
+ var import_api = require("@opentelemetry/api");
33
34
  var import_instrumentation_undici = require("@opentelemetry/instrumentation-undici");
34
35
  var import_sdk_logs = require("@opentelemetry/sdk-logs");
35
36
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
@@ -44,10 +45,12 @@ var import_packageVersion = require('./packageVersion.cjs');
44
45
  var import_providers = require('./providers.cjs');
45
46
  var import_redaction = require('./redaction.cjs');
46
47
  var import_sentry = require('./sentry.cjs');
48
+ var import_serverErrors = require('./serverErrors.cjs');
47
49
  var import_spanExporter = require('./spanExporter.cjs');
48
50
  var import_spanProcessor = require('./spanProcessor.cjs');
49
51
  var import_spool = require('./spool.cjs');
50
52
  var import_startup = require('./startup.cjs');
53
+ var import_validationErrors = require('./validationErrors.cjs');
51
54
  const BATCH_SCHEDULE_DELAY_MILLIS = 1e3;
52
55
  const BATCH_EXPORT_TIMEOUT_MILLIS = 3e4;
53
56
  const BATCH_MAX_QUEUE_SIZE = 2048;
@@ -124,6 +127,8 @@ async function resetActivation() {
124
127
  const activationState = holder[ACTIVATION_STATE_KEY];
125
128
  delete holder[ACTIVATION_STATE_KEY];
126
129
  hasWarnedAboutVersionSkew = false;
130
+ (0, import_validationErrors.resetValidationErrors)();
131
+ (0, import_serverErrors.resetServerErrors)();
127
132
  if (!activationState) {
128
133
  return;
129
134
  }
@@ -139,6 +144,18 @@ async function resetActivation() {
139
144
  await handles.spool.clear();
140
145
  }
141
146
  let hasWarnedAboutVersionSkew = false;
147
+ function emitErrorEvents(loggerProvider) {
148
+ const logger = loggerProvider.getLogger("apitally");
149
+ const events = [
150
+ [import_validationErrors.VALIDATION_ERROR_EVENT_NAME, (0, import_validationErrors.drainValidationErrors)()],
151
+ [import_serverErrors.SERVER_ERROR_EVENT_NAME, (0, import_serverErrors.drainServerErrors)()]
152
+ ];
153
+ for (const [eventName, bodies] of events) {
154
+ for (const body of bodies) {
155
+ logger.emit({ timestamp: Date.now(), context: import_api.ROOT_CONTEXT, eventName, body });
156
+ }
157
+ }
158
+ }
142
159
  function getActivationState() {
143
160
  const holder = globalThis;
144
161
  const existing = holder[ACTIVATION_STATE_KEY];
@@ -201,7 +218,11 @@ function startPipelines(startupEventInfo, triggeringSpan) {
201
218
  maxQueueSize: BATCH_MAX_QUEUE_SIZE,
202
219
  maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE
203
220
  });
204
- const logRecordProcessor = new import_logRecordProcessor.ApitallyLogRecordProcessor(batchLogProcessor, spanPipeline);
221
+ const logRecordProcessor = new import_logRecordProcessor.ApitallyLogRecordProcessor(
222
+ batchLogProcessor,
223
+ spanPipeline,
224
+ config.maskLogRecord
225
+ );
205
226
  const loggerProvider = (0, import_providers.createLoggerProvider)(resource, [logRecordProcessor]);
206
227
  const metricsPipeline = new import_metrics.MetricsPipeline(resource, spool);
207
228
  spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);
@@ -214,6 +235,7 @@ function startPipelines(startupEventInfo, triggeringSpan) {
214
235
  worker.flushCallbacks.push(
215
236
  () => metricsPipeline.collectAndExport(),
216
237
  () => batchSpanProcessor.forceFlush(),
238
+ () => emitErrorEvents(loggerProvider),
217
239
  () => batchLogProcessor.forceFlush()
218
240
  );
219
241
  if (config.captureLogs) {
@@ -256,8 +278,8 @@ function createUndiciInstrumentation(otlpEndpoint) {
256
278
  async function drainAndStop(handles) {
257
279
  try {
258
280
  await handles.spanPipeline.shutdown();
259
- await handles.loggerProvider.shutdown();
260
281
  await handles.worker.finalDrain();
282
+ await handles.loggerProvider.shutdown();
261
283
  await handles.worker.stop();
262
284
  } catch (error) {
263
285
  (0, import_logger.logWarning)(`Error draining telemetry on shutdown: ${String(error)}`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/activation.ts"],"sourcesContent":["import { isMainThread } from \"node:worker_threads\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor, type Span } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport {\n type ApitallyConfig,\n type ApitallyOptions,\n getConfig,\n isApitallyDisabledViaEnv,\n setConfig,\n} 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 { 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\";\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 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(triggeringSpan?: Span): 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, triggeringSpan);\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 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\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 // The emergency kill switch overrides an explicit disabled: false option.\n isApitallyDisabledViaEnv() ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(\n startupEventInfo: StartupEventInfo | undefined,\n triggeringSpan?: Span,\n): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource(hasUserProvider, triggeringSpan?.resource);\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);\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(batchLogProcessor, spanPipeline);\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 () => batchSpanProcessor.forceFlush(),\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 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.loggerProvider.shutdown();\n await handles.worker.finalDrain();\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":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAA6B;AAC7B,oCAAsC;AACtC,sBAA6D;AAC7D,4BAA8C;AAE9C,oBAMO;AACP,0BAAuD;AACvD,wBAKO;AACP,oBAA+C;AAC/C,+BAA0C;AAC1C,gCAA2C;AAC3C,qBAAgC;AAChC,4BAAiC;AACjC,uBAIO;AACP,uBAA0B;AAC1B,oBAA8C;AAC9C,0BAAqC;AACrC,2BAKO;AACP,mBAAsB;AACtB,qBAAwD;AAIxD,MAAM,8BAA8B;AACpC,MAAM,8BAA8B;AACpC,MAAM,uBAAuB;AAC7B,MAAM,8BAA8B;AACpC,MAAM,gDAAgD;AACtD,MAAM,8BAA8B;AAOpC,MAAM,uBAAuB,uBAAO,IAAI,qBAAqB;AAyBtD,SAAS,UAAU,UAA2B,CAAC,GAAmB;AACvE,QAAM,aAAS,yBAAU,OAAO;AAGhC,MAAI,CAAC,OAAO,YAAY,QAAQ,IAAI,kCAAkC,QAAW;AAC/E,YAAQ,IAAI,gCAAgC;AAAA,EAC9C;AACA,4DAAgC,QAAQ;AACxC,SAAO;AACT;AAGO,SAAS,yBAAyB,MAA8B;AACrE,QAAM,kBAAkB,mBAAmB;AAC3C,kBAAgB,qBAAqB;AACvC;AAIO,SAAS,SAAS,gBAA6B;AACpD,QAAM,kBAAkB,mBAAmB;AAC3C,MAAI,gBAAgB,qBAAqB;AACvC;AAAA,EACF;AACA,kBAAgB,sBAAsB;AACtC,MAAI,qBAAqB,GAAG;AAC1B;AAAA,EACF;AACA,MAAI;AACF,UAAM,UAAU,eAAe,gBAAgB,kBAAkB,cAAc;AAC/E,oBAAgB,UAAU;AAC1B,oBAAgB,cAAc,MAAM,aAAa,OAAO;AACxD,0BAAsB,eAAe;AACrC,uBAAmB,eAAe;AAAA,EACpC,SAAS,OAAO;AACd,gCAAS,+BAA+B,OAAO,KAAK,CAAC,EAAE;AAAA,EACzD;AACF;AAEO,SAAS,cAAuB;AACrC,SAAO,mBAAmB,EAAE,YAAY;AAC1C;AAEO,SAAS,uBAAsD;AACpE,SAAO,mBAAmB,EAAE;AAC9B;AAEA,eAAsB,iBAAgC;AACpD,MAAI;AACF,UAAM,mBAAmB,EAAE,SAAS,OAAO,SAAS;AAAA,EACtD,SAAS,OAAO;AACd,gCAAS,6BAA6B,OAAO,KAAK,CAAC,EAAE;AAAA,EACvD;AACF;AAIO,SAAS,WAA0B;AACxC,QAAM,kBAAkB,mBAAmB;AAC3C,QAAM,UAAU,gBAAgB;AAChC,QAAM,cAAc,gBAAgB;AACpC,MAAI,CAAC,WAAW,CAAC,aAAa;AAC5B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACA,MAAI,CAAC,gBAAgB,iBAAiB;AACpC,yBAAqB,eAAe;AACpC,UAAM,qBAAqB,gBAAgB;AAC3C,oBAAgB,mBACd,qBACI,mBAAmB,KAAK,MAAM,QAAQ,OAAO,YAAY,CAAC,IAC1D,QAAQ,QAAQ,GACpB,KAAK,WAAW;AAAA,EACpB;AACA,SAAO,gBAAgB;AACzB;AAGO,MAAM,sBAAsB;AAAA,EACjC,aAAa,MAAa,IAAI,mBAAM;AAAA,EACpC,oBAAoB,CAAC,YAA+C,IAAI,iCAAa,OAAO;AAC9F;AACA,MAAM,mBAAmB,EAAE,GAAG,oBAAoB;AAGlD,eAAsB,kBAAiC;AACrD,SAAO,OAAO,qBAAqB,gBAAgB;AACnD,QAAM,SAAS;AACf,QAAM,kBAAkB,OAAO,oBAAoB;AACnD,SAAO,OAAO,oBAAoB;AAClC,8BAA4B;AAC5B,MAAI,CAAC,iBAAiB;AACpB;AAAA,EACF;AACA,uBAAqB,eAAe;AACpC,QAAM,UAAU,gBAAgB;AAChC,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AACA,UAAQ,uBAAuB,QAAQ;AACvC,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM,QAAQ,aAAa,SAAS;AACpC,QAAM,QAAQ,eAAe,SAAS;AACtC,QAAM,QAAQ,MAAM,MAAM;AAC5B;AAEA,IAAI,4BAA4B;AAEhC,SAAS,qBAAsC;AAC7C,QAAM,SAAS;AACf,QAAM,WAAW,OAAO,oBAAoB;AAC5C,MAAI,UAAU;AACZ,QAAI,CAAC,6BAA6B,SAAS,mBAAe,wCAAiB,GAAG;AAC5E,kCAA4B;AAC5B;AAAA,QACE,+DAA+D,SAAS,UAAU,YAAQ,wCAAiB,CAAC,yCAAyC,SAAS,UAAU;AAAA,MAC1K;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,QAAM,kBAAmC;AAAA,IACvC,gBAAY,wCAAiB;AAAA,IAC7B,qBAAqB;AAAA,EACvB;AACA,SAAO,oBAAoB,IAAI;AAC/B,SAAO;AACT;AAEA,SAAS,uBAAgC;AACvC,SACE,QAAQ,QAAQ,IAAI,cAAc,KAClC,QAAQ,QAAQ,IAAI,MAAM,KAC1B,QAAQ,IAAI,aAAa;AAAA,MAEzB,wCAAyB,SACzB,yBAAU,EAAE;AAEhB;AAEA,SAAS,eACP,kBACA,gBACmB;AACnB,QAAM,aAAS,yBAAU;AACzB,MAAI,sBAAkB,sDAAgC;AACtD,QAAM,EAAE,KAAK,SAAS,QAAI,8CAA4B,iBAAiB,gBAAgB,QAAQ;AAC/F,QAAM,aAAa,SAAS,WAAW,qBAAqB;AAC5D,QAAM,QAAQ,oBAAoB,YAAY;AAC9C,QAAM,eAAe,IAAI,yCAAqB;AAAA,IAC5C,WAAW,IAAI,2BAAU;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB,OAAO;AAAA,IACxB,kBAAkB,OAAO;AAAA,EAC3B,CAAC;AAGD,QAAM,qBAAqB,IAAI,yCAAmB,cAAc;AAAA,IAC9D,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,cAAc;AAAA,IACd,oBACE,OAAO,sBAAsB,OAAO,sBAChC,gDACA;AAAA,EACR,CAAC;AACD,QAAM,eAAe,IAAI,kCAAa,kBAAkB;AACxD,MAAI;AACJ,MAAI,CAAC,iBAAiB;AACpB,yBAAiB,sCAAoB,UAAU,CAAC,YAAY,CAAC;AAC7D,QAAI,CAAC,gBAAgB;AACnB,wBAAkB;AAClB;AAAA,QACE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,kDAAsB,YAAY;AAGlC,QAAM,oBAAoB,IAAI,wCAAwB;AAAA,IACpD,UAAU,IAAI,mDAA0B,KAAK;AAAA,IAC7C,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,cAAc;AAAA,IACd,oBAAoB;AAAA,EACtB,CAAC;AACD,QAAM,qBAAqB,IAAI,qDAA2B,mBAAmB,YAAY;AACzF,QAAM,qBAAiB,uCAAqB,UAAU,CAAC,kBAAkB,CAAC;AAC1E,QAAM,kBAAkB,IAAI,+BAAgB,UAAU,KAAK;AAC3D,eAAa,kBAAkB,CAAC,WAAW,gBAAgB,kBAAkB,MAAM;AACnF,QAAM,SAAS,oBAAoB,mBAAmB;AAAA,IACpD;AAAA,IACA,cAAc,OAAO;AAAA,IACrB,YAAY,OAAO;AAAA,IACnB;AAAA,EACF,CAAC;AACD,SAAO,eAAe;AAAA,IACpB,MAAM,gBAAgB,iBAAiB;AAAA,IACvC,MAAM,mBAAmB,WAAW;AAAA,IACpC,MAAM,kBAAkB,WAAW;AAAA,EACrC;AACA,MAAI,OAAO,aAAa;AACtB,iDAAsB,cAAc;AACpC,oDAAyB,cAAc;AACvC,iDAAsB,cAAc;AACpC,8CAAmB,cAAc;AAAA,EACnC;AACA,mDAA8B;AAC9B,MAAI;AACJ,MAAI,CAAC,iBAAiB;AACpB,4BAAwB,4BAA4B,OAAO,YAAY;AAAA,EACzE;AACA,SAAO,MAAM;AACb,MAAI,kBAAkB;AACpB,yCAAiB,gBAAgB,gBAAgB;AAAA,EACnD;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAIA,SAAS,4BAA4B,cAA6C;AAChF,QAAM,iBAAiB,IAAI,IAAI,YAAY,EAAE;AAC7C,SAAO,IAAI,oDAAsB;AAAA,IAC/B,mBAAmB,CAAC,YAAY;AAC9B,UAAI;AACF,eAAO,IAAI,IAAI,OAAO,QAAQ,MAAM,CAAC,EAAE,WAAW;AAAA,MACpD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,aAAa,SAA2C;AACrE,MAAI;AACF,UAAM,QAAQ,aAAa,SAAS;AACpC,UAAM,QAAQ,eAAe,SAAS;AACtC,UAAM,QAAQ,OAAO,WAAW;AAChC,UAAM,QAAQ,OAAO,KAAK;AAAA,EAC5B,SAAS,OAAO;AACd,kCAAW,yCAAyC,OAAO,KAAK,CAAC,EAAE;AAAA,EACrE;AACF;AAEA,SAAS,mBAAmB,iBAAwC;AAClE,MAAI,QAAQ,aAAa,WAAW,CAAC,yCAAc;AACjD;AAAA,EACF;AACA,MAAI;AACJ,cAAY;AAAA,IACV,SAAS,MAAM,wBAAwB,iBAAiB,WAAW,SAAS;AAAA,IAC5E,QAAQ,MAAM,wBAAwB,iBAAiB,WAAW,QAAQ;AAAA,EAC5E;AACA,kBAAgB,kBAAkB;AAClC,MAAI;AACF,YAAQ,oBAAoB,WAAW,UAAU,OAAO;AACxD,YAAQ,oBAAoB,UAAU,UAAU,MAAM;AAAA,EACxD,SAAS,OAAO;AACd,sBAAkB,iBAAiB,SAAS;AAC5C,kCAAW,+CAA+C,OAAO,KAAK,CAAC,EAAE;AAAA,EAC3E;AACF;AAEA,SAAS,wBACP,iBACA,WACA,QACM;AACN,QAAM,yBAAyB,QAC5B,UAAU,MAAM,EAChB,KAAK,CAAC,aAAa,aAAa,UAAU,MAAM,CAAC;AACpD,oBAAkB,iBAAiB,SAAS;AAC5C,QAAM,eAAe,4BAA4B,iBAAiB,QAAQ,sBAAsB;AAChG,kBAAgB,qBAAqB;AACrC,OAAK,aAAa,MAAM,CAAC,UAAmB;AAC1C,gCAAS,+BAA+B,MAAM,KAAK,OAAO,KAAK,CAAC,EAAE;AAAA,EACpE,CAAC;AACH;AAEA,eAAe,4BACb,iBACA,QACA,wBACe;AACf,QAAM,UAAU,gBAAgB;AAChC,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AACA,MAAI;AACF,QAAI,gBAAgB,iBAAiB;AACnC,YAAM,sBAAsB,gBAAgB,eAAe;AAAA,IAC7D,OAAO;AACL,YAAM,QAAQ,OAAO,WAAW,2BAA2B;AAAA,IAC7D;AAAA,EACF,SAAS,OAAO;AACd,gCAAS,+BAA+B,MAAM,KAAK,OAAO,KAAK,CAAC,EAAE;AAAA,EACpE;AACA,MAAI,0BAA0B,QAAQ,UAAU,MAAM,EAAE,SAAS,GAAG;AAClE;AAAA,EACF;AACA,QAAM,WAAW,WAAW,YAAY,MAAM;AAC9C,MAAI,QAAQ,aAAa,WAAW,QAAQ,QAAQ,GAAG;AACrD,YAAQ,KAAK,QAAQ;AAAA,EACvB;AACA,MAAI;AACF,YAAQ,KAAK,QAAQ,KAAK,MAAM;AAAA,EAClC,QAAQ;AACN,YAAQ,KAAK,QAAQ;AAAA,EACvB;AACF;AAEA,eAAe,sBAAsB,SAAuC;AAC1E,MAAI;AACJ,QAAM,kBAAkB,IAAI,QAAc,CAAC,YAAY;AACrD,oBAAgB,WAAW,SAAS,2BAA2B;AAAA,EACjE,CAAC;AACD,MAAI;AACF,UAAM,QAAQ,KAAK,CAAC,SAAS,eAAe,CAAC;AAAA,EAC/C,UAAE;AACA,QAAI,eAAe;AACjB,mBAAa,aAAa;AAAA,IAC5B;AAAA,EACF;AACF;AAEA,SAAS,kBACP,iBACA,YAAY,gBAAgB,iBACtB;AACN,MAAI,CAAC,WAAW;AACd;AAAA,EACF;AACA,UAAQ,eAAe,WAAW,UAAU,OAAO;AACnD,UAAQ,eAAe,UAAU,UAAU,MAAM;AACjD,MAAI,gBAAgB,oBAAoB,WAAW;AACjD,oBAAgB,kBAAkB;AAAA,EACpC;AACF;AAEA,SAAS,qBAAqB,iBAAwC;AACpE,oBAAkB,eAAe;AACjC,MAAI,gBAAgB,oBAAoB;AACtC,YAAQ,eAAe,cAAc,gBAAgB,kBAAkB;AACvE,oBAAgB,qBAAqB;AAAA,EACvC;AACF;AAEA,SAAS,sBAAsB,iBAAwC;AACrE,QAAM,WAAW,MAAM;AAErB,SAAK,SAAS,EAAE,MAAM,CAAC,UAAmB;AACxC,kCAAS,yCAAyC,OAAO,KAAK,CAAC,EAAE;AAAA,IACnE,CAAC;AAAA,EACH;AACA,kBAAgB,qBAAqB;AACrC,UAAQ,GAAG,cAAc,QAAQ;AACnC;","names":[]}
1
+ {"version":3,"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, type Span } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport {\n type ApitallyConfig,\n type ApitallyOptions,\n getConfig,\n isApitallyDisabledViaEnv,\n setConfig,\n} 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 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(triggeringSpan?: Span): 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, triggeringSpan);\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 aggregate group, 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 // The emergency kill switch overrides an explicit disabled: false option.\n isApitallyDisabledViaEnv() ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(\n startupEventInfo: StartupEventInfo | undefined,\n triggeringSpan?: Span,\n): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource(hasUserProvider, triggeringSpan?.resource);\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);\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 () => batchSpanProcessor.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 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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","names":[]}
@@ -13,8 +13,9 @@ import '@opentelemetry/sdk-metrics';
13
13
  import './context.cjs';
14
14
  import '@opentelemetry/api';
15
15
  import '@opentelemetry/core';
16
- import 'node:zlib';
16
+ import './validationErrors.cjs';
17
17
  import '@opentelemetry/api-logs';
18
+ import 'node:zlib';
18
19
 
19
20
  interface ActivationHandles {
20
21
  spanPipeline: SpanPipeline;
@@ -13,8 +13,9 @@ import '@opentelemetry/sdk-metrics';
13
13
  import './context.js';
14
14
  import '@opentelemetry/api';
15
15
  import '@opentelemetry/core';
16
- import 'node:zlib';
16
+ import './validationErrors.js';
17
17
  import '@opentelemetry/api-logs';
18
+ import 'node:zlib';
18
19
 
19
20
  interface ActivationHandles {
20
21
  spanPipeline: SpanPipeline;