@sentienguard/apm 1.0.5 → 1.0.7

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/src/index.js CHANGED
@@ -1,209 +1,225 @@
1
- /**
2
- * SentienGuard APM SDK
3
- *
4
- * Minimal, production-safe APM that runs inside client applications
5
- * and sends aggregated metrics to the SentienGuard backend.
6
- *
7
- * Usage:
8
- * import "@sentienguard/apm";
9
- *
10
- * That's it. No function calls, no setup code, no decorators.
11
- *
12
- * Configuration via environment variables:
13
- * SENTIENGUARD_APM_KEY=xxxx (required)
14
- * SENTIENGUARD_SERVICE=my-api (required)
15
- * SENTIENGUARD_ENV=production (optional, default: production)
16
- * SENTIENGUARD_ENDPOINT=https://... (optional)
17
- * SENTIENGUARD_FLUSH_INTERVAL=10 (optional, seconds)
18
- *
19
- * No config → SDK disables itself silently.
20
- */
21
-
22
- import config, { isEnabled, debug, warn, getConfig } from './config.js';
23
- import { instrumentHttp, expressMiddleware, fastifyPlugin } from './instrumentation.js';
24
- import { instrumentDependencies } from './dependencies.js';
25
- import { startErrorCapture, expressErrorMiddleware, fastifyErrorHandler } from './errors.js';
26
- import { startFlushing, stopFlushing, finalFlush, flush } from './transport.js';
27
- import { getAggregator } from './aggregator.js';
28
- import { normalizeRoute, extractRoute, RouteRegistry } from './normalizer.js';
29
- import { instrumentMongoDB, autoInstrumentMongoDB, stopMongoDBInstrumentation } from './mongodb.js';
30
- import { instrumentOpenAI, stopOpenAIInstrumentation } from './openai.js';
31
- import { createBreaker, wrapMongoOperation, getBreakerStats, shutdownBreakers } from './circuitBreaker.js';
32
-
33
- let isInitialized = false;
34
-
35
- /**
36
- * Initialize the SDK
37
- * Called automatically on import
38
- */
39
- function initialize() {
40
- if (isInitialized) {
41
- debug('SDK already initialized');
42
- return;
43
- }
44
-
45
- // Check if SDK should be enabled
46
- if (!isEnabled()) {
47
- // Silently disable - this is expected behavior
48
- debug('SDK disabled (missing API key or service name)');
49
- return;
50
- }
51
-
52
- // Warn if this import is not first (other modules may have created servers already)
53
- // We can't reliably detect this, so just log for debugging
54
- debug(`Initializing SDK for service: ${config.service}`);
55
- debug(`Environment: ${config.environment}`);
56
- debug(`Endpoint: ${config.endpoint}`);
57
- debug(`Flush interval: ${config.flushInterval}s`);
58
-
59
- // Instrument HTTP (incoming requests)
60
- instrumentHttp();
61
-
62
- // Instrument dependencies (outgoing requests)
63
- instrumentDependencies();
64
-
65
- // Auto-instrument MongoDB if available
66
- autoInstrumentMongoDB();
67
-
68
- // Start error capture
69
- startErrorCapture();
70
-
71
- // Start periodic flush
72
- startFlushing();
73
-
74
- // Handle graceful shutdown
75
- setupGracefulShutdown();
76
-
77
- isInitialized = true;
78
- debug('SDK initialized successfully');
79
- }
80
-
81
- /**
82
- * Setup graceful shutdown handlers
83
- */
84
- function setupGracefulShutdown() {
85
- const shutdown = async (signal) => {
86
- debug(`Received ${signal}, performing graceful shutdown`);
87
-
88
- // Stop accepting new data
89
- stopFlushing();
90
-
91
- // Final flush
92
- await finalFlush();
93
-
94
- debug('Shutdown complete');
95
- };
96
-
97
- // Handle common shutdown signals
98
- process.once('SIGTERM', () => shutdown('SIGTERM'));
99
- process.once('SIGINT', () => shutdown('SIGINT'));
100
-
101
- // Handle process exit
102
- process.once('beforeExit', () => shutdown('beforeExit'));
103
- }
104
-
105
- /**
106
- * Shutdown the SDK
107
- * Call this before process exit for clean shutdown
108
- */
109
- async function shutdown() {
110
- if (!isInitialized) return;
111
-
112
- debug('Shutting down SDK');
113
-
114
- // Stop MongoDB instrumentation
115
- stopMongoDBInstrumentation();
116
-
117
- // Stop OpenAI instrumentation
118
- stopOpenAIInstrumentation();
119
-
120
- // Shutdown circuit breakers
121
- shutdownBreakers();
122
-
123
- stopFlushing();
124
- await finalFlush();
125
-
126
- isInitialized = false;
127
- debug('SDK shutdown complete');
128
- }
129
-
130
- /**
131
- * Get current SDK status
132
- */
133
- function getStatus() {
134
- const aggregator = getAggregator();
135
- const stats = aggregator.getStats();
136
-
137
- return {
138
- enabled: isEnabled(),
139
- initialized: isInitialized,
140
- config: {
141
- service: config.service,
142
- environment: config.environment,
143
- flushInterval: config.flushInterval
144
- },
145
- stats
146
- };
147
- }
148
-
149
- // Auto-initialize on import
150
- initialize();
151
-
152
- // Export for advanced usage
153
- export {
154
- // Core functions
155
- initialize,
156
- shutdown,
157
- getStatus,
158
- flush,
159
-
160
- // Config
161
- getConfig,
162
- isEnabled,
163
-
164
- // Middleware for frameworks (optional, for better route extraction)
165
- expressMiddleware,
166
- expressErrorMiddleware,
167
- fastifyPlugin,
168
- fastifyErrorHandler,
169
-
170
- // Utilities (for custom instrumentation)
171
- normalizeRoute,
172
- extractRoute,
173
- RouteRegistry,
174
- getAggregator,
175
-
176
- // MongoDB instrumentation
177
- instrumentMongoDB,
178
-
179
- // OpenAI instrumentation
180
- instrumentOpenAI,
181
-
182
- // Circuit breaker
183
- createBreaker,
184
- wrapMongoOperation,
185
- getBreakerStats
186
- };
187
-
188
- // Default export
189
- export default {
190
- initialize,
191
- shutdown,
192
- getStatus,
193
- flush,
194
- expressMiddleware,
195
- expressErrorMiddleware,
196
- fastifyPlugin,
197
- fastifyErrorHandler,
198
- normalizeRoute,
199
- extractRoute,
200
- getAggregator,
201
- // MongoDB
202
- instrumentMongoDB,
203
- // OpenAI
204
- instrumentOpenAI,
205
- // Circuit breaker
206
- createBreaker,
207
- wrapMongoOperation,
208
- getBreakerStats
209
- };
1
+ /**
2
+ * SentienGuard APM SDK
3
+ *
4
+ * Minimal, production-safe APM that runs inside client applications
5
+ * and sends aggregated metrics to the SentienGuard backend.
6
+ *
7
+ * Usage:
8
+ * import "@sentienguard/apm";
9
+ *
10
+ * That's it. No function calls, no setup code, no decorators.
11
+ *
12
+ * Configuration via environment variables:
13
+ * SENTIENGUARD_APM_KEY=xxxx (required)
14
+ * SENTIENGUARD_SERVICE=my-api (required)
15
+ * SENTIENGUARD_ENV=production (optional, default: production)
16
+ * SENTIENGUARD_ENDPOINT=https://... (optional)
17
+ * SENTIENGUARD_FLUSH_INTERVAL=10 (optional, seconds)
18
+ *
19
+ * No config → SDK disables itself silently.
20
+ */
21
+
22
+ import config, { isEnabled, debug, getConfig, loadConfig } from './config.js';
23
+ import { instrumentHttp, expressMiddleware, fastifyPlugin } from './instrumentation.js';
24
+ import { instrumentDependencies } from './dependencies.js';
25
+ import { startErrorCapture, expressErrorMiddleware, fastifyErrorHandler } from './errors.js';
26
+ import { startFlushing, stopFlushing, finalFlush, flush } from './transport.js';
27
+ import { getAggregator } from './aggregator.js';
28
+ import { normalizeRoute, extractRoute, RouteRegistry } from './normalizer.js';
29
+ import { instrumentMongoDB, autoInstrumentMongoDB, stopMongoDBInstrumentation } from './mongodb.js';
30
+ import { instrumentOpenAI, stopOpenAIInstrumentation } from './openai.js';
31
+ import { createBreaker, wrapMongoOperation, getBreakerStats, shutdownBreakers } from './circuitBreaker.js';
32
+
33
+ let isInitialized = false;
34
+
35
+ /**
36
+ * Initialize the SDK
37
+ * Called automatically on import
38
+ */
39
+ function initialize() {
40
+ if (isInitialized) {
41
+ debug('SDK already initialized');
42
+ return;
43
+ }
44
+
45
+ // Load config from env vars (lazy — allows dotenv to load first)
46
+ loadConfig();
47
+
48
+ // Check if SDK should be enabled
49
+ if (!isEnabled()) {
50
+ // Silently disable - this is expected behavior
51
+ debug('SDK disabled (missing API key or service name)');
52
+ return;
53
+ }
54
+
55
+ // Warn if this import is not first (other modules may have created servers already)
56
+ // We can't reliably detect this, so just log for debugging
57
+ debug(`Initializing SDK for service: ${config.service}`);
58
+ debug(`Environment: ${config.environment}`);
59
+ debug(`Endpoint: ${config.endpoint}`);
60
+ debug(`Flush interval: ${config.flushInterval}s`);
61
+
62
+ // Instrument HTTP (incoming requests)
63
+ instrumentHttp();
64
+
65
+ // Instrument dependencies (outgoing requests)
66
+ instrumentDependencies();
67
+
68
+ // Auto-instrument MongoDB if available
69
+ autoInstrumentMongoDB();
70
+
71
+ // Start error capture
72
+ startErrorCapture();
73
+
74
+ // Start periodic flush
75
+ startFlushing();
76
+
77
+ // Handle graceful shutdown
78
+ setupGracefulShutdown();
79
+
80
+ isInitialized = true;
81
+ debug('SDK initialized successfully');
82
+ }
83
+
84
+ /**
85
+ * Setup graceful shutdown handlers
86
+ */
87
+ function setupGracefulShutdown() {
88
+ const shutdown = async (signal) => {
89
+ debug(`Received ${signal}, performing graceful shutdown`);
90
+
91
+ // Stop accepting new data
92
+ stopFlushing();
93
+
94
+ // Final flush
95
+ await finalFlush();
96
+
97
+ debug('Shutdown complete');
98
+ };
99
+
100
+ // Handle common shutdown signals
101
+ process.once('SIGTERM', () => shutdown('SIGTERM'));
102
+ process.once('SIGINT', () => shutdown('SIGINT'));
103
+
104
+ // Handle process exit
105
+ process.once('beforeExit', () => shutdown('beforeExit'));
106
+ }
107
+
108
+ /**
109
+ * Shutdown the SDK
110
+ * Call this before process exit for clean shutdown
111
+ */
112
+ async function shutdown() {
113
+ if (!isInitialized) return;
114
+
115
+ debug('Shutting down SDK');
116
+
117
+ // Stop MongoDB instrumentation
118
+ stopMongoDBInstrumentation();
119
+
120
+ // Stop OpenAI instrumentation
121
+ stopOpenAIInstrumentation();
122
+
123
+ // Shutdown circuit breakers
124
+ shutdownBreakers();
125
+
126
+ stopFlushing();
127
+ await finalFlush();
128
+
129
+ isInitialized = false;
130
+ debug('SDK shutdown complete');
131
+ }
132
+
133
+ /**
134
+ * Get current SDK status
135
+ */
136
+ function getStatus() {
137
+ const aggregator = getAggregator();
138
+ const stats = aggregator.getStats();
139
+
140
+ return {
141
+ enabled: isEnabled(),
142
+ initialized: isInitialized,
143
+ config: {
144
+ service: config.service,
145
+ environment: config.environment,
146
+ flushInterval: config.flushInterval
147
+ },
148
+ stats
149
+ };
150
+ }
151
+
152
+ // Phase 1: Immediately patch http/https (config-independent, must happen before servers are created)
153
+ instrumentHttp();
154
+ instrumentDependencies();
155
+
156
+ // Phase 2: Try full initialization (works if env vars are already set at system/process level)
157
+ initialize();
158
+
159
+ // Phase 3: If init failed (env vars not loaded yet, e.g. dotenv.config() hasn't run),
160
+ // retry after the importing module's synchronous code completes
161
+ if (!isInitialized) {
162
+ process.nextTick(() => {
163
+ loadConfig({ force: true });
164
+ initialize();
165
+ });
166
+ }
167
+
168
+ // Export for advanced usage
169
+ export {
170
+ // Core functions
171
+ initialize,
172
+ shutdown,
173
+ getStatus,
174
+ flush,
175
+
176
+ // Config
177
+ getConfig,
178
+ isEnabled,
179
+
180
+ // Middleware for frameworks (optional, for better route extraction)
181
+ expressMiddleware,
182
+ expressErrorMiddleware,
183
+ fastifyPlugin,
184
+ fastifyErrorHandler,
185
+
186
+ // Utilities (for custom instrumentation)
187
+ normalizeRoute,
188
+ extractRoute,
189
+ RouteRegistry,
190
+ getAggregator,
191
+
192
+ // MongoDB instrumentation
193
+ instrumentMongoDB,
194
+
195
+ // OpenAI instrumentation
196
+ instrumentOpenAI,
197
+
198
+ // Circuit breaker
199
+ createBreaker,
200
+ wrapMongoOperation,
201
+ getBreakerStats
202
+ };
203
+
204
+ // Default export
205
+ export default {
206
+ initialize,
207
+ shutdown,
208
+ getStatus,
209
+ flush,
210
+ expressMiddleware,
211
+ expressErrorMiddleware,
212
+ fastifyPlugin,
213
+ fastifyErrorHandler,
214
+ normalizeRoute,
215
+ extractRoute,
216
+ getAggregator,
217
+ // MongoDB
218
+ instrumentMongoDB,
219
+ // OpenAI
220
+ instrumentOpenAI,
221
+ // Circuit breaker
222
+ createBreaker,
223
+ wrapMongoOperation,
224
+ getBreakerStats
225
+ };