@codebaz/nextdoctor-agent 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +3 -0
- package/README.md +568 -0
- package/dist/detectors/__tests__/cold-start-threshold.test.d.ts +2 -0
- package/dist/detectors/__tests__/cold-start-threshold.test.d.ts.map +1 -0
- package/dist/detectors/__tests__/cold-start-threshold.test.js +156 -0
- package/dist/detectors/__tests__/cold-start-threshold.test.js.map +1 -0
- package/dist/detectors/__tests__/dynamic-route-candidate.test.d.ts +2 -0
- package/dist/detectors/__tests__/dynamic-route-candidate.test.d.ts.map +1 -0
- package/dist/detectors/__tests__/dynamic-route-candidate.test.js +318 -0
- package/dist/detectors/__tests__/dynamic-route-candidate.test.js.map +1 -0
- package/dist/detectors/__tests__/fetch-no-cache.test.d.ts +2 -0
- package/dist/detectors/__tests__/fetch-no-cache.test.d.ts.map +1 -0
- package/dist/detectors/__tests__/fetch-no-cache.test.js +199 -0
- package/dist/detectors/__tests__/fetch-no-cache.test.js.map +1 -0
- package/dist/detectors/base-detector.d.ts +17 -0
- package/dist/detectors/base-detector.d.ts.map +1 -0
- package/dist/detectors/base-detector.js +50 -0
- package/dist/detectors/base-detector.js.map +1 -0
- package/dist/detectors/cold-start-threshold.detector.d.ts +11 -0
- package/dist/detectors/cold-start-threshold.detector.d.ts.map +1 -0
- package/dist/detectors/cold-start-threshold.detector.js +87 -0
- package/dist/detectors/cold-start-threshold.detector.js.map +1 -0
- package/dist/detectors/dynamic-route-candidate.detector.d.ts +23 -0
- package/dist/detectors/dynamic-route-candidate.detector.d.ts.map +1 -0
- package/dist/detectors/dynamic-route-candidate.detector.js +96 -0
- package/dist/detectors/dynamic-route-candidate.detector.js.map +1 -0
- package/dist/detectors/fetch-no-cache.detector.d.ts +12 -0
- package/dist/detectors/fetch-no-cache.detector.d.ts.map +1 -0
- package/dist/detectors/fetch-no-cache.detector.js +178 -0
- package/dist/detectors/fetch-no-cache.detector.js.map +1 -0
- package/dist/detectors/index.d.ts +28 -0
- package/dist/detectors/index.d.ts.map +1 -0
- package/dist/detectors/index.js +97 -0
- package/dist/detectors/index.js.map +1 -0
- package/dist/detectors/types.d.ts +32 -0
- package/dist/detectors/types.d.ts.map +1 -0
- package/dist/detectors/types.js +2 -0
- package/dist/detectors/types.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +133 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +363 -0
- package/dist/init.js.map +1 -0
- package/dist/middleware.d.ts +10 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +61 -0
- package/dist/middleware.js.map +1 -0
- package/dist/optimization.d.ts +43 -0
- package/dist/optimization.d.ts.map +1 -0
- package/dist/optimization.js +139 -0
- package/dist/optimization.js.map +1 -0
- package/dist/system-monitor.d.ts +124 -0
- package/dist/system-monitor.d.ts.map +1 -0
- package/dist/system-monitor.js +221 -0
- package/dist/system-monitor.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
- package/src/detectors/__tests__/cold-start-threshold.test.ts +183 -0
- package/src/detectors/__tests__/dynamic-route-candidate.test.ts +365 -0
- package/src/detectors/__tests__/fetch-no-cache.test.ts +239 -0
- package/src/detectors/base-detector.ts +69 -0
- package/src/detectors/cold-start-threshold.detector.ts +95 -0
- package/src/detectors/dynamic-route-candidate.detector.ts +107 -0
- package/src/detectors/fetch-no-cache.detector.ts +204 -0
- package/src/detectors/index.ts +127 -0
- package/src/detectors/types.ts +38 -0
- package/src/index.ts +60 -0
- package/src/init.ts +424 -0
- package/src/middleware.ts +75 -0
- package/src/optimization.ts +164 -0
- package/src/system-monitor.ts +295 -0
- package/src/types.ts +66 -0
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
# `@codebaz/nextdoctor-agent`
|
|
2
|
+
|
|
3
|
+
**Enterprise-grade OpenTelemetry agent for Next.js.** Automatic performance monitoring, anomaly detection, and issue diagnostics for production applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Zero-Config Instrumentation**: Works out-of-the-box via Next.js Instrumentation Hook
|
|
8
|
+
- ✅ **Vercel Native**: Seamless integration with Vercel deployments and `@vercel/otel`
|
|
9
|
+
- ✅ **CPU & Memory Monitoring**: Real-time system resource tracking with threshold alerts
|
|
10
|
+
- ✅ **Intelligent Sampling**: Adaptive sampling rate to manage trace volume
|
|
11
|
+
- ✅ **Performance Monitoring**: Automatic detection of slow routes and database queries
|
|
12
|
+
- ✅ **Anomaly Detection**: Real-time issue detection with actionable suggestions
|
|
13
|
+
- ✅ **Circuit Breaker**: Protected exports with automatic failover
|
|
14
|
+
- ✅ **Batch Processing**: Memory-efficient trace batching
|
|
15
|
+
- ✅ **Enterprise Logging**: Structured logging with multiple levels (DEBUG, INFO, WARN, ERROR)
|
|
16
|
+
- ✅ **Custom Metrics**: Easy API for application-level metrics
|
|
17
|
+
- ✅ **Health Monitoring**: Real-time agent health status
|
|
18
|
+
- ✅ **Middleware Support**: Ready-made instrumentation for API routes
|
|
19
|
+
- ✅ **Retry Policy**: Configurable exponential backoff with jitter
|
|
20
|
+
- ✅ **Multi-Environment**: Support for development, staging, and production
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @codebaz/nextdoctor-agent
|
|
26
|
+
# or
|
|
27
|
+
pnpm add @codebaz/nextdoctor-agent
|
|
28
|
+
# or
|
|
29
|
+
yarn add @codebaz/nextdoctor-agent
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Requires **Next.js 14+** and **Node.js 18+**
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
### 1. Initialize in `instrumentation.ts`
|
|
37
|
+
|
|
38
|
+
Create `instrumentation.ts` in your Next.js project root:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { initNextDoctor } from '@codebaz/nextdoctor-agent';
|
|
42
|
+
|
|
43
|
+
export default async function instrumentation() {
|
|
44
|
+
// Only initialize in production
|
|
45
|
+
if (process.env.NODE_ENV === 'development') return;
|
|
46
|
+
|
|
47
|
+
await initNextDoctor({
|
|
48
|
+
projectToken: process.env.NEXTDOCTOR_PROJECT_TOKEN!,
|
|
49
|
+
endpoint: process.env.NEXTDOCTOR_ENDPOINT || 'https://ingest.nextdoctor.dev',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Add Environment Variables
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
NEXTDOCTOR_PROJECT_TOKEN=your-secure-project-token
|
|
58
|
+
NEXTDOCTOR_ENDPOINT=https://ingest.nextdoctor.dev
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Deploy
|
|
62
|
+
|
|
63
|
+
Your Next.js app will now automatically:
|
|
64
|
+
- 🔍 Capture OpenTelemetry traces
|
|
65
|
+
- 📊 Report performance metrics
|
|
66
|
+
- 🚨 Detect performance issues
|
|
67
|
+
- 📤 Send data to NextDoctor dashboard
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
### Advanced Setup
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { initNextDoctor, LogLevel } from '@codebaz/nextdoctor-agent';
|
|
75
|
+
|
|
76
|
+
await initNextDoctor({
|
|
77
|
+
// Required
|
|
78
|
+
projectToken: process.env.NEXTDOCTOR_PROJECT_TOKEN!,
|
|
79
|
+
endpoint: process.env.NEXTDOCTOR_ENDPOINT || 'https://ingest.nextdoctor.dev',
|
|
80
|
+
|
|
81
|
+
// Optional - Enterprise Features
|
|
82
|
+
enabled: true,
|
|
83
|
+
serviceName: 'my-next-app',
|
|
84
|
+
version: '1.2.3',
|
|
85
|
+
environment: 'production',
|
|
86
|
+
logLevel: LogLevel.INFO,
|
|
87
|
+
samplingRate: 1.0, // 0.0 to 1.0
|
|
88
|
+
timeout: 30000, // ms
|
|
89
|
+
enableDebugLogging: false,
|
|
90
|
+
|
|
91
|
+
// Exporter Configuration
|
|
92
|
+
exporter: {
|
|
93
|
+
type: 'vercel', // or 'otlp-http', 'none'
|
|
94
|
+
batchSize: 100,
|
|
95
|
+
batchTimeoutMs: 5000,
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// Retry Policy
|
|
99
|
+
retryPolicy: {
|
|
100
|
+
maxRetries: 5,
|
|
101
|
+
initialDelayMs: 100,
|
|
102
|
+
maxDelayMs: 30000,
|
|
103
|
+
backoffMultiplier: 2,
|
|
104
|
+
randomizationFactor: 0.1,
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
// Feature Flags
|
|
108
|
+
captureLogs: true,
|
|
109
|
+
captureMetrics: true,
|
|
110
|
+
captureExceptions: true,
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### `initNextDoctor(config)`
|
|
117
|
+
|
|
118
|
+
Initializes the NextDoctor agent with automatic retries and validation.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
await initNextDoctor({
|
|
122
|
+
projectToken: '...',
|
|
123
|
+
endpoint: '...',
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `shutdownNextDoctor()`
|
|
128
|
+
|
|
129
|
+
Gracefully shuts down the agent (e.g., before serverless function timeout).
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
await shutdownNextDoctor();
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `reportMetric(name, value, attributes?)`
|
|
136
|
+
|
|
137
|
+
Report a custom application metric.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { reportMetric } from '@codebaz/nextdoctor-agent';
|
|
141
|
+
|
|
142
|
+
reportMetric('checkout.total', 12999, {
|
|
143
|
+
currency: 'USD',
|
|
144
|
+
items: 5,
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `getHealthStatus()`
|
|
149
|
+
|
|
150
|
+
Get real-time agent health information.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { getHealthStatus } from '@codebaz/nextdoctor-agent';
|
|
154
|
+
|
|
155
|
+
const health = getHealthStatus();
|
|
156
|
+
console.log(health);
|
|
157
|
+
// {
|
|
158
|
+
// initialized: true,
|
|
159
|
+
// isHealthy: true,
|
|
160
|
+
// exporterStatus: 'healthy',
|
|
161
|
+
// bufferedSpans: 42,
|
|
162
|
+
// errorCount: 0
|
|
163
|
+
// }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### `getDetectedIssues()`
|
|
167
|
+
|
|
168
|
+
Retrieve detected performance issues and anomalies.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { getDetectedIssues } from '@codebaz/nextdoctor-agent';
|
|
172
|
+
|
|
173
|
+
const issues = getDetectedIssues();
|
|
174
|
+
issues.forEach(issue => {
|
|
175
|
+
console.log(`${issue.severity}: ${issue.message}`);
|
|
176
|
+
console.log(`💡 ${issue.suggestion}`);
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### System Monitoring (CPU & Memory)
|
|
181
|
+
|
|
182
|
+
The agent automatically monitors system resources and detects performance degradation.
|
|
183
|
+
|
|
184
|
+
#### `getSystemMetrics()`
|
|
185
|
+
|
|
186
|
+
Get real-time CPU and memory metrics.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { getSystemMetrics } from '@codebaz/nextdoctor-agent';
|
|
190
|
+
|
|
191
|
+
const metrics = getSystemMetrics();
|
|
192
|
+
console.log(metrics);
|
|
193
|
+
// {
|
|
194
|
+
// cpu: {
|
|
195
|
+
// timestamp: 1712154800000,
|
|
196
|
+
// usage: 45.2, // percentage 0-100
|
|
197
|
+
// coreCount: 4,
|
|
198
|
+
// systemLoadPerCore: 1.13,
|
|
199
|
+
// loadAverage: {
|
|
200
|
+
// oneMinute: 4.52,
|
|
201
|
+
// fiveMinutes: 3.89,
|
|
202
|
+
// fifteenMinutes: 2.45
|
|
203
|
+
// }
|
|
204
|
+
// },
|
|
205
|
+
// memory: {
|
|
206
|
+
// timestamp: 1712154800000,
|
|
207
|
+
// heapUsed: 124567890, // bytes
|
|
208
|
+
// heapTotal: 536870912,
|
|
209
|
+
// heapUsagePercent: 23.2,
|
|
210
|
+
// systemMemoryUsed: 8589934592, // bytes
|
|
211
|
+
// systemMemoryTotal: 34359738368,
|
|
212
|
+
// systemMemoryUsagePercent: 25.0
|
|
213
|
+
// },
|
|
214
|
+
// uptime: 3600000 // milliseconds
|
|
215
|
+
// }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### `getSystemHealth(cpuThreshold, memThreshold)`
|
|
219
|
+
|
|
220
|
+
Check system health with configurable thresholds (default: CPU 80%, Memory 85%).
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { getSystemHealth } from '@codebaz/nextdoctor-agent';
|
|
224
|
+
|
|
225
|
+
const health = getSystemHealth(80, 85); // CPU and Memory thresholds
|
|
226
|
+
console.log(health);
|
|
227
|
+
// {
|
|
228
|
+
// healthy: true,
|
|
229
|
+
// warnings: [
|
|
230
|
+
// 'High CPU usage: 92% (threshold: 80%)',
|
|
231
|
+
// 'High heap memory: 89% (threshold: 85%)'
|
|
232
|
+
// ],
|
|
233
|
+
// metrics: { ... }
|
|
234
|
+
// }
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### `getSystemSummary()`
|
|
238
|
+
|
|
239
|
+
Get a formatted dashboard-friendly summary.
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import { getSystemSummary } from '@codebaz/nextdoctor-agent';
|
|
243
|
+
|
|
244
|
+
const summary = getSystemSummary();
|
|
245
|
+
console.log(summary);
|
|
246
|
+
// {
|
|
247
|
+
// status: 'warning',
|
|
248
|
+
// cpu: {
|
|
249
|
+
// usage: '45.2%',
|
|
250
|
+
// cores: 4,
|
|
251
|
+
// load: { oneMinute: 4.52, fiveMinutes: 3.89, fifteenMinutes: 2.45 }
|
|
252
|
+
// },
|
|
253
|
+
// memory: {
|
|
254
|
+
// heap: {
|
|
255
|
+
// used: '118.7 MB',
|
|
256
|
+
// total: '512 MB',
|
|
257
|
+
// usage: '23.2%'
|
|
258
|
+
// },
|
|
259
|
+
// system: {
|
|
260
|
+
// used: '8 GB',
|
|
261
|
+
// total: '32 GB',
|
|
262
|
+
// usage: '25.0%'
|
|
263
|
+
// }
|
|
264
|
+
// },
|
|
265
|
+
// warnings: []
|
|
266
|
+
// }
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### Monitoring CPU in API Routes
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import { withNextDoctorMonitoring, getSystemMetrics } from '@codebaz/nextdoctor-agent';
|
|
273
|
+
|
|
274
|
+
const handler = async (req, res) => {
|
|
275
|
+
const metrics = getSystemMetrics();
|
|
276
|
+
|
|
277
|
+
if (metrics && metrics.cpu.usage > 80) {
|
|
278
|
+
console.warn('High CPU detected, consider rate limiting');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const data = await processData();
|
|
282
|
+
res.json(data);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export default withNextDoctorMonitoring(handler);
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Middleware
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
### API Route Monitoring
|
|
292
|
+
|
|
293
|
+
Automatically capture and monitor API routes:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// app/api/users/route.ts
|
|
297
|
+
import { withNextDoctorMonitoring } from '@codebaz/nextdoctor-agent/middleware';
|
|
298
|
+
|
|
299
|
+
const handler = async (req, res) => {
|
|
300
|
+
const users = await db.users.findAll();
|
|
301
|
+
res.json(users);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export default withNextDoctorMonitoring(handler);
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Operation Timing
|
|
308
|
+
|
|
309
|
+
Monitor async operations with automatic timing:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { withNextDoctorTiming } from '@codebaz/nextdoctor-agent/middleware';
|
|
313
|
+
|
|
314
|
+
const users = await withNextDoctorTiming(
|
|
315
|
+
'fetch-users',
|
|
316
|
+
async () => {
|
|
317
|
+
return await db.users.findAll();
|
|
318
|
+
},
|
|
319
|
+
{ source: 'homepage' }
|
|
320
|
+
);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Enterprise Features
|
|
324
|
+
|
|
325
|
+
### Intelligent Sampling
|
|
326
|
+
|
|
327
|
+
Automatically adapts sampling rate based on trace volume:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { IntelligentSampler } from '@codebaz/nextdoctor-agent/optimization';
|
|
331
|
+
|
|
332
|
+
const sampler = new IntelligentSampler(0.1); // Start at 10%
|
|
333
|
+
if (sampler.shouldSample('http.request')) {
|
|
334
|
+
// capture trace
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Circuit Breaker
|
|
339
|
+
|
|
340
|
+
Protects against degraded exporters:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { CircuitBreaker } from '@codebaz/nextdoctor-agent/optimization';
|
|
344
|
+
|
|
345
|
+
const breaker = new CircuitBreaker();
|
|
346
|
+
const result = await breaker.execute(async () => {
|
|
347
|
+
return await exporter.export(traces);
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Batch Processing
|
|
352
|
+
|
|
353
|
+
Memory-efficient batch processing for high-throughput scenarios:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
import { BatchProcessor } from '@codebaz/nextdoctor-agent/optimization';
|
|
357
|
+
|
|
358
|
+
const processor = new BatchProcessor(
|
|
359
|
+
100, // batch size
|
|
360
|
+
5000, // timeout ms
|
|
361
|
+
async (batch) => {
|
|
362
|
+
await exporter.export(batch);
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
processor.add(spanData);
|
|
367
|
+
await processor.flush();
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Detection Engine
|
|
371
|
+
|
|
372
|
+
The NextDoctor Detection Engine automatically analyzes OpenTelemetry traces and identifies Next.js-specific performance anti-patterns. Unlike generic monitoring, it provides **actionable diagnostics** with concrete code suggestions.
|
|
373
|
+
|
|
374
|
+
### Automatic Issue Detection
|
|
375
|
+
|
|
376
|
+
The engine continuously monitors traces and reports detected issues via `getDetectedIssues()`:
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
import { getDetectedIssues } from '@codebaz/nextdoctor-agent';
|
|
380
|
+
|
|
381
|
+
// In a dashboard or monitoring endpoint
|
|
382
|
+
app.get('/api/nextdoctor/issues', (req, res) => {
|
|
383
|
+
const issues = getDetectedIssues();
|
|
384
|
+
res.json({
|
|
385
|
+
total: issues.length,
|
|
386
|
+
byRoute: groupBy(issues, i => i.route),
|
|
387
|
+
critical: issues.filter(i => i.severity === 'critical'),
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Three MVP Detection Rules
|
|
393
|
+
|
|
394
|
+
#### 1. **Cold Start Threshold** (Edge Functions)
|
|
395
|
+
|
|
396
|
+
Detects when your Next.js Edge Function startup time exceeds 800ms, or when there's high latency variance (P50 vs P99 > 2000ms) indicating intermittent cold starts.
|
|
397
|
+
|
|
398
|
+
**Example Detection:**
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"id": "COLD_START_THRESHOLD",
|
|
402
|
+
"severity": "critical",
|
|
403
|
+
"message": "Edge function cold start: 1200ms (threshold: 800ms)",
|
|
404
|
+
"route": "/api/auth",
|
|
405
|
+
"suggestion": "Move heavy imports outside handler, consider Node.js runtime for this route, or implement keep-warm strategy"
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**When it triggers:**
|
|
410
|
+
- Startup time > 800ms on Edge runtime
|
|
411
|
+
- P99 latency is 2000ms+ higher than P50 (intermittent cold starts)
|
|
412
|
+
|
|
413
|
+
#### 2. **Uncached Fetch Detection** (Server Components)
|
|
414
|
+
|
|
415
|
+
Detects `fetch()` calls in Server Components without cache directives, especially N+1 patterns where the same URL is fetched multiple times.
|
|
416
|
+
|
|
417
|
+
**Example Detection - Single Fetch:**
|
|
418
|
+
```json
|
|
419
|
+
{
|
|
420
|
+
"id": "FETCH_NO_CACHE",
|
|
421
|
+
"severity": "high",
|
|
422
|
+
"message": "Uncached fetch(): https://api.example.com/user",
|
|
423
|
+
"route": "/dashboard",
|
|
424
|
+
"suggestion": "Add cache directive. Example:\n\nconst data = await fetch(\n 'https://api.example.com/user',\n { cache: 'force-cache' }\n);\n\nOr use revalidate:\n\nconst data = await fetch(..., {\n next: { revalidate: 3600 }\n});"
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Example Detection - N+1 Pattern:**
|
|
429
|
+
```json
|
|
430
|
+
{
|
|
431
|
+
"id": "FETCH_NO_CACHE",
|
|
432
|
+
"severity": "critical",
|
|
433
|
+
"message": "N+1 fetch pattern: https://api.example.com/posts called 5 times without cache",
|
|
434
|
+
"route": "/user/[id]",
|
|
435
|
+
"suggestion": "This URL is being fetched 5 times in a single request (N+1 pattern). Refactor to:\n\n1. Batch fetch all posts in one request\n2. Use Next.js Data Cache (cache directive)\n3. Use Database Queries instead of HTTP fetches"
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**When it triggers:**
|
|
440
|
+
- `fetch()` called without `cache: 'no-store'` or `cache: 'no-cache'` in Server Component
|
|
441
|
+
- No `next.revalidate` specified
|
|
442
|
+
- Filtered: Ignores POST/PUT/DELETE, internal URLs, and calls < 50ms
|
|
443
|
+
|
|
444
|
+
#### 3. **Dynamic Route Candidate** (Unnecessary Dynamic Rendering)
|
|
445
|
+
|
|
446
|
+
Detects when `cookies()` or `headers()` are called but never actually read specific values, forcing the entire page to be dynamic when it could be static.
|
|
447
|
+
|
|
448
|
+
**Example Detection:**
|
|
449
|
+
```json
|
|
450
|
+
{
|
|
451
|
+
"id": "DYNAMIC_ROUTE_CANDIDATE",
|
|
452
|
+
"severity": "warning",
|
|
453
|
+
"message": "Unnecessary dynamic rendering: cookies() called but no specific key accessed",
|
|
454
|
+
"route": "/products/[id]",
|
|
455
|
+
"suggestion": "Option 1: Remove the cookies() call if not needed\n\nOption 2: Move to Server Action:\n\n'use server';\nexport async function getUser() {\n const sessionId = cookies().get('session')?.value;\n // ...\n}\n\nOption 3: Add export const dynamic = 'force-static' if this route is truly static"
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**When it triggers:**
|
|
460
|
+
- `cookies()` or `headers()` function is invoked
|
|
461
|
+
- No child span shows specific key access (e.g., `cookies().get('key')`)
|
|
462
|
+
- Route contains `[` indicating dynamic segment
|
|
463
|
+
|
|
464
|
+
### Accessing Detected Issues
|
|
465
|
+
|
|
466
|
+
#### Real-time in Application
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
// app/api/health/route.ts
|
|
470
|
+
import { getDetectedIssues, getHealthStatus } from '@codebaz/nextdoctor-agent';
|
|
471
|
+
|
|
472
|
+
export async function GET() {
|
|
473
|
+
const issues = getDetectedIssues();
|
|
474
|
+
const health = getHealthStatus();
|
|
475
|
+
|
|
476
|
+
return Response.json({
|
|
477
|
+
agent: health,
|
|
478
|
+
detected: {
|
|
479
|
+
critical: issues.filter(i => i.severity === 'critical'),
|
|
480
|
+
high: issues.filter(i => i.severity === 'high'),
|
|
481
|
+
count: issues.length,
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### In Dashboard
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// pages/dashboard/diagnostics.tsx
|
|
491
|
+
import { useSuspenseQuery } from '@tanstack/react-query';
|
|
492
|
+
|
|
493
|
+
export default function DiagnosticsPage() {
|
|
494
|
+
const { data } = useSuspenseQuery({
|
|
495
|
+
queryKey: ['nextdoctor/issues'],
|
|
496
|
+
queryFn: () => fetch('/api/nextdoctor/issues').then(r => r.json()),
|
|
497
|
+
refetchInterval: 5000,
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
return (
|
|
501
|
+
<div>
|
|
502
|
+
<h2>NextDoctor Issues</h2>
|
|
503
|
+
{data.critical.map(issue => (
|
|
504
|
+
<div key={issue.id} className="critical">
|
|
505
|
+
<strong>{issue.message}</strong>
|
|
506
|
+
<pre>{issue.suggestion}</pre>
|
|
507
|
+
</div>
|
|
508
|
+
))}
|
|
509
|
+
</div>
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### Deduplication & Smart Reporting
|
|
515
|
+
|
|
516
|
+
The engine automatically:
|
|
517
|
+
- **Deduplicates** identical issues within 60-second windows
|
|
518
|
+
- **Groups** similar issues (e.g., multiple fetches to same URL)
|
|
519
|
+
- **Escalates severity** for N+1 patterns (1x = high, 3x+ = critical)
|
|
520
|
+
- **Tracks counts** so you know how many times an issue occurred
|
|
521
|
+
- **Sorts results** by severity (critical → high → warning → info)
|
|
522
|
+
|
|
523
|
+
## Telemetry Types
|
|
524
|
+
|
|
525
|
+
### Supported Metrics
|
|
526
|
+
|
|
527
|
+
- **API Latency**: HTTP request/response times
|
|
528
|
+
- **Database Performance**: Query execution times
|
|
529
|
+
- **Memory Usage**: Heap size and GC metrics
|
|
530
|
+
- **Error Rates**: Exception tracking
|
|
531
|
+
- **Custom Metrics**: Application-specific KPIs
|
|
532
|
+
|
|
533
|
+
### Detected Issues
|
|
534
|
+
|
|
535
|
+
The agent automatically detects:
|
|
536
|
+
- Slow API routes (> 3s)
|
|
537
|
+
- N+1 database queries
|
|
538
|
+
- Memory leaks
|
|
539
|
+
- Uncaught exceptions
|
|
540
|
+
- External API timeouts
|
|
541
|
+
|
|
542
|
+
## Environment Variables
|
|
543
|
+
|
|
544
|
+
| Variable | Required | Default | Description |
|
|
545
|
+
|----------|----------|---------|-------------|
|
|
546
|
+
| `NEXTDOCTOR_PROJECT_TOKEN` | ✅ | - | Your project authentication token |
|
|
547
|
+
| `NEXTDOCTOR_ENDPOINT` | ✅ | - | Ingest endpoint URL |
|
|
548
|
+
| `NODE_ENV` | - | - | Set to "production" to enable collection |
|
|
549
|
+
|
|
550
|
+
## Best Practices
|
|
551
|
+
|
|
552
|
+
1. **Use In Production**: Agent is disabled in development by default
|
|
553
|
+
2. **Set Sample Rate**: For high-traffic apps, use `samplingRate: 0.1` to 0.5
|
|
554
|
+
3. **Monitor Health**: Regularly check `getHealthStatus()` in dashboards
|
|
555
|
+
4. **Handle Shutdown**: Call `shutdownNextDoctor()` in serverless timeouts
|
|
556
|
+
5. **Environment-Specific Config**: Use environment variables for endpoint switching
|
|
557
|
+
6. **Error Boundaries**: Custom metrics should wrap try-catch blocks
|
|
558
|
+
|
|
559
|
+
## Support
|
|
560
|
+
|
|
561
|
+
- 📖 [Documentation](https://codebaz.com/nextdoctor)
|
|
562
|
+
- 🐛 [Report Issues](https://github.com/codebaz/nextdoctor/issues)
|
|
563
|
+
- 💬 [Discord Community](https://discord.gg/codebaz)
|
|
564
|
+
- 📧 [Enterprise Support](mailto:enterprise@codebaz.com)
|
|
565
|
+
|
|
566
|
+
## License
|
|
567
|
+
|
|
568
|
+
MIT - See LICENSE file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cold-start-threshold.test.d.ts","sourceRoot":"","sources":["../../../src/detectors/__tests__/cold-start-threshold.test.ts"],"names":[],"mappings":""}
|