autotel 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -8
- package/dist/auto.cjs +5 -5
- package/dist/auto.js +3 -3
- package/dist/{chunk-EETEPDW2.cjs → chunk-2WSBYOW7.cjs} +9 -9
- package/dist/{chunk-EETEPDW2.cjs.map → chunk-2WSBYOW7.cjs.map} +1 -1
- package/dist/{chunk-M4K4GMI7.cjs → chunk-5JSIRHVW.cjs} +22 -22
- package/dist/{chunk-M4K4GMI7.cjs.map → chunk-5JSIRHVW.cjs.map} +1 -1
- package/dist/{chunk-AYJ27WRH.cjs → chunk-CMWDPNRB.cjs} +15 -6
- package/dist/chunk-CMWDPNRB.cjs.map +1 -0
- package/dist/chunk-DPP5Y5XN.cjs +167 -0
- package/dist/chunk-DPP5Y5XN.cjs.map +1 -0
- package/dist/{chunk-MX7AH3K7.cjs → chunk-EDJKNUGP.cjs} +73 -42
- package/dist/chunk-EDJKNUGP.cjs.map +1 -0
- package/dist/{chunk-DNYKJR3M.js → chunk-EKU6O7WG.js} +15 -6
- package/dist/chunk-EKU6O7WG.js.map +1 -0
- package/dist/{chunk-PTMQAULX.js → chunk-HRL4GTXD.js} +3 -3
- package/dist/{chunk-PTMQAULX.js.map → chunk-HRL4GTXD.js.map} +1 -1
- package/dist/{chunk-MAAPH5NI.js → chunk-MHGJOJZW.js} +3 -3
- package/dist/{chunk-MAAPH5NI.js.map → chunk-MHGJOJZW.js.map} +1 -1
- package/dist/chunk-NGEG2JQ5.js +159 -0
- package/dist/chunk-NGEG2JQ5.js.map +1 -0
- package/dist/{chunk-NQXRWF3V.js → chunk-UHCAPEP7.js} +68 -37
- package/dist/chunk-UHCAPEP7.js.map +1 -0
- package/dist/{chunk-PCFUNQCQ.js → chunk-VL63L5JL.js} +3 -3
- package/dist/{chunk-PCFUNQCQ.js.map → chunk-VL63L5JL.js.map} +1 -1
- package/dist/{chunk-UUL3EEY4.cjs → chunk-X2ZZ65N4.cjs} +7 -7
- package/dist/{chunk-UUL3EEY4.cjs.map → chunk-X2ZZ65N4.cjs.map} +1 -1
- package/dist/decorators.cjs +4 -4
- package/dist/decorators.js +4 -4
- package/dist/event.cjs +7 -7
- package/dist/event.js +4 -4
- package/dist/functional.cjs +11 -11
- package/dist/functional.js +4 -4
- package/dist/index.cjs +32 -32
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -9
- package/dist/{init-ChicO1u-.d.ts → init-CDiC7CVz.d.ts} +75 -26
- package/dist/{init-CqBWkMZB.d.cts → init-Cj2D8f1S.d.cts} +75 -26
- package/dist/instrumentation.cjs +16 -13
- package/dist/instrumentation.cjs.map +1 -1
- package/dist/instrumentation.js +9 -6
- package/dist/instrumentation.js.map +1 -1
- package/dist/logger.cjs +23 -3
- package/dist/logger.d.cts +156 -8
- package/dist/logger.d.ts +156 -8
- package/dist/logger.js +1 -1
- package/dist/metric.cjs +1 -1
- package/dist/metric.js +1 -1
- package/dist/register.cjs +2 -6
- package/dist/register.cjs.map +1 -1
- package/dist/register.d.cts +1 -29
- package/dist/register.d.ts +1 -29
- package/dist/register.js +2 -6
- package/dist/register.js.map +1 -1
- package/dist/sampling.cjs +1 -1
- package/dist/sampling.js +1 -1
- package/dist/semantic-helpers.cjs +9 -9
- package/dist/semantic-helpers.js +5 -5
- package/dist/testing.cjs +1 -1
- package/dist/testing.js +1 -1
- package/dist/yaml-config.cjs +4 -4
- package/dist/yaml-config.d.cts +1 -1
- package/dist/yaml-config.d.ts +1 -1
- package/dist/yaml-config.js +1 -1
- package/package.json +17 -18
- package/src/autotel-logger.test.ts +440 -0
- package/src/autotel-logger.ts +257 -0
- package/src/http.test.ts +4 -6
- package/src/init.customization.test.ts +1 -1
- package/src/init.integrations.test.ts +43 -21
- package/src/init.openllmetry.test.ts +1 -1
- package/src/init.ts +136 -84
- package/src/instrumentation.ts +10 -8
- package/src/logger.ts +51 -7
- package/src/register.ts +15 -19
- package/src/yaml-config.ts +16 -1
- package/dist/chunk-4OAT42CA.cjs +0 -73
- package/dist/chunk-4OAT42CA.cjs.map +0 -1
- package/dist/chunk-5GWX5LFW.js +0 -70
- package/dist/chunk-5GWX5LFW.js.map +0 -1
- package/dist/chunk-AYJ27WRH.cjs.map +0 -1
- package/dist/chunk-DNYKJR3M.js.map +0 -1
- package/dist/chunk-MX7AH3K7.cjs.map +0 -1
- package/dist/chunk-NQXRWF3V.js.map +0 -1
package/README.md
CHANGED
|
@@ -831,7 +831,38 @@ init({
|
|
|
831
831
|
|
|
832
832
|
OpenTelemetry's auto-instrumentation packages require special setup depending on your module system:
|
|
833
833
|
|
|
834
|
-
**
|
|
834
|
+
**ESM Setup (Recommended for Node 18.19+)**
|
|
835
|
+
|
|
836
|
+
Use `autotel/register` for clean ESM instrumentation without complex `NODE_OPTIONS`:
|
|
837
|
+
|
|
838
|
+
```typescript
|
|
839
|
+
// instrumentation.mjs (or .ts)
|
|
840
|
+
import 'autotel/register'; // MUST be first import!
|
|
841
|
+
import { init } from 'autotel';
|
|
842
|
+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
843
|
+
|
|
844
|
+
init({
|
|
845
|
+
service: 'my-app',
|
|
846
|
+
instrumentations: getNodeAutoInstrumentations({
|
|
847
|
+
'@opentelemetry/instrumentation-pino': { enabled: true },
|
|
848
|
+
}),
|
|
849
|
+
});
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
```bash
|
|
853
|
+
# Run with --import flag
|
|
854
|
+
tsx --import ./instrumentation.mjs src/server.ts
|
|
855
|
+
# or with Node
|
|
856
|
+
node --import ./instrumentation.mjs src/server.js
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
**Requirements for ESM instrumentation:**
|
|
860
|
+
|
|
861
|
+
- Install `@opentelemetry/auto-instrumentations-node` as a **direct dependency** in your app
|
|
862
|
+
- Import `autotel/register` **before** any other imports
|
|
863
|
+
- Use `--import` flag (not `--require`)
|
|
864
|
+
|
|
865
|
+
**CommonJS Setup**
|
|
835
866
|
|
|
836
867
|
No special flags required. Just use `--require`:
|
|
837
868
|
|
|
@@ -846,21 +877,21 @@ No special flags required. Just use `--require`:
|
|
|
846
877
|
node --require ./instrumentation.js src/server.js
|
|
847
878
|
```
|
|
848
879
|
|
|
849
|
-
**ESM (
|
|
850
|
-
|
|
851
|
-
If you need ESM, use the `--experimental-loader` flag:
|
|
880
|
+
**Zero-Config ESM (reads from env vars):**
|
|
852
881
|
|
|
853
882
|
```bash
|
|
854
|
-
|
|
883
|
+
OTEL_SERVICE_NAME=my-app tsx --import autotel/auto src/index.ts
|
|
855
884
|
```
|
|
856
885
|
|
|
857
|
-
|
|
886
|
+
**Legacy ESM (Node 18.0-18.18)**
|
|
887
|
+
|
|
888
|
+
If you can't use `autotel/register`, use the `--experimental-loader` flag:
|
|
858
889
|
|
|
859
890
|
```bash
|
|
860
891
|
NODE_OPTIONS="--experimental-loader=@opentelemetry/instrumentation/hook.mjs --import ./instrumentation.ts" tsx src/server.ts
|
|
861
892
|
```
|
|
862
893
|
|
|
863
|
-
**Note:** The loader hook is an OpenTelemetry upstream requirement for ESM, not an autotel limitation.
|
|
894
|
+
**Note:** The loader hook is an OpenTelemetry upstream requirement for ESM, not an autotel limitation. See [OpenTelemetry ESM docs](https://opentelemetry.io/docs/languages/js/getting-started/nodejs/#esm-support) for details.
|
|
864
895
|
|
|
865
896
|
## Operational Safety & Runtime Controls
|
|
866
897
|
|
|
@@ -873,7 +904,7 @@ NODE_OPTIONS="--experimental-loader=@opentelemetry/instrumentation/hook.mjs --im
|
|
|
873
904
|
|
|
874
905
|
```bash
|
|
875
906
|
# Disable metrics without touching code (metrics are ON by default)
|
|
876
|
-
|
|
907
|
+
AUTOTEL_METRICS=off node server.js
|
|
877
908
|
|
|
878
909
|
# Point at a different collector
|
|
879
910
|
OTLP_ENDPOINT=https://otel.mycompany.com node server.js
|
package/dist/auto.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkEDJKNUGP_cjs = require('./chunk-EDJKNUGP.cjs');
|
|
4
|
+
var chunkCMWDPNRB_cjs = require('./chunk-CMWDPNRB.cjs');
|
|
5
5
|
require('./chunk-GVLK7YUU.cjs');
|
|
6
6
|
require('./chunk-HE6T6FIX.cjs');
|
|
7
|
-
require('./chunk-
|
|
7
|
+
require('./chunk-DPP5Y5XN.cjs');
|
|
8
8
|
require('./chunk-Y4Y2S7BM.cjs');
|
|
9
9
|
require('./chunk-URRW6M2C.cjs');
|
|
10
10
|
require('./chunk-G7VZBCD6.cjs');
|
|
@@ -14,10 +14,10 @@ var importInTheMiddle = require('import-in-the-middle');
|
|
|
14
14
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
15
|
var { registerOptions } = importInTheMiddle.createAddHookMessageChannel();
|
|
16
16
|
module$1.register("import-in-the-middle/hook.mjs", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('auto.cjs', document.baseURI).href)), registerOptions);
|
|
17
|
-
var yamlConfig =
|
|
17
|
+
var yamlConfig = chunkCMWDPNRB_cjs.loadYamlConfig();
|
|
18
18
|
var integrationsEnv = process.env.AUTOTEL_INTEGRATIONS;
|
|
19
19
|
var integrations = integrationsEnv === "true" ? true : integrationsEnv ? integrationsEnv.split(",").map((s) => s.trim()) : yamlConfig?.integrations ?? ["http", "express"];
|
|
20
|
-
|
|
20
|
+
chunkEDJKNUGP_cjs.init({
|
|
21
21
|
service: yamlConfig?.service ?? process.env.OTEL_SERVICE_NAME ?? "unknown-service",
|
|
22
22
|
debug: yamlConfig?.debug ?? process.env.AUTOTEL_DEBUG === "true",
|
|
23
23
|
integrations
|
package/dist/auto.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { init } from './chunk-
|
|
2
|
-
import { loadYamlConfig } from './chunk-
|
|
1
|
+
import { init } from './chunk-UHCAPEP7.js';
|
|
2
|
+
import { loadYamlConfig } from './chunk-EKU6O7WG.js';
|
|
3
3
|
import './chunk-X4RMFFMR.js';
|
|
4
4
|
import './chunk-5R2M36QB.js';
|
|
5
|
-
import './chunk-
|
|
5
|
+
import './chunk-NGEG2JQ5.js';
|
|
6
6
|
import './chunk-KVGNW3FC.js';
|
|
7
7
|
import './chunk-P6JUDYNO.js';
|
|
8
8
|
import './chunk-Z6ZWNWWR.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkYLPNXZFI_cjs = require('./chunk-YLPNXZFI.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkEDJKNUGP_cjs = require('./chunk-EDJKNUGP.cjs');
|
|
5
5
|
var api = require('@opentelemetry/api');
|
|
6
6
|
|
|
7
7
|
// src/circuit-breaker.ts
|
|
@@ -189,7 +189,7 @@ var Event = class {
|
|
|
189
189
|
this.serviceName = serviceName;
|
|
190
190
|
this.logger = options.logger;
|
|
191
191
|
this.collector = options.collector;
|
|
192
|
-
this.subscribers = options.subscribers === void 0 ?
|
|
192
|
+
this.subscribers = options.subscribers === void 0 ? chunkEDJKNUGP_cjs.getConfig()?.subscribers || [] : options.subscribers;
|
|
193
193
|
this.hasSubscribers = this.subscribers.length > 0;
|
|
194
194
|
this.circuitBreakers = /* @__PURE__ */ new Map();
|
|
195
195
|
for (const subscriber of this.subscribers) {
|
|
@@ -219,7 +219,7 @@ var Event = class {
|
|
|
219
219
|
service: this.serviceName,
|
|
220
220
|
...attributes
|
|
221
221
|
};
|
|
222
|
-
const config =
|
|
222
|
+
const config = chunkEDJKNUGP_cjs.getConfig();
|
|
223
223
|
if (config) {
|
|
224
224
|
if (config.version) {
|
|
225
225
|
enriched["service.version"] = config.version;
|
|
@@ -267,7 +267,7 @@ var Event = class {
|
|
|
267
267
|
* ```
|
|
268
268
|
*/
|
|
269
269
|
trackEvent(eventName, attributes) {
|
|
270
|
-
const validationConfig =
|
|
270
|
+
const validationConfig = chunkEDJKNUGP_cjs.getValidationConfig();
|
|
271
271
|
const validated = chunkYLPNXZFI_cjs.validateEvent(
|
|
272
272
|
eventName,
|
|
273
273
|
attributes,
|
|
@@ -305,12 +305,12 @@ var Event = class {
|
|
|
305
305
|
await circuitBreaker.execute(() => fn(subscriber));
|
|
306
306
|
} catch (error) {
|
|
307
307
|
if (error instanceof CircuitOpenError) {
|
|
308
|
-
|
|
308
|
+
chunkEDJKNUGP_cjs.getLogger().warn(`[Events] ${error.message}`, {
|
|
309
309
|
subscriberName: subscriber.name || "Unknown"
|
|
310
310
|
});
|
|
311
311
|
return;
|
|
312
312
|
}
|
|
313
|
-
|
|
313
|
+
chunkEDJKNUGP_cjs.getLogger().error(
|
|
314
314
|
`[Events] Subscriber ${subscriber.name || "Unknown"} failed`,
|
|
315
315
|
error instanceof Error ? error : void 0,
|
|
316
316
|
{ subscriberName: subscriber.name || "Unknown" }
|
|
@@ -469,7 +469,7 @@ var Event = class {
|
|
|
469
469
|
try {
|
|
470
470
|
await subscriber.shutdown();
|
|
471
471
|
} catch (error) {
|
|
472
|
-
|
|
472
|
+
chunkEDJKNUGP_cjs.getLogger().error(
|
|
473
473
|
`[Events] Failed to shutdown subscriber ${subscriber.name || "Unknown"}`,
|
|
474
474
|
error instanceof Error ? error : void 0,
|
|
475
475
|
{ subscriberName: subscriber.name || "Unknown" }
|
|
@@ -494,5 +494,5 @@ function resetEvents() {
|
|
|
494
494
|
exports.Event = Event;
|
|
495
495
|
exports.getEvents = getEvents;
|
|
496
496
|
exports.resetEvents = resetEvents;
|
|
497
|
-
//# sourceMappingURL=chunk-
|
|
498
|
-
//# sourceMappingURL=chunk-
|
|
497
|
+
//# sourceMappingURL=chunk-2WSBYOW7.cjs.map
|
|
498
|
+
//# sourceMappingURL=chunk-2WSBYOW7.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/circuit-breaker.ts","../src/event.ts"],"names":["getConfig","trace","getOperationContext","getValidationConfig","validateEvent","getLogger"],"mappings":"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","file":"chunk-EETEPDW2.cjs","sourcesContent":["/**\n * Circuit breaker for event subscribers\n *\n * Prevents cascading failures by fast-failing when an (subscriber) is unhealthy.\n * Uses the circuit breaker pattern with three states:\n * - CLOSED: Normal operation ((subscriber) working)\n * - OPEN: Fast-fail mode ((subscriber) down)\n * - HALF_OPEN: Testing if (subscriber) recovered\n */\n\nexport interface CircuitBreakerConfig {\n /** Number of failures before opening circuit (default: 5) */\n failureThreshold: number;\n /** Time to wait before trying again in ms (default: 30000 = 30s) */\n resetTimeout: number;\n /** Time window for counting failures in ms (default: 60000 = 1min) */\n windowSize: number;\n}\n\nconst DEFAULT_CONFIG: CircuitBreakerConfig = {\n failureThreshold: 5,\n resetTimeout: 30_000, // 30 seconds\n windowSize: 60_000, // 1 minute\n};\n\nexport type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';\n\nexport const CircuitState = {\n CLOSED: 'CLOSED' as const, // Normal operation\n OPEN: 'OPEN' as const, // Fast-fail mode\n HALF_OPEN: 'HALF_OPEN' as const, // Testing recovery\n} as const;\n\ninterface FailureRecord {\n timestamp: number;\n error: string;\n}\n\n/**\n * Circuit breaker implementation\n *\n * Tracks failures and automatically opens the circuit to prevent\n * overwhelming failing subscribers.\n */\nexport class CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failures: FailureRecord[] = [];\n private lastFailureTime: number = 0;\n private readonly config: CircuitBreakerConfig;\n private readonly name: string;\n\n constructor(name: string, config?: Partial<CircuitBreakerConfig>) {\n this.name = name;\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Execute a function with circuit breaker protection\n * Throws CircuitOpenError if circuit is open\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n // Check if circuit is open\n if (this.state === CircuitState.OPEN) {\n // Check if we should transition to half-open\n const now = Date.now();\n if (now - this.lastFailureTime >= this.config.resetTimeout) {\n this.state = CircuitState.HALF_OPEN;\n } else {\n throw new CircuitOpenError(\n `Circuit breaker is OPEN for ${this.name}. ` +\n `Will retry in ${Math.ceil((this.config.resetTimeout - (now - this.lastFailureTime)) / 1000)}s`,\n );\n }\n }\n\n try {\n const result = await fn();\n\n // Success! Close circuit if it was half-open\n if (this.state === CircuitState.HALF_OPEN) {\n this.reset();\n }\n\n return result;\n } catch (error) {\n this.recordFailure(error);\n throw error;\n }\n }\n\n /**\n * Record a failure and potentially open the circuit\n */\n private recordFailure(error: unknown): void {\n const now = Date.now();\n\n // Remove old failures outside the time window\n this.failures = this.failures.filter(\n (f) => now - f.timestamp < this.config.windowSize,\n );\n\n // Record new failure\n this.failures.push({\n timestamp: now,\n error: error instanceof Error ? error.message : String(error),\n });\n\n this.lastFailureTime = now;\n\n // Check if we should open the circuit\n if (this.failures.length >= this.config.failureThreshold) {\n if (this.state === CircuitState.HALF_OPEN) {\n // Failed during test - reopen circuit\n this.state = CircuitState.OPEN;\n } else if (this.state === CircuitState.CLOSED) {\n // Too many failures - open circuit\n this.state = CircuitState.OPEN;\n }\n }\n }\n\n /**\n * Reset the circuit breaker (on success)\n */\n private reset(): void {\n this.state = CircuitState.CLOSED;\n this.failures = [];\n this.lastFailureTime = 0;\n }\n\n /**\n * Get current state (for monitoring)\n */\n getState(): CircuitState {\n return this.state;\n }\n\n /**\n * Get failure count in current window\n */\n getFailureCount(): number {\n const now = Date.now();\n // Clean up old failures\n this.failures = this.failures.filter(\n (f) => now - f.timestamp < this.config.windowSize,\n );\n return this.failures.length;\n }\n\n /**\n * Get recent failures (for debugging)\n */\n getRecentFailures(): FailureRecord[] {\n const now = Date.now();\n return this.failures.filter(\n (f) => now - f.timestamp < this.config.windowSize,\n );\n }\n\n /**\n * Manually reset the circuit breaker (for testing or manual intervention)\n */\n forceReset(): void {\n this.reset();\n }\n\n /**\n * Manually open the circuit (for testing or manual intervention)\n */\n forceOpen(): void {\n this.state = CircuitState.OPEN;\n this.lastFailureTime = Date.now();\n }\n}\n\n/**\n * Error thrown when circuit is open\n */\nexport class CircuitOpenError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CircuitOpenError';\n }\n}\n","/**\n * Events API for product events platforms\n *\n * Track user behavior, business events, and critical actions.\n * Sends to product events platforms (PostHog, Mixpanel, Amplitude) via subscribers.\n * For business people who think in events/funnels.\n *\n * For OpenTelemetry metrics (Prometheus/Grafana), use the Metrics class instead.\n *\n * @example Recommended: Configure subscribers in init(), use track() function\n * ```typescript\n * import { init, track } from 'autotel';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * init({\n * service: 'my-app',\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_...' })]\n * });\n *\n * // Track events - uses subscribers from init()\n * track('application.submitted', { jobId: '123', userId: '456' });\n * ```\n *\n * @example Create Event instance (inherits subscribers from init)\n * ```typescript\n * import { Event } from 'autotel/event';\n *\n * // Uses subscribers configured in init()\n * const event = new Event('job-application');\n * event.trackEvent('application.submitted', { jobId: '123' });\n * ```\n *\n * @example Override subscribers for specific Event instance\n * ```typescript\n * import { Event } from 'autotel/event';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * // Override: use different subscribers for this instance\n * const event = new Event('job-application', {\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_different_project' })]\n * });\n *\n * event.trackEvent('application.submitted', { jobId: '123' });\n * ```\n */\n\nimport { trace } from '@opentelemetry/api';\nimport { type Logger } from './logger';\nimport { getLogger, getValidationConfig, getConfig } from './init';\nimport {\n type EventSubscriber,\n type EventAttributes,\n type FunnelStatus,\n type OutcomeStatus,\n} from './event-subscriber';\nimport { type EventCollector } from './event-testing';\nimport { CircuitBreaker, CircuitOpenError } from './circuit-breaker';\nimport { validateEvent } from './validation';\nimport { getOperationContext } from './operation-context';\n\n// Re-export types for convenience\nexport type {\n EventAttributes,\n FunnelStatus,\n OutcomeStatus,\n} from './event-subscriber';\n\n/**\n * Events class for tracking user behavior and product events\n *\n * Track critical indicators such as:\n * - User events (signups, purchases, feature usage)\n * - Conversion funnels (signup → activation → purchase)\n * - Business outcomes (success/failure rates)\n * - Product metrics (revenue, engagement, retention)\n *\n * All events are sent to events platforms via subscribers (PostHog, Mixpanel, etc.).\n * For OpenTelemetry metrics, use the Metrics class instead.\n */\n/**\n * Events options\n */\nexport interface EventsOptions {\n /** Optional logger for audit trail */\n logger?: Logger;\n /** Optional collector for testing (captures events in memory) */\n collector?: EventCollector;\n /**\n * Optional subscribers to send events to other platforms\n * (e.g., PostHog, Mixpanel, Amplitude)\n *\n * **Subscriber Resolution**:\n * - If provided → uses these subscribers (instance override)\n * - If not provided → falls back to subscribers from `init()` (global config)\n * - If neither → no subscribers (events logged only)\n *\n * Install `autotel-subscribers` package for ready-made subscribers\n */\n subscribers?: EventSubscriber[];\n}\n\nexport class Event {\n private serviceName: string;\n private logger?: Logger;\n private collector?: EventCollector;\n private subscribers: EventSubscriber[];\n private hasSubscribers: boolean; // Cached for performance\n private circuitBreakers: Map<EventSubscriber, CircuitBreaker>; // One per subscriber\n\n /**\n * Create a new Event instance\n *\n * **Note**: Most users should use `init()` + `track()` instead of creating Event instances directly.\n *\n * **Subscriber Resolution**:\n * - If `subscribers` provided in options → uses those (instance override)\n * - If `subscribers` not provided → falls back to subscribers from `init()` (global config)\n * - If neither → no subscribers (events logged only)\n *\n * @param serviceName - Service name for identifying events\n * @param options - Optional configuration (logger, collector, subscribers)\n *\n * @example Recommended: Use track() with init()\n * ```typescript\n * import { init, track } from 'autotel';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * init({\n * service: 'checkout',\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_...' })]\n * });\n *\n * track('purchase.completed', { amount: 99.99 });\n * ```\n *\n * @example Inherit subscribers from init()\n * ```typescript\n * // Uses subscribers configured in init()\n * const event = new Event('checkout');\n * event.trackEvent('purchase.completed', { amount: 99.99 });\n * ```\n *\n * @example Override subscribers for this instance\n * ```typescript\n * import { Event } from 'autotel/event';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * // Override: use different subscribers for this instance only\n * const event = new Event('checkout', {\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_different_project' })]\n * });\n * ```\n */\n constructor(serviceName: string, options: EventsOptions = {}) {\n this.serviceName = serviceName;\n this.logger = options.logger;\n this.collector = options.collector;\n\n // Subscriber resolution: instance-level overrides global init() config\n // If subscribers provided to constructor, use those\n // Otherwise, fall back to subscribers from init()\n this.subscribers =\n options.subscribers === undefined\n ? getConfig()?.subscribers || []\n : options.subscribers;\n\n this.hasSubscribers = this.subscribers.length > 0; // Cache for hot path\n\n // Create circuit breaker for each subscriber\n this.circuitBreakers = new Map();\n for (const subscriber of this.subscribers) {\n const subscriberName = subscriber.name || 'Unknown';\n this.circuitBreakers.set(\n subscriber,\n new CircuitBreaker(subscriberName, {\n failureThreshold: 5,\n resetTimeout: 30_000, // 30s\n windowSize: 60_000, // 1min\n }),\n );\n }\n }\n\n /**\n * Automatically enrich attributes with all available telemetry context\n *\n * Auto-captures:\n * - Resource attributes: service.version, deployment.environment\n * - Trace context: traceId, spanId, correlationId\n * - Operation context: operation.name\n */\n private enrichWithTelemetryContext(\n attributes: EventAttributes = {},\n ): EventAttributes {\n const enriched: EventAttributes = {\n service: this.serviceName,\n ...attributes,\n };\n\n // 1. Resource attributes (service-level context)\n const config = getConfig();\n if (config) {\n if (config.version) {\n enriched['service.version'] = config.version;\n }\n if (config.environment) {\n enriched['deployment.environment'] = config.environment;\n }\n }\n\n // 2. Trace context (if inside a traced operation)\n const span = trace.getActiveSpan();\n const spanContext = span?.spanContext();\n if (spanContext) {\n enriched.traceId = spanContext.traceId;\n enriched.spanId = spanContext.spanId;\n // Add correlation ID (first 16 chars of trace ID) for easier log grouping\n enriched.correlationId = spanContext.traceId.slice(0, 16);\n }\n\n // 3. Operation context (if inside a trace/span)\n const operationContext = getOperationContext();\n if (operationContext) {\n enriched['operation.name'] = operationContext.name;\n }\n\n return enriched;\n }\n\n /**\n * Track a business event\n *\n * Use this for tracking user actions, business events, product usage:\n * - \"user.signup\"\n * - \"order.completed\"\n * - \"feature.used\"\n *\n * Events are sent to configured subscribers (PostHog, Mixpanel, etc.).\n *\n * @example\n * ```typescript\n * // Track user signup\n * events.trackEvent('user.signup', {\n * userId: '123',\n * plan: 'pro'\n * })\n *\n * // Track order\n * events.trackEvent('order.completed', {\n * orderId: 'ord_123',\n * amount: 99.99\n * })\n * ```\n */\n trackEvent(eventName: string, attributes?: EventAttributes): void {\n // Validate and sanitize input (with custom config if provided)\n const validationConfig = getValidationConfig();\n const validated = validateEvent(\n eventName,\n attributes,\n validationConfig || undefined,\n );\n\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext(\n validated.attributes,\n );\n\n this.logger?.info('Event tracked', {\n event: validated.eventName,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordEvent({\n event: validated.eventName,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers (zero overhead if no subscribers)\n // Run in background - don't block event recording\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackEvent(validated.eventName, enrichedAttributes),\n );\n }\n }\n\n /**\n * Notify all subscribers concurrently without blocking\n * Uses circuit breakers to protect against failing subscribers\n * Uses Promise.allSettled to prevent subscriber errors from affecting other subscribers\n */\n private async notifySubscribers(\n fn: (subscriber: EventSubscriber) => Promise<void>,\n ): Promise<void> {\n const promises = this.subscribers.map(async (subscriber) => {\n const circuitBreaker = this.circuitBreakers.get(subscriber);\n if (!circuitBreaker) return; // Should never happen\n\n try {\n // Execute with circuit breaker protection\n await circuitBreaker.execute(() => fn(subscriber));\n } catch (error) {\n // Handle circuit open errors (expected behavior when subscriber is down)\n if (error instanceof CircuitOpenError) {\n // Circuit is open - subscriber is down, log at warn level for visibility (same behavior in all environments)\n getLogger().warn(`[Events] ${error.message}`, {\n subscriberName: subscriber.name || 'Unknown',\n });\n return;\n }\n\n // Log other subscriber errors but don't throw - event failures shouldn't break business logic\n getLogger().error(\n `[Events] Subscriber ${subscriber.name || 'Unknown'} failed`,\n error instanceof Error ? error : undefined,\n { subscriberName: subscriber.name || 'Unknown' },\n );\n }\n });\n\n // Wait for all subscribers (success or failure)\n await Promise.allSettled(promises);\n }\n\n /**\n * Track conversion funnel steps\n *\n * Monitor where users drop off in multi-step processes.\n *\n * @example\n * ```typescript\n * // Track signup funnel\n * events.trackFunnelStep('signup', 'started', { userId: '123' })\n * events.trackFunnelStep('signup', 'email_verified', { userId: '123' })\n * events.trackFunnelStep('signup', 'completed', { userId: '123' })\n *\n * // Track checkout flow\n * events.trackFunnelStep('checkout', 'started', { cartValue: 99.99 })\n * events.trackFunnelStep('checkout', 'payment_info', { cartValue: 99.99 })\n * events.trackFunnelStep('checkout', 'completed', { cartValue: 99.99 })\n * ```\n */\n trackFunnelStep(\n funnelName: string,\n status: FunnelStatus,\n attributes?: EventAttributes,\n ): void {\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext(attributes);\n\n this.logger?.info('Funnel step tracked', {\n funnel: funnelName,\n status,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordFunnelStep({\n funnel: funnelName,\n status,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackFunnelStep(funnelName, status, enrichedAttributes),\n );\n }\n }\n\n /**\n * Track outcomes (success/failure/partial)\n *\n * Monitor success rates of critical operations.\n *\n * @example\n * ```typescript\n * // Track email delivery\n * events.trackOutcome('email.delivery', 'success', {\n * recipientType: 'user',\n * emailType: 'welcome'\n * })\n *\n * events.trackOutcome('email.delivery', 'failure', {\n * recipientType: 'user',\n * errorCode: 'invalid_email'\n * })\n *\n * // Track payment processing\n * events.trackOutcome('payment.process', 'success', { amount: 99.99 })\n * events.trackOutcome('payment.process', 'failure', { error: 'insufficient_funds' })\n * ```\n */\n trackOutcome(\n operationName: string,\n status: OutcomeStatus,\n attributes?: EventAttributes,\n ): void {\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext(attributes);\n\n this.logger?.info('Outcome tracked', {\n operation: operationName,\n status,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordOutcome({\n operation: operationName,\n status,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackOutcome(operationName, status, enrichedAttributes),\n );\n }\n }\n\n /**\n * Track value metrics\n *\n * Record numerical values like revenue, transaction amounts,\n * item counts, processing times, engagement scores, etc.\n *\n * @example\n * ```typescript\n * // Track revenue\n * events.trackValue('order.revenue', 149.99, {\n * currency: 'USD',\n * productCategory: 'electronics'\n * })\n *\n * // Track items per cart\n * events.trackValue('cart.item_count', 5, {\n * userId: '123'\n * })\n *\n * // Track processing time\n * events.trackValue('api.response_time', 250, {\n * unit: 'ms',\n * endpoint: '/api/checkout'\n * })\n * ```\n */\n trackValue(\n metricName: string,\n value: number,\n attributes?: EventAttributes,\n ): void {\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext({\n metric: metricName,\n ...attributes,\n });\n\n this.logger?.debug('Value tracked', {\n metric: metricName,\n value,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordValue({\n metric: metricName,\n value,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackValue(metricName, value, enrichedAttributes),\n );\n }\n }\n\n /**\n * Flush all subscribers and wait for pending events\n *\n * Call this before shutdown to ensure all events are delivered.\n *\n * @example\n * ```typescript\n * const event =new Event('app', { subscribers: [...] });\n *\n * // Before shutdown\n * await events.flush();\n * ```\n */\n async flush(): Promise<void> {\n if (!this.hasSubscribers) return;\n\n const shutdownPromises = this.subscribers.map(async (subscriber) => {\n if (subscriber.shutdown) {\n try {\n await subscriber.shutdown();\n } catch (error) {\n getLogger().error(\n `[Events] Failed to shutdown subscriber ${subscriber.name || 'Unknown'}`,\n error instanceof Error ? error : undefined,\n { subscriberName: subscriber.name || 'Unknown' },\n );\n }\n }\n });\n\n await Promise.allSettled(shutdownPromises);\n }\n}\n\n/**\n * Global events instances (singleton pattern)\n */\nconst eventsInstances = new Map<string, Event>();\n\n/**\n * Get or create an Events instance for a service\n *\n * @param serviceName - Service name for identifying events\n * @param logger - Optional logger\n * @returns Events instance\n *\n * @example\n * ```typescript\n * const event =getEvents('job-application')\n * events.trackEvent('application.submitted', { jobId: '123' })\n * ```\n */\nexport function getEvents(serviceName: string, logger?: Logger): Event {\n if (!eventsInstances.has(serviceName)) {\n eventsInstances.set(serviceName, new Event(serviceName, { logger }));\n }\n return eventsInstances.get(serviceName)!;\n}\n\n/**\n * Reset all events instances (mainly for testing)\n */\nexport function resetEvents(): void {\n eventsInstances.clear();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/circuit-breaker.ts","../src/event.ts"],"names":["getConfig","trace","getOperationContext","getValidationConfig","validateEvent","getLogger"],"mappings":"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","file":"chunk-2WSBYOW7.cjs","sourcesContent":["/**\n * Circuit breaker for event subscribers\n *\n * Prevents cascading failures by fast-failing when an (subscriber) is unhealthy.\n * Uses the circuit breaker pattern with three states:\n * - CLOSED: Normal operation ((subscriber) working)\n * - OPEN: Fast-fail mode ((subscriber) down)\n * - HALF_OPEN: Testing if (subscriber) recovered\n */\n\nexport interface CircuitBreakerConfig {\n /** Number of failures before opening circuit (default: 5) */\n failureThreshold: number;\n /** Time to wait before trying again in ms (default: 30000 = 30s) */\n resetTimeout: number;\n /** Time window for counting failures in ms (default: 60000 = 1min) */\n windowSize: number;\n}\n\nconst DEFAULT_CONFIG: CircuitBreakerConfig = {\n failureThreshold: 5,\n resetTimeout: 30_000, // 30 seconds\n windowSize: 60_000, // 1 minute\n};\n\nexport type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';\n\nexport const CircuitState = {\n CLOSED: 'CLOSED' as const, // Normal operation\n OPEN: 'OPEN' as const, // Fast-fail mode\n HALF_OPEN: 'HALF_OPEN' as const, // Testing recovery\n} as const;\n\ninterface FailureRecord {\n timestamp: number;\n error: string;\n}\n\n/**\n * Circuit breaker implementation\n *\n * Tracks failures and automatically opens the circuit to prevent\n * overwhelming failing subscribers.\n */\nexport class CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failures: FailureRecord[] = [];\n private lastFailureTime: number = 0;\n private readonly config: CircuitBreakerConfig;\n private readonly name: string;\n\n constructor(name: string, config?: Partial<CircuitBreakerConfig>) {\n this.name = name;\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Execute a function with circuit breaker protection\n * Throws CircuitOpenError if circuit is open\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n // Check if circuit is open\n if (this.state === CircuitState.OPEN) {\n // Check if we should transition to half-open\n const now = Date.now();\n if (now - this.lastFailureTime >= this.config.resetTimeout) {\n this.state = CircuitState.HALF_OPEN;\n } else {\n throw new CircuitOpenError(\n `Circuit breaker is OPEN for ${this.name}. ` +\n `Will retry in ${Math.ceil((this.config.resetTimeout - (now - this.lastFailureTime)) / 1000)}s`,\n );\n }\n }\n\n try {\n const result = await fn();\n\n // Success! Close circuit if it was half-open\n if (this.state === CircuitState.HALF_OPEN) {\n this.reset();\n }\n\n return result;\n } catch (error) {\n this.recordFailure(error);\n throw error;\n }\n }\n\n /**\n * Record a failure and potentially open the circuit\n */\n private recordFailure(error: unknown): void {\n const now = Date.now();\n\n // Remove old failures outside the time window\n this.failures = this.failures.filter(\n (f) => now - f.timestamp < this.config.windowSize,\n );\n\n // Record new failure\n this.failures.push({\n timestamp: now,\n error: error instanceof Error ? error.message : String(error),\n });\n\n this.lastFailureTime = now;\n\n // Check if we should open the circuit\n if (this.failures.length >= this.config.failureThreshold) {\n if (this.state === CircuitState.HALF_OPEN) {\n // Failed during test - reopen circuit\n this.state = CircuitState.OPEN;\n } else if (this.state === CircuitState.CLOSED) {\n // Too many failures - open circuit\n this.state = CircuitState.OPEN;\n }\n }\n }\n\n /**\n * Reset the circuit breaker (on success)\n */\n private reset(): void {\n this.state = CircuitState.CLOSED;\n this.failures = [];\n this.lastFailureTime = 0;\n }\n\n /**\n * Get current state (for monitoring)\n */\n getState(): CircuitState {\n return this.state;\n }\n\n /**\n * Get failure count in current window\n */\n getFailureCount(): number {\n const now = Date.now();\n // Clean up old failures\n this.failures = this.failures.filter(\n (f) => now - f.timestamp < this.config.windowSize,\n );\n return this.failures.length;\n }\n\n /**\n * Get recent failures (for debugging)\n */\n getRecentFailures(): FailureRecord[] {\n const now = Date.now();\n return this.failures.filter(\n (f) => now - f.timestamp < this.config.windowSize,\n );\n }\n\n /**\n * Manually reset the circuit breaker (for testing or manual intervention)\n */\n forceReset(): void {\n this.reset();\n }\n\n /**\n * Manually open the circuit (for testing or manual intervention)\n */\n forceOpen(): void {\n this.state = CircuitState.OPEN;\n this.lastFailureTime = Date.now();\n }\n}\n\n/**\n * Error thrown when circuit is open\n */\nexport class CircuitOpenError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CircuitOpenError';\n }\n}\n","/**\n * Events API for product events platforms\n *\n * Track user behavior, business events, and critical actions.\n * Sends to product events platforms (PostHog, Mixpanel, Amplitude) via subscribers.\n * For business people who think in events/funnels.\n *\n * For OpenTelemetry metrics (Prometheus/Grafana), use the Metrics class instead.\n *\n * @example Recommended: Configure subscribers in init(), use track() function\n * ```typescript\n * import { init, track } from 'autotel';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * init({\n * service: 'my-app',\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_...' })]\n * });\n *\n * // Track events - uses subscribers from init()\n * track('application.submitted', { jobId: '123', userId: '456' });\n * ```\n *\n * @example Create Event instance (inherits subscribers from init)\n * ```typescript\n * import { Event } from 'autotel/event';\n *\n * // Uses subscribers configured in init()\n * const event = new Event('job-application');\n * event.trackEvent('application.submitted', { jobId: '123' });\n * ```\n *\n * @example Override subscribers for specific Event instance\n * ```typescript\n * import { Event } from 'autotel/event';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * // Override: use different subscribers for this instance\n * const event = new Event('job-application', {\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_different_project' })]\n * });\n *\n * event.trackEvent('application.submitted', { jobId: '123' });\n * ```\n */\n\nimport { trace } from '@opentelemetry/api';\nimport { type Logger } from './logger';\nimport { getLogger, getValidationConfig, getConfig } from './init';\nimport {\n type EventSubscriber,\n type EventAttributes,\n type FunnelStatus,\n type OutcomeStatus,\n} from './event-subscriber';\nimport { type EventCollector } from './event-testing';\nimport { CircuitBreaker, CircuitOpenError } from './circuit-breaker';\nimport { validateEvent } from './validation';\nimport { getOperationContext } from './operation-context';\n\n// Re-export types for convenience\nexport type {\n EventAttributes,\n FunnelStatus,\n OutcomeStatus,\n} from './event-subscriber';\n\n/**\n * Events class for tracking user behavior and product events\n *\n * Track critical indicators such as:\n * - User events (signups, purchases, feature usage)\n * - Conversion funnels (signup → activation → purchase)\n * - Business outcomes (success/failure rates)\n * - Product metrics (revenue, engagement, retention)\n *\n * All events are sent to events platforms via subscribers (PostHog, Mixpanel, etc.).\n * For OpenTelemetry metrics, use the Metrics class instead.\n */\n/**\n * Events options\n */\nexport interface EventsOptions {\n /** Optional logger for audit trail */\n logger?: Logger;\n /** Optional collector for testing (captures events in memory) */\n collector?: EventCollector;\n /**\n * Optional subscribers to send events to other platforms\n * (e.g., PostHog, Mixpanel, Amplitude)\n *\n * **Subscriber Resolution**:\n * - If provided → uses these subscribers (instance override)\n * - If not provided → falls back to subscribers from `init()` (global config)\n * - If neither → no subscribers (events logged only)\n *\n * Install `autotel-subscribers` package for ready-made subscribers\n */\n subscribers?: EventSubscriber[];\n}\n\nexport class Event {\n private serviceName: string;\n private logger?: Logger;\n private collector?: EventCollector;\n private subscribers: EventSubscriber[];\n private hasSubscribers: boolean; // Cached for performance\n private circuitBreakers: Map<EventSubscriber, CircuitBreaker>; // One per subscriber\n\n /**\n * Create a new Event instance\n *\n * **Note**: Most users should use `init()` + `track()` instead of creating Event instances directly.\n *\n * **Subscriber Resolution**:\n * - If `subscribers` provided in options → uses those (instance override)\n * - If `subscribers` not provided → falls back to subscribers from `init()` (global config)\n * - If neither → no subscribers (events logged only)\n *\n * @param serviceName - Service name for identifying events\n * @param options - Optional configuration (logger, collector, subscribers)\n *\n * @example Recommended: Use track() with init()\n * ```typescript\n * import { init, track } from 'autotel';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * init({\n * service: 'checkout',\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_...' })]\n * });\n *\n * track('purchase.completed', { amount: 99.99 });\n * ```\n *\n * @example Inherit subscribers from init()\n * ```typescript\n * // Uses subscribers configured in init()\n * const event = new Event('checkout');\n * event.trackEvent('purchase.completed', { amount: 99.99 });\n * ```\n *\n * @example Override subscribers for this instance\n * ```typescript\n * import { Event } from 'autotel/event';\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * // Override: use different subscribers for this instance only\n * const event = new Event('checkout', {\n * subscribers: [new PostHogSubscriber({ apiKey: 'phc_different_project' })]\n * });\n * ```\n */\n constructor(serviceName: string, options: EventsOptions = {}) {\n this.serviceName = serviceName;\n this.logger = options.logger;\n this.collector = options.collector;\n\n // Subscriber resolution: instance-level overrides global init() config\n // If subscribers provided to constructor, use those\n // Otherwise, fall back to subscribers from init()\n this.subscribers =\n options.subscribers === undefined\n ? getConfig()?.subscribers || []\n : options.subscribers;\n\n this.hasSubscribers = this.subscribers.length > 0; // Cache for hot path\n\n // Create circuit breaker for each subscriber\n this.circuitBreakers = new Map();\n for (const subscriber of this.subscribers) {\n const subscriberName = subscriber.name || 'Unknown';\n this.circuitBreakers.set(\n subscriber,\n new CircuitBreaker(subscriberName, {\n failureThreshold: 5,\n resetTimeout: 30_000, // 30s\n windowSize: 60_000, // 1min\n }),\n );\n }\n }\n\n /**\n * Automatically enrich attributes with all available telemetry context\n *\n * Auto-captures:\n * - Resource attributes: service.version, deployment.environment\n * - Trace context: traceId, spanId, correlationId\n * - Operation context: operation.name\n */\n private enrichWithTelemetryContext(\n attributes: EventAttributes = {},\n ): EventAttributes {\n const enriched: EventAttributes = {\n service: this.serviceName,\n ...attributes,\n };\n\n // 1. Resource attributes (service-level context)\n const config = getConfig();\n if (config) {\n if (config.version) {\n enriched['service.version'] = config.version;\n }\n if (config.environment) {\n enriched['deployment.environment'] = config.environment;\n }\n }\n\n // 2. Trace context (if inside a traced operation)\n const span = trace.getActiveSpan();\n const spanContext = span?.spanContext();\n if (spanContext) {\n enriched.traceId = spanContext.traceId;\n enriched.spanId = spanContext.spanId;\n // Add correlation ID (first 16 chars of trace ID) for easier log grouping\n enriched.correlationId = spanContext.traceId.slice(0, 16);\n }\n\n // 3. Operation context (if inside a trace/span)\n const operationContext = getOperationContext();\n if (operationContext) {\n enriched['operation.name'] = operationContext.name;\n }\n\n return enriched;\n }\n\n /**\n * Track a business event\n *\n * Use this for tracking user actions, business events, product usage:\n * - \"user.signup\"\n * - \"order.completed\"\n * - \"feature.used\"\n *\n * Events are sent to configured subscribers (PostHog, Mixpanel, etc.).\n *\n * @example\n * ```typescript\n * // Track user signup\n * events.trackEvent('user.signup', {\n * userId: '123',\n * plan: 'pro'\n * })\n *\n * // Track order\n * events.trackEvent('order.completed', {\n * orderId: 'ord_123',\n * amount: 99.99\n * })\n * ```\n */\n trackEvent(eventName: string, attributes?: EventAttributes): void {\n // Validate and sanitize input (with custom config if provided)\n const validationConfig = getValidationConfig();\n const validated = validateEvent(\n eventName,\n attributes,\n validationConfig || undefined,\n );\n\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext(\n validated.attributes,\n );\n\n this.logger?.info('Event tracked', {\n event: validated.eventName,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordEvent({\n event: validated.eventName,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers (zero overhead if no subscribers)\n // Run in background - don't block event recording\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackEvent(validated.eventName, enrichedAttributes),\n );\n }\n }\n\n /**\n * Notify all subscribers concurrently without blocking\n * Uses circuit breakers to protect against failing subscribers\n * Uses Promise.allSettled to prevent subscriber errors from affecting other subscribers\n */\n private async notifySubscribers(\n fn: (subscriber: EventSubscriber) => Promise<void>,\n ): Promise<void> {\n const promises = this.subscribers.map(async (subscriber) => {\n const circuitBreaker = this.circuitBreakers.get(subscriber);\n if (!circuitBreaker) return; // Should never happen\n\n try {\n // Execute with circuit breaker protection\n await circuitBreaker.execute(() => fn(subscriber));\n } catch (error) {\n // Handle circuit open errors (expected behavior when subscriber is down)\n if (error instanceof CircuitOpenError) {\n // Circuit is open - subscriber is down, log at warn level for visibility (same behavior in all environments)\n getLogger().warn(`[Events] ${error.message}`, {\n subscriberName: subscriber.name || 'Unknown',\n });\n return;\n }\n\n // Log other subscriber errors but don't throw - event failures shouldn't break business logic\n getLogger().error(\n `[Events] Subscriber ${subscriber.name || 'Unknown'} failed`,\n error instanceof Error ? error : undefined,\n { subscriberName: subscriber.name || 'Unknown' },\n );\n }\n });\n\n // Wait for all subscribers (success or failure)\n await Promise.allSettled(promises);\n }\n\n /**\n * Track conversion funnel steps\n *\n * Monitor where users drop off in multi-step processes.\n *\n * @example\n * ```typescript\n * // Track signup funnel\n * events.trackFunnelStep('signup', 'started', { userId: '123' })\n * events.trackFunnelStep('signup', 'email_verified', { userId: '123' })\n * events.trackFunnelStep('signup', 'completed', { userId: '123' })\n *\n * // Track checkout flow\n * events.trackFunnelStep('checkout', 'started', { cartValue: 99.99 })\n * events.trackFunnelStep('checkout', 'payment_info', { cartValue: 99.99 })\n * events.trackFunnelStep('checkout', 'completed', { cartValue: 99.99 })\n * ```\n */\n trackFunnelStep(\n funnelName: string,\n status: FunnelStatus,\n attributes?: EventAttributes,\n ): void {\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext(attributes);\n\n this.logger?.info('Funnel step tracked', {\n funnel: funnelName,\n status,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordFunnelStep({\n funnel: funnelName,\n status,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackFunnelStep(funnelName, status, enrichedAttributes),\n );\n }\n }\n\n /**\n * Track outcomes (success/failure/partial)\n *\n * Monitor success rates of critical operations.\n *\n * @example\n * ```typescript\n * // Track email delivery\n * events.trackOutcome('email.delivery', 'success', {\n * recipientType: 'user',\n * emailType: 'welcome'\n * })\n *\n * events.trackOutcome('email.delivery', 'failure', {\n * recipientType: 'user',\n * errorCode: 'invalid_email'\n * })\n *\n * // Track payment processing\n * events.trackOutcome('payment.process', 'success', { amount: 99.99 })\n * events.trackOutcome('payment.process', 'failure', { error: 'insufficient_funds' })\n * ```\n */\n trackOutcome(\n operationName: string,\n status: OutcomeStatus,\n attributes?: EventAttributes,\n ): void {\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext(attributes);\n\n this.logger?.info('Outcome tracked', {\n operation: operationName,\n status,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordOutcome({\n operation: operationName,\n status,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackOutcome(operationName, status, enrichedAttributes),\n );\n }\n }\n\n /**\n * Track value metrics\n *\n * Record numerical values like revenue, transaction amounts,\n * item counts, processing times, engagement scores, etc.\n *\n * @example\n * ```typescript\n * // Track revenue\n * events.trackValue('order.revenue', 149.99, {\n * currency: 'USD',\n * productCategory: 'electronics'\n * })\n *\n * // Track items per cart\n * events.trackValue('cart.item_count', 5, {\n * userId: '123'\n * })\n *\n * // Track processing time\n * events.trackValue('api.response_time', 250, {\n * unit: 'ms',\n * endpoint: '/api/checkout'\n * })\n * ```\n */\n trackValue(\n metricName: string,\n value: number,\n attributes?: EventAttributes,\n ): void {\n // Auto-attach all available telemetry context\n const enrichedAttributes = this.enrichWithTelemetryContext({\n metric: metricName,\n ...attributes,\n });\n\n this.logger?.debug('Value tracked', {\n metric: metricName,\n value,\n attributes: enrichedAttributes,\n });\n\n // Record for testing\n this.collector?.recordValue({\n metric: metricName,\n value,\n attributes: enrichedAttributes,\n service: this.serviceName,\n timestamp: Date.now(),\n });\n\n // Notify subscribers\n if (this.hasSubscribers) {\n void this.notifySubscribers((subscriber) =>\n subscriber.trackValue(metricName, value, enrichedAttributes),\n );\n }\n }\n\n /**\n * Flush all subscribers and wait for pending events\n *\n * Call this before shutdown to ensure all events are delivered.\n *\n * @example\n * ```typescript\n * const event =new Event('app', { subscribers: [...] });\n *\n * // Before shutdown\n * await events.flush();\n * ```\n */\n async flush(): Promise<void> {\n if (!this.hasSubscribers) return;\n\n const shutdownPromises = this.subscribers.map(async (subscriber) => {\n if (subscriber.shutdown) {\n try {\n await subscriber.shutdown();\n } catch (error) {\n getLogger().error(\n `[Events] Failed to shutdown subscriber ${subscriber.name || 'Unknown'}`,\n error instanceof Error ? error : undefined,\n { subscriberName: subscriber.name || 'Unknown' },\n );\n }\n }\n });\n\n await Promise.allSettled(shutdownPromises);\n }\n}\n\n/**\n * Global events instances (singleton pattern)\n */\nconst eventsInstances = new Map<string, Event>();\n\n/**\n * Get or create an Events instance for a service\n *\n * @param serviceName - Service name for identifying events\n * @param logger - Optional logger\n * @returns Events instance\n *\n * @example\n * ```typescript\n * const event =getEvents('job-application')\n * events.trackEvent('application.submitted', { jobId: '123' })\n * ```\n */\nexport function getEvents(serviceName: string, logger?: Logger): Event {\n if (!eventsInstances.has(serviceName)) {\n eventsInstances.set(serviceName, new Event(serviceName, { logger }));\n }\n return eventsInstances.get(serviceName)!;\n}\n\n/**\n * Reset all events instances (mainly for testing)\n */\nexport function resetEvents(): void {\n eventsInstances.clear();\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var chunk2EHB2KXS_cjs = require('./chunk-2EHB2KXS.cjs');
|
|
4
4
|
var chunkIW37CN6L_cjs = require('./chunk-IW37CN6L.cjs');
|
|
5
5
|
var chunkYLPNXZFI_cjs = require('./chunk-YLPNXZFI.cjs');
|
|
6
|
-
var
|
|
6
|
+
var chunkEDJKNUGP_cjs = require('./chunk-EDJKNUGP.cjs');
|
|
7
7
|
var chunkHE6T6FIX_cjs = require('./chunk-HE6T6FIX.cjs');
|
|
8
8
|
var chunkY4Y2S7BM_cjs = require('./chunk-Y4Y2S7BM.cjs');
|
|
9
9
|
var api = require('@opentelemetry/api');
|
|
@@ -108,7 +108,7 @@ var EventQueue = class {
|
|
|
108
108
|
enqueue(event) {
|
|
109
109
|
if (this.queue.length >= this.config.maxSize) {
|
|
110
110
|
const droppedEvent = this.queue.shift();
|
|
111
|
-
|
|
111
|
+
chunkEDJKNUGP_cjs.getLogger().warn(
|
|
112
112
|
`[autotel] Events queue full (${this.config.maxSize} events). Dropping oldest event. Events are being produced faster than they can be sent. Check your subscribers or reduce tracking frequency.`,
|
|
113
113
|
{ droppedEvent: droppedEvent?.name }
|
|
114
114
|
);
|
|
@@ -154,7 +154,7 @@ var EventQueue = class {
|
|
|
154
154
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
155
155
|
return this.sendWithRetry(events, retriesLeft - 1);
|
|
156
156
|
} else {
|
|
157
|
-
|
|
157
|
+
chunkEDJKNUGP_cjs.getLogger().error(
|
|
158
158
|
"[autotel] Failed to send events after retries",
|
|
159
159
|
error instanceof Error ? error : void 0,
|
|
160
160
|
{ retriesAttempted: this.config.maxRetries }
|
|
@@ -212,12 +212,12 @@ var EventQueue = class {
|
|
|
212
212
|
// src/track.ts
|
|
213
213
|
var eventsQueue = null;
|
|
214
214
|
function getOrCreateQueue() {
|
|
215
|
-
if (!
|
|
216
|
-
|
|
215
|
+
if (!chunkEDJKNUGP_cjs.isInitialized()) {
|
|
216
|
+
chunkEDJKNUGP_cjs.warnIfNotInitialized("track()");
|
|
217
217
|
return null;
|
|
218
218
|
}
|
|
219
219
|
if (!eventsQueue) {
|
|
220
|
-
const config =
|
|
220
|
+
const config = chunkEDJKNUGP_cjs.getConfig();
|
|
221
221
|
if (!config?.subscribers || config.subscribers.length === 0) {
|
|
222
222
|
return null;
|
|
223
223
|
}
|
|
@@ -228,7 +228,7 @@ function getOrCreateQueue() {
|
|
|
228
228
|
function track(event, data) {
|
|
229
229
|
const queue = getOrCreateQueue();
|
|
230
230
|
if (!queue) return;
|
|
231
|
-
const validationConfig =
|
|
231
|
+
const validationConfig = chunkEDJKNUGP_cjs.getValidationConfig();
|
|
232
232
|
const validated = chunkYLPNXZFI_cjs.validateEvent(event, data, validationConfig || void 0);
|
|
233
233
|
const span2 = api.trace.getActiveSpan();
|
|
234
234
|
const enrichedData = span2 ? {
|
|
@@ -636,8 +636,8 @@ function wrapWithTracing(fnFactory, options, variableName) {
|
|
|
636
636
|
}
|
|
637
637
|
const startTime = performance.now();
|
|
638
638
|
const isRootSpan = options.startNewRoot || api.trace.getActiveSpan() === void 0;
|
|
639
|
-
const shouldAutoFlush = options.autoFlushEvents ??
|
|
640
|
-
const shouldAutoFlushSpans =
|
|
639
|
+
const shouldAutoFlush = options.autoFlushEvents ?? chunkEDJKNUGP_cjs.getConfig()?.autoFlushEvents ?? true;
|
|
640
|
+
const shouldAutoFlushSpans = chunkEDJKNUGP_cjs.getConfig()?.autoFlush ?? false;
|
|
641
641
|
const flushIfNeeded = async () => {
|
|
642
642
|
if (!shouldAutoFlush || !isRootSpan) return;
|
|
643
643
|
try {
|
|
@@ -646,7 +646,7 @@ function wrapWithTracing(fnFactory, options, variableName) {
|
|
|
646
646
|
await queue.flush();
|
|
647
647
|
}
|
|
648
648
|
if (shouldAutoFlushSpans) {
|
|
649
|
-
const sdk =
|
|
649
|
+
const sdk = chunkEDJKNUGP_cjs.getSdk();
|
|
650
650
|
if (sdk) {
|
|
651
651
|
try {
|
|
652
652
|
const sdkAny = sdk;
|
|
@@ -661,7 +661,7 @@ function wrapWithTracing(fnFactory, options, variableName) {
|
|
|
661
661
|
}
|
|
662
662
|
}
|
|
663
663
|
} catch (error) {
|
|
664
|
-
const initConfig =
|
|
664
|
+
const initConfig = chunkEDJKNUGP_cjs.getConfig();
|
|
665
665
|
const logger = initConfig?.logger;
|
|
666
666
|
if (logger?.error) {
|
|
667
667
|
if (error instanceof Error) {
|
|
@@ -821,14 +821,14 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
|
|
|
821
821
|
}
|
|
822
822
|
const startTime = performance.now();
|
|
823
823
|
const isRootSpan = options.startNewRoot || api.trace.getActiveSpan() === void 0;
|
|
824
|
-
const shouldAutoFlush = options.autoFlushEvents ??
|
|
825
|
-
const shouldAutoFlushSpans =
|
|
824
|
+
const shouldAutoFlush = options.autoFlushEvents ?? chunkEDJKNUGP_cjs.getConfig()?.autoFlushEvents ?? true;
|
|
825
|
+
const shouldAutoFlushSpans = chunkEDJKNUGP_cjs.getConfig()?.autoFlush ?? false;
|
|
826
826
|
const flushIfNeeded = () => {
|
|
827
827
|
if (!shouldAutoFlush || !isRootSpan) return;
|
|
828
828
|
const queue = getEventQueue();
|
|
829
829
|
if (queue && queue.size() > 0) {
|
|
830
830
|
void queue.flush().catch((error) => {
|
|
831
|
-
const initConfig =
|
|
831
|
+
const initConfig = chunkEDJKNUGP_cjs.getConfig();
|
|
832
832
|
const logger = initConfig?.logger;
|
|
833
833
|
if (logger?.error) {
|
|
834
834
|
if (error instanceof Error) {
|
|
@@ -840,7 +840,7 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
|
|
|
840
840
|
});
|
|
841
841
|
}
|
|
842
842
|
if (shouldAutoFlushSpans) {
|
|
843
|
-
const sdk =
|
|
843
|
+
const sdk = chunkEDJKNUGP_cjs.getSdk();
|
|
844
844
|
if (sdk) {
|
|
845
845
|
try {
|
|
846
846
|
const sdkAny = sdk;
|
|
@@ -848,7 +848,7 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
|
|
|
848
848
|
const tracerProvider = sdkAny.getTracerProvider();
|
|
849
849
|
if (tracerProvider && typeof tracerProvider.forceFlush === "function") {
|
|
850
850
|
void tracerProvider.forceFlush().catch((error) => {
|
|
851
|
-
const initConfig =
|
|
851
|
+
const initConfig = chunkEDJKNUGP_cjs.getConfig();
|
|
852
852
|
const logger = initConfig?.logger;
|
|
853
853
|
if (logger?.error) {
|
|
854
854
|
if (error instanceof Error) {
|
|
@@ -989,8 +989,8 @@ function executeImmediately(fn, options) {
|
|
|
989
989
|
}
|
|
990
990
|
const startTime = performance.now();
|
|
991
991
|
const isRootSpan = options.startNewRoot || api.trace.getActiveSpan() === void 0;
|
|
992
|
-
const shouldAutoFlush = options.autoFlushEvents ??
|
|
993
|
-
const shouldAutoFlushSpans =
|
|
992
|
+
const shouldAutoFlush = options.autoFlushEvents ?? chunkEDJKNUGP_cjs.getConfig()?.autoFlushEvents ?? true;
|
|
993
|
+
const shouldAutoFlushSpans = chunkEDJKNUGP_cjs.getConfig()?.autoFlush ?? false;
|
|
994
994
|
const callCounter = options.withMetrics ? meter.createCounter(`${spanName}.calls`, {
|
|
995
995
|
description: `Call count for ${spanName}`,
|
|
996
996
|
unit: "1"
|
|
@@ -1007,7 +1007,7 @@ function executeImmediately(fn, options) {
|
|
|
1007
1007
|
await queue.flush();
|
|
1008
1008
|
}
|
|
1009
1009
|
if (shouldAutoFlushSpans) {
|
|
1010
|
-
const sdk =
|
|
1010
|
+
const sdk = chunkEDJKNUGP_cjs.getSdk();
|
|
1011
1011
|
if (sdk) {
|
|
1012
1012
|
try {
|
|
1013
1013
|
const sdkAny = sdk;
|
|
@@ -1022,7 +1022,7 @@ function executeImmediately(fn, options) {
|
|
|
1022
1022
|
}
|
|
1023
1023
|
}
|
|
1024
1024
|
} catch (error) {
|
|
1025
|
-
const initConfig =
|
|
1025
|
+
const initConfig = chunkEDJKNUGP_cjs.getConfig();
|
|
1026
1026
|
const logger = initConfig?.logger;
|
|
1027
1027
|
if (logger?.error) {
|
|
1028
1028
|
if (error instanceof Error) {
|
|
@@ -1368,5 +1368,5 @@ exports.track = track;
|
|
|
1368
1368
|
exports.withBaggage = withBaggage;
|
|
1369
1369
|
exports.withNewContext = withNewContext;
|
|
1370
1370
|
exports.withTracing = withTracing;
|
|
1371
|
-
//# sourceMappingURL=chunk-
|
|
1372
|
-
//# sourceMappingURL=chunk-
|
|
1371
|
+
//# sourceMappingURL=chunk-5JSIRHVW.cjs.map
|
|
1372
|
+
//# sourceMappingURL=chunk-5JSIRHVW.cjs.map
|