@upyo/opentelemetry 0.2.0-dev.24
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 +449 -0
- package/dist/index.cjs +1119 -0
- package/dist/index.d.cts +558 -0
- package/dist/index.d.ts +558 -0
- package/dist/index.js +1092 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
<!-- deno-fmt-ignore-file -->
|
|
2
|
+
|
|
3
|
+
@upyo/opentelemetry
|
|
4
|
+
===================
|
|
5
|
+
|
|
6
|
+
[![JSR][JSR badge]][JSR]
|
|
7
|
+
[![npm][npm badge]][npm]
|
|
8
|
+
|
|
9
|
+
OpenTelemetry observability transport for [Upyo] email library.
|
|
10
|
+
|
|
11
|
+
This package provides a decorator transport that wraps existing Upyo transports
|
|
12
|
+
to add automatic OpenTelemetry metrics and tracing without requiring changes to
|
|
13
|
+
existing code. It follows the decorator pattern, accepting any transport and
|
|
14
|
+
adding standardized observability features including email delivery metrics,
|
|
15
|
+
latency histograms, error classification, and distributed tracing support.
|
|
16
|
+
|
|
17
|
+
[JSR]: https://jsr.io/@upyo/opentelemetry
|
|
18
|
+
[JSR badge]: https://jsr.io/badges/@upyo/opentelemetry
|
|
19
|
+
[npm]: https://www.npmjs.com/package/@upyo/opentelemetry
|
|
20
|
+
[npm badge]: https://img.shields.io/npm/v/@upyo/opentelemetry?logo=npm
|
|
21
|
+
[Upyo]: https://upyo.org/
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Features
|
|
25
|
+
--------
|
|
26
|
+
|
|
27
|
+
- Zero-code observability: Wrap any existing Upyo transport with OpenTelemetry
|
|
28
|
+
instrumentation
|
|
29
|
+
- Comprehensive metrics: Email delivery counters, duration histograms,
|
|
30
|
+
message size tracking, and active operation gauges
|
|
31
|
+
- Distributed tracing: Automatic span creation with semantic attributes
|
|
32
|
+
following OpenTelemetry conventions
|
|
33
|
+
- Error classification: Intelligent categorization of email delivery failures
|
|
34
|
+
(auth, rate_limit, network, etc.)
|
|
35
|
+
- Performance optimized: Configurable sampling rates and feature toggles for
|
|
36
|
+
minimal overhead
|
|
37
|
+
- Cross-runtime compatible: Works on Node.js, Deno, Bun, and edge functions
|
|
38
|
+
- Flexible configuration: Support both manual provider injection and
|
|
39
|
+
auto-configuration helpers
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
Installation
|
|
43
|
+
------------
|
|
44
|
+
|
|
45
|
+
~~~~ sh
|
|
46
|
+
npm add @upyo/core @upyo/opentelemetry @opentelemetry/api
|
|
47
|
+
pnpm add @upyo/core @upyo/opentelemetry @opentelemetry/api
|
|
48
|
+
yarn add @upyo/core @upyo/opentelemetry @opentelemetry/api
|
|
49
|
+
deno add --jsr @upyo/core @upyo/opentelemetry
|
|
50
|
+
bun add @upyo/core @upyo/opentelemetry @opentelemetry/api
|
|
51
|
+
~~~~
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
Basic Usage
|
|
55
|
+
-----------
|
|
56
|
+
|
|
57
|
+
~~~~ typescript
|
|
58
|
+
import { MailgunTransport } from "@upyo/mailgun";
|
|
59
|
+
import { OpenTelemetryTransport } from "@upyo/opentelemetry";
|
|
60
|
+
import { trace, metrics } from "@opentelemetry/api";
|
|
61
|
+
|
|
62
|
+
// Create your base transport
|
|
63
|
+
const baseTransport = new MailgunTransport({
|
|
64
|
+
apiKey: "your-api-key",
|
|
65
|
+
domain: "your-domain.com",
|
|
66
|
+
region: "us"
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Wrap with OpenTelemetry observability
|
|
70
|
+
const transport = new OpenTelemetryTransport(baseTransport, {
|
|
71
|
+
tracerProvider: trace.getTracerProvider(),
|
|
72
|
+
meterProvider: metrics.getMeterProvider(),
|
|
73
|
+
metrics: { enabled: true },
|
|
74
|
+
tracing: { enabled: true }
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Use exactly like any other transport
|
|
78
|
+
const receipt = await transport.send(message);
|
|
79
|
+
if (receipt.successful) {
|
|
80
|
+
console.log('Message sent with ID:', receipt.messageId);
|
|
81
|
+
} else {
|
|
82
|
+
console.error('Send failed:', receipt.errorMessages.join(', '));
|
|
83
|
+
}
|
|
84
|
+
~~~~
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
Factory Function
|
|
88
|
+
----------------
|
|
89
|
+
|
|
90
|
+
For simplified setup, use the factory function:
|
|
91
|
+
|
|
92
|
+
~~~~ typescript
|
|
93
|
+
import { createOpenTelemetryTransport } from "@upyo/opentelemetry";
|
|
94
|
+
|
|
95
|
+
const transport = createOpenTelemetryTransport(baseTransport, {
|
|
96
|
+
serviceName: "email-service",
|
|
97
|
+
serviceVersion: "1.0.0",
|
|
98
|
+
metrics: { prefix: "myapp" },
|
|
99
|
+
tracing: { recordSensitiveData: false }
|
|
100
|
+
});
|
|
101
|
+
~~~~
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
Auto-Configuration
|
|
105
|
+
------------------
|
|
106
|
+
|
|
107
|
+
For environments where you want automatic OpenTelemetry setup:
|
|
108
|
+
|
|
109
|
+
~~~~ typescript
|
|
110
|
+
import { createOpenTelemetryTransport } from "@upyo/opentelemetry";
|
|
111
|
+
|
|
112
|
+
const transport = createOpenTelemetryTransport(baseTransport, {
|
|
113
|
+
serviceName: "email-service",
|
|
114
|
+
auto: {
|
|
115
|
+
tracing: { endpoint: "http://jaeger:14268/api/traces" },
|
|
116
|
+
metrics: { endpoint: "http://prometheus:9090/api/v1/write" }
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
~~~~
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
Resource Management
|
|
123
|
+
-------------------
|
|
124
|
+
|
|
125
|
+
The OpenTelemetryTransport implements `AsyncDisposable` and automatically
|
|
126
|
+
handles cleanup of wrapped transports:
|
|
127
|
+
|
|
128
|
+
~~~~ typescript
|
|
129
|
+
// Using with explicit disposal
|
|
130
|
+
const transport = new OpenTelemetryTransport(smtpTransport, config);
|
|
131
|
+
try {
|
|
132
|
+
await transport.send(message);
|
|
133
|
+
} finally {
|
|
134
|
+
await transport[Symbol.asyncDispose]();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Using with 'using' statement (when available)
|
|
138
|
+
{
|
|
139
|
+
using transport = new OpenTelemetryTransport(smtpTransport, config);
|
|
140
|
+
await transport.send(message);
|
|
141
|
+
// Automatically disposed at end of scope
|
|
142
|
+
}
|
|
143
|
+
~~~~
|
|
144
|
+
|
|
145
|
+
**Disposal Priority:**
|
|
146
|
+
|
|
147
|
+
1. If wrapped transport supports `AsyncDisposable` → calls `[Symbol.asyncDispose]()`
|
|
148
|
+
2. If wrapped transport supports `Disposable` → calls `[Symbol.dispose]()`
|
|
149
|
+
3. If wrapped transport supports neither → no-op (no error thrown)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
Configuration
|
|
153
|
+
-------------
|
|
154
|
+
|
|
155
|
+
### `OpenTelemetryConfig`
|
|
156
|
+
|
|
157
|
+
| Option | Type | Default | Description |
|
|
158
|
+
| -------------------- | ---------------- | ------------------------ | ----------------------------------------------------------- |
|
|
159
|
+
| `tracerProvider` | `TracerProvider` | | OpenTelemetry tracer provider (required if tracing enabled) |
|
|
160
|
+
| `meterProvider` | `MeterProvider` | | OpenTelemetry meter provider (required if metrics enabled) |
|
|
161
|
+
| `metrics` | `MetricsConfig` | `{ enabled: true }` | Metrics collection configuration |
|
|
162
|
+
| `tracing` | `TracingConfig` | `{ enabled: true }` | Tracing configuration |
|
|
163
|
+
| `attributeExtractor` | `Function` | | Custom attribute extractor function |
|
|
164
|
+
| `errorClassifier` | `Function` | `defaultErrorClassifier` | Custom error classifier function |
|
|
165
|
+
| `auto` | `AutoConfig` | | Auto-configuration options |
|
|
166
|
+
|
|
167
|
+
### `MetricsConfig`
|
|
168
|
+
|
|
169
|
+
| Option | Type | Default | Description |
|
|
170
|
+
| ----------------- | ---------- | --------------------- | -------------------------------------- |
|
|
171
|
+
| `enabled` | `boolean` | `true` | Whether metrics collection is enabled |
|
|
172
|
+
| `samplingRate` | `number` | `1.0` | Sampling rate (0.0 to 1.0) |
|
|
173
|
+
| `prefix` | `string` | `"upyo"` | Prefix for metric names |
|
|
174
|
+
| `durationBuckets` | `number[]` | `[0.001, 0.005, ...]` | Histogram buckets for duration metrics |
|
|
175
|
+
|
|
176
|
+
### `TracingConfig`
|
|
177
|
+
|
|
178
|
+
| Option | Type | Default | Description |
|
|
179
|
+
| --------------------- | --------- | --------- | ---------------------------------------------- |
|
|
180
|
+
| `enabled` | `boolean` | `true` | Whether tracing is enabled |
|
|
181
|
+
| `samplingRate` | `number` | `1.0` | Sampling rate (0.0 to 1.0) |
|
|
182
|
+
| `recordSensitiveData` | `boolean` | `false` | Whether to record email addresses and subjects |
|
|
183
|
+
| `spanPrefix` | `string` | `"email"` | Prefix for span names |
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
Telemetry Data
|
|
187
|
+
--------------
|
|
188
|
+
|
|
189
|
+
### Metrics
|
|
190
|
+
|
|
191
|
+
The transport collects the following metrics:
|
|
192
|
+
|
|
193
|
+
| Metric Name | Type | Labels | Description |
|
|
194
|
+
| ------------------------------- | --------- | ----------------------------------- | -------------------------------- |
|
|
195
|
+
| `upyo_email_attempts_total` | Counter | `transport`, `status`, `error_type` | Total email send attempts |
|
|
196
|
+
| `upyo_email_messages_total` | Counter | `transport`, `priority` | Total email messages processed |
|
|
197
|
+
| `upyo_email_duration_seconds` | Histogram | `transport`, `operation` | Duration of email operations |
|
|
198
|
+
| `upyo_email_message_size_bytes` | Histogram | `transport`, `content_type` | Size of email messages |
|
|
199
|
+
| `upyo_email_attachments_count` | Histogram | `transport` | Number of attachments per email |
|
|
200
|
+
| `upyo_email_active_sends` | Gauge | `transport` | Currently active send operations |
|
|
201
|
+
|
|
202
|
+
### Span Attributes
|
|
203
|
+
|
|
204
|
+
The transport creates spans with the following attributes:
|
|
205
|
+
|
|
206
|
+
#### General Operation Attributes
|
|
207
|
+
|
|
208
|
+
| Attribute | Type | Description |
|
|
209
|
+
| ---------------- | -------- | ------------------------------------------------- |
|
|
210
|
+
| `operation.name` | `string` | Operation name (`email.send`, `email.send_batch`) |
|
|
211
|
+
| `operation.type` | `string` | Always `"email"` |
|
|
212
|
+
|
|
213
|
+
#### Network Attributes
|
|
214
|
+
|
|
215
|
+
| Attribute | Type | Description |
|
|
216
|
+
| ----------------------- | -------- | ---------------------------------- |
|
|
217
|
+
| `network.protocol.name` | `string` | Protocol (`smtp`, `https`, `http`) |
|
|
218
|
+
| `server.address` | `string` | Server hostname |
|
|
219
|
+
| `server.port` | `number` | Server port |
|
|
220
|
+
|
|
221
|
+
#### Email-Specific Attributes
|
|
222
|
+
|
|
223
|
+
| Attribute | Type | Description |
|
|
224
|
+
| ------------------------- | -------- | ----------------------------------------------- |
|
|
225
|
+
| `email.from.address` | `string` | Sender email (if `recordSensitiveData: true`) |
|
|
226
|
+
| `email.from.domain` | `string` | Sender domain (if `recordSensitiveData: false`) |
|
|
227
|
+
| `email.to.count` | `number` | Number of recipients |
|
|
228
|
+
| `email.cc.count` | `number` | Number of CC recipients |
|
|
229
|
+
| `email.bcc.count` | `number` | Number of BCC recipients |
|
|
230
|
+
| `email.subject.length` | `number` | Length of subject line |
|
|
231
|
+
| `email.attachments.count` | `number` | Number of attachments |
|
|
232
|
+
| `email.message.size` | `number` | Estimated message size in bytes |
|
|
233
|
+
| `email.content.type` | `string` | Content type (`html`, `text`, `multipart`) |
|
|
234
|
+
| `email.priority` | `string` | Message priority (`high`, `normal`, `low`) |
|
|
235
|
+
| `email.tags` | `string` | JSON array of message tags |
|
|
236
|
+
|
|
237
|
+
#### Upyo-Specific Attributes
|
|
238
|
+
|
|
239
|
+
| Attribute | Type | Description |
|
|
240
|
+
| ------------------------ | -------- | ---------------------------------------- |
|
|
241
|
+
| `upyo.transport.name` | `string` | Transport type (`mailgun`, `smtp`, etc.) |
|
|
242
|
+
| `upyo.transport.version` | `string` | Transport version |
|
|
243
|
+
| `upyo.message.id` | `string` | Message ID from successful sends |
|
|
244
|
+
| `upyo.retry.count` | `number` | Number of retry attempts |
|
|
245
|
+
| `upyo.batch.size` | `number` | Batch size for batch operations |
|
|
246
|
+
|
|
247
|
+
### Span Events
|
|
248
|
+
|
|
249
|
+
| Event Name | Description | Attributes |
|
|
250
|
+
| ------------------- | ------------------------- | ------------------------------------- |
|
|
251
|
+
| `email.sent` | Email successfully sent | `message.id` |
|
|
252
|
+
| `email.send_failed` | Email send failed | `error.count`, `error.messages` |
|
|
253
|
+
| `exception` | Exception occurred | `exception.type`, `exception.message` |
|
|
254
|
+
| `retry` | Retry attempt | `retry.attempt`, `retry.reason` |
|
|
255
|
+
| `partial_success` | Batch partially succeeded | `success_count`, `failure_count` |
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
Error Classification
|
|
259
|
+
--------------------
|
|
260
|
+
|
|
261
|
+
The transport automatically classifies errors into standard categories:
|
|
262
|
+
|
|
263
|
+
| Category | Description | Example Errors |
|
|
264
|
+
| --------------------- | ----------------------- | --------------------------------------- |
|
|
265
|
+
| `auth` | Authentication failures | Invalid API key, unauthorized |
|
|
266
|
+
| `rate_limit` | Rate limiting | Quota exceeded, too many requests |
|
|
267
|
+
| `network` | Network connectivity | Timeout, DNS resolution, abort |
|
|
268
|
+
| `validation` | Input validation | Invalid email format, malformed request |
|
|
269
|
+
| `service_unavailable` | Service outages | HTTP 503, temporarily unavailable |
|
|
270
|
+
| `server_error` | Server errors | HTTP 500, internal server error |
|
|
271
|
+
| `unknown` | Unclassified errors | Any other errors |
|
|
272
|
+
|
|
273
|
+
### Custom Error Classification
|
|
274
|
+
|
|
275
|
+
You can provide a custom error classifier:
|
|
276
|
+
|
|
277
|
+
~~~~ typescript
|
|
278
|
+
import { createErrorClassifier } from "@upyo/opentelemetry";
|
|
279
|
+
|
|
280
|
+
const customClassifier = createErrorClassifier({
|
|
281
|
+
patterns: {
|
|
282
|
+
"spam": /spam|blocked|reputation/i,
|
|
283
|
+
"bounce": /bounce|undeliverable|invalid.*recipient/i,
|
|
284
|
+
},
|
|
285
|
+
fallback: "email_error"
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const transport = new OpenTelemetryTransport(baseTransport, {
|
|
289
|
+
errorClassifier: customClassifier,
|
|
290
|
+
// ... other config
|
|
291
|
+
});
|
|
292
|
+
~~~~
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
Custom Attributes
|
|
296
|
+
-----------------
|
|
297
|
+
|
|
298
|
+
Add custom attributes to spans and metrics:
|
|
299
|
+
|
|
300
|
+
~~~~ typescript
|
|
301
|
+
import { createEmailAttributeExtractor } from "@upyo/opentelemetry";
|
|
302
|
+
|
|
303
|
+
const customExtractor = createEmailAttributeExtractor("my-transport", {
|
|
304
|
+
customAttributes: (operation, transportName, messageCount, totalSize) => ({
|
|
305
|
+
"app.version": "1.0.0",
|
|
306
|
+
"app.environment": process.env.NODE_ENV,
|
|
307
|
+
"deployment.id": process.env.DEPLOYMENT_ID,
|
|
308
|
+
})
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const transport = new OpenTelemetryTransport(baseTransport, {
|
|
312
|
+
attributeExtractor: customExtractor,
|
|
313
|
+
// ... other config
|
|
314
|
+
});
|
|
315
|
+
~~~~
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
Performance Considerations
|
|
319
|
+
--------------------------
|
|
320
|
+
|
|
321
|
+
### Sampling
|
|
322
|
+
|
|
323
|
+
Control overhead with sampling rates:
|
|
324
|
+
|
|
325
|
+
~~~~ typescript
|
|
326
|
+
const transport = new OpenTelemetryTransport(baseTransport, {
|
|
327
|
+
metrics: {
|
|
328
|
+
enabled: true,
|
|
329
|
+
samplingRate: 0.1 // Sample 10% of operations
|
|
330
|
+
},
|
|
331
|
+
tracing: {
|
|
332
|
+
enabled: true,
|
|
333
|
+
samplingRate: 0.05 // Sample 5% of operations
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
~~~~
|
|
337
|
+
|
|
338
|
+
### Feature Toggles
|
|
339
|
+
|
|
340
|
+
Disable features selectively:
|
|
341
|
+
|
|
342
|
+
~~~~ typescript
|
|
343
|
+
// Metrics only, no tracing
|
|
344
|
+
const metricsOnlyTransport = new OpenTelemetryTransport(baseTransport, {
|
|
345
|
+
meterProvider: metrics.getMeterProvider(),
|
|
346
|
+
metrics: { enabled: true },
|
|
347
|
+
tracing: { enabled: false }
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Tracing only, no metrics
|
|
351
|
+
const tracingOnlyTransport = new OpenTelemetryTransport(baseTransport, {
|
|
352
|
+
tracerProvider: trace.getTracerProvider(),
|
|
353
|
+
tracing: { enabled: true },
|
|
354
|
+
metrics: { enabled: false }
|
|
355
|
+
});
|
|
356
|
+
~~~~
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
Monitoring Examples
|
|
360
|
+
-------------------
|
|
361
|
+
|
|
362
|
+
### Prometheus Queries
|
|
363
|
+
|
|
364
|
+
~~~~ promql
|
|
365
|
+
# Email delivery success rate
|
|
366
|
+
rate(upyo_email_attempts_total{status="success"}[5m]) /
|
|
367
|
+
rate(upyo_email_attempts_total[5m])
|
|
368
|
+
|
|
369
|
+
# Average email send duration
|
|
370
|
+
rate(upyo_email_duration_seconds_sum[5m]) /
|
|
371
|
+
rate(upyo_email_duration_seconds_count[5m])
|
|
372
|
+
|
|
373
|
+
# Error rate by transport
|
|
374
|
+
rate(upyo_email_attempts_total{status="failure"}[5m]) by (transport, error_type)
|
|
375
|
+
|
|
376
|
+
# Active email sending operations
|
|
377
|
+
upyo_email_active_sends
|
|
378
|
+
~~~~
|
|
379
|
+
|
|
380
|
+
### Grafana Dashboard Panels
|
|
381
|
+
|
|
382
|
+
~~~~ json
|
|
383
|
+
{
|
|
384
|
+
"title": "Email Delivery Success Rate",
|
|
385
|
+
"type": "stat",
|
|
386
|
+
"targets": [{
|
|
387
|
+
"expr": "rate(upyo_email_attempts_total{status=\"success\"}[5m]) / rate(upyo_email_attempts_total[5m])",
|
|
388
|
+
"format": "time_series"
|
|
389
|
+
}]
|
|
390
|
+
}
|
|
391
|
+
~~~~
|
|
392
|
+
|
|
393
|
+
### Alerting Rules
|
|
394
|
+
|
|
395
|
+
~~~~ yaml
|
|
396
|
+
groups:
|
|
397
|
+
- name: email_alerts
|
|
398
|
+
rules:
|
|
399
|
+
- alert: EmailDeliveryFailureRate
|
|
400
|
+
expr: |
|
|
401
|
+
(
|
|
402
|
+
rate(upyo_email_attempts_total{status="failure"}[5m]) /
|
|
403
|
+
rate(upyo_email_attempts_total[5m])
|
|
404
|
+
) > 0.05
|
|
405
|
+
for: 2m
|
|
406
|
+
labels:
|
|
407
|
+
severity: warning
|
|
408
|
+
annotations:
|
|
409
|
+
summary: "High email delivery failure rate"
|
|
410
|
+
description: "Email failure rate is {{ $value | humanizePercentage }} for transport {{ $labels.transport }}"
|
|
411
|
+
|
|
412
|
+
- alert: EmailSendDurationHigh
|
|
413
|
+
expr: |
|
|
414
|
+
histogram_quantile(0.95, rate(upyo_email_duration_seconds_bucket[5m])) > 10
|
|
415
|
+
for: 5m
|
|
416
|
+
labels:
|
|
417
|
+
severity: warning
|
|
418
|
+
annotations:
|
|
419
|
+
summary: "High email send duration"
|
|
420
|
+
description: "95th percentile email send duration is {{ $value }}s"
|
|
421
|
+
~~~~
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
Cross-Runtime Compatibility
|
|
425
|
+
---------------------------
|
|
426
|
+
|
|
427
|
+
This package works across all JavaScript runtimes:
|
|
428
|
+
|
|
429
|
+
- **Node.js**: Full OpenTelemetry ecosystem support
|
|
430
|
+
- **Deno**: Native ESM and web standards compatibility
|
|
431
|
+
- **Bun**: High-performance runtime optimizations
|
|
432
|
+
- **Edge functions**: Minimal overhead for serverless environments
|
|
433
|
+
|
|
434
|
+
Resource cleanup is handled automatically via `AsyncDisposable` when supported:
|
|
435
|
+
|
|
436
|
+
~~~~ typescript
|
|
437
|
+
// Automatic cleanup with using statement (Node.js 20+, modern browsers)
|
|
438
|
+
await using transport = new OpenTelemetryTransport(baseTransport, config);
|
|
439
|
+
await transport.send(message);
|
|
440
|
+
// Transport is automatically disposed here
|
|
441
|
+
|
|
442
|
+
// Manual cleanup for older environments
|
|
443
|
+
const transport = new OpenTelemetryTransport(baseTransport, config);
|
|
444
|
+
try {
|
|
445
|
+
await transport.send(message);
|
|
446
|
+
} finally {
|
|
447
|
+
await transport[Symbol.asyncDispose]();
|
|
448
|
+
}
|
|
449
|
+
~~~~
|