@gravito/monitor 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +305 -0
- package/dist/index.cjs +1008 -0
- package/dist/index.d.cts +516 -0
- package/dist/index.d.ts +516 -0
- package/dist/index.js +955 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# @gravito/monitor
|
|
2
|
+
|
|
3
|
+
Lightweight observability module for Gravito - Health Checks, Metrics, and Tracing.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🏥 **Health Checks** - Kubernetes-ready `/health`, `/ready`, `/live` endpoints
|
|
8
|
+
- 📊 **Metrics** - Prometheus-compatible `/metrics` endpoint
|
|
9
|
+
- 🔍 **Tracing** - OpenTelemetry OTLP support (via external Collector)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add @gravito/monitor
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For OpenTelemetry tracing (optional):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun add @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { PlanetCore } from 'gravito-core'
|
|
27
|
+
import { MonitorOrbit } from '@gravito/monitor'
|
|
28
|
+
|
|
29
|
+
const core = new PlanetCore()
|
|
30
|
+
|
|
31
|
+
core.orbit(new MonitorOrbit({
|
|
32
|
+
health: {
|
|
33
|
+
enabled: true,
|
|
34
|
+
path: '/health',
|
|
35
|
+
readyPath: '/ready',
|
|
36
|
+
livePath: '/live',
|
|
37
|
+
},
|
|
38
|
+
metrics: {
|
|
39
|
+
enabled: true,
|
|
40
|
+
path: '/metrics',
|
|
41
|
+
prefix: 'myapp_',
|
|
42
|
+
},
|
|
43
|
+
tracing: {
|
|
44
|
+
enabled: true,
|
|
45
|
+
serviceName: 'my-gravito-app',
|
|
46
|
+
endpoint: 'http://localhost:4318/v1/traces',
|
|
47
|
+
},
|
|
48
|
+
}))
|
|
49
|
+
|
|
50
|
+
await core.liftoff()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Health Checks
|
|
54
|
+
|
|
55
|
+
### Default Endpoints
|
|
56
|
+
|
|
57
|
+
| Endpoint | Description |
|
|
58
|
+
|----------|-------------|
|
|
59
|
+
| `GET /health` | Full health check with all registered checks |
|
|
60
|
+
| `GET /ready` | Kubernetes readiness probe |
|
|
61
|
+
| `GET /live` | Kubernetes liveness probe |
|
|
62
|
+
|
|
63
|
+
### Registering Custom Checks
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const monitor = core.services.get('monitor')
|
|
67
|
+
|
|
68
|
+
// Register a database check
|
|
69
|
+
monitor.health.register('database', async () => {
|
|
70
|
+
const isConnected = await db.ping()
|
|
71
|
+
return isConnected
|
|
72
|
+
? { status: 'healthy' }
|
|
73
|
+
: { status: 'unhealthy', message: 'Database disconnected' }
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// Register a Redis check
|
|
77
|
+
monitor.health.register('redis', async () => {
|
|
78
|
+
const result = await redis.ping()
|
|
79
|
+
return { status: result === 'PONG' ? 'healthy' : 'unhealthy' }
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Built-in Check Factories
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import {
|
|
87
|
+
createDatabaseCheck,
|
|
88
|
+
createRedisCheck,
|
|
89
|
+
createMemoryCheck,
|
|
90
|
+
createHttpCheck
|
|
91
|
+
} from '@gravito/monitor'
|
|
92
|
+
|
|
93
|
+
// Database check
|
|
94
|
+
monitor.health.register('db', createDatabaseCheck(() => db.isConnected()))
|
|
95
|
+
|
|
96
|
+
// Memory check (warns at 90% heap usage)
|
|
97
|
+
monitor.health.register('memory', createMemoryCheck({ maxHeapUsedPercent: 90 }))
|
|
98
|
+
|
|
99
|
+
// External service check
|
|
100
|
+
monitor.health.register('api', createHttpCheck('https://api.example.com/health'))
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Health Response Format
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"status": "healthy",
|
|
108
|
+
"timestamp": "2024-12-25T12:00:00Z",
|
|
109
|
+
"uptime": 3600,
|
|
110
|
+
"checks": {
|
|
111
|
+
"database": { "status": "healthy", "latency": 5 },
|
|
112
|
+
"redis": { "status": "healthy", "latency": 2 },
|
|
113
|
+
"memory": {
|
|
114
|
+
"status": "healthy",
|
|
115
|
+
"details": { "heapUsedPercent": "45.2" }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Metrics
|
|
122
|
+
|
|
123
|
+
### Prometheus Endpoint
|
|
124
|
+
|
|
125
|
+
The `/metrics` endpoint exposes metrics in Prometheus text format:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
# HELP myapp_http_requests_total Total HTTP requests
|
|
129
|
+
# TYPE myapp_http_requests_total counter
|
|
130
|
+
myapp_http_requests_total{method="GET",path="/api/users",status="200"} 150
|
|
131
|
+
|
|
132
|
+
# HELP myapp_http_request_duration_seconds HTTP request duration
|
|
133
|
+
# TYPE myapp_http_request_duration_seconds histogram
|
|
134
|
+
myapp_http_request_duration_seconds_bucket{le="0.01"} 50
|
|
135
|
+
myapp_http_request_duration_seconds_bucket{le="0.1"} 120
|
|
136
|
+
myapp_http_request_duration_seconds_sum 12.5
|
|
137
|
+
myapp_http_request_duration_seconds_count 150
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Custom Metrics
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
const monitor = core.services.get('monitor')
|
|
144
|
+
|
|
145
|
+
// Counter
|
|
146
|
+
const requestCounter = monitor.metrics.counter({
|
|
147
|
+
name: 'api_requests_total',
|
|
148
|
+
help: 'Total API requests',
|
|
149
|
+
labels: ['endpoint', 'status'],
|
|
150
|
+
})
|
|
151
|
+
requestCounter.inc({ endpoint: '/users', status: '200' })
|
|
152
|
+
|
|
153
|
+
// Gauge
|
|
154
|
+
const activeConnections = monitor.metrics.gauge({
|
|
155
|
+
name: 'active_connections',
|
|
156
|
+
help: 'Current active connections',
|
|
157
|
+
})
|
|
158
|
+
activeConnections.set(42)
|
|
159
|
+
activeConnections.inc()
|
|
160
|
+
activeConnections.dec()
|
|
161
|
+
|
|
162
|
+
// Histogram
|
|
163
|
+
const responseTime = monitor.metrics.histogram({
|
|
164
|
+
name: 'response_time_seconds',
|
|
165
|
+
help: 'Response time in seconds',
|
|
166
|
+
labels: ['endpoint'],
|
|
167
|
+
buckets: [0.01, 0.05, 0.1, 0.5, 1],
|
|
168
|
+
})
|
|
169
|
+
responseTime.observe(0.125, { endpoint: '/users' })
|
|
170
|
+
|
|
171
|
+
// Timer helper
|
|
172
|
+
const stopTimer = responseTime.startTimer({ endpoint: '/users' })
|
|
173
|
+
// ... do work ...
|
|
174
|
+
stopTimer() // Records duration automatically
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Tracing
|
|
178
|
+
|
|
179
|
+
### OpenTelemetry Integration
|
|
180
|
+
|
|
181
|
+
@gravito/monitor uses the **OTLP (OpenTelemetry Protocol)** standard. To send traces to different backends:
|
|
182
|
+
|
|
183
|
+
| Backend | Method |
|
|
184
|
+
|---------|--------|
|
|
185
|
+
| **Jaeger** | OTLP Collector → Jaeger |
|
|
186
|
+
| **Zipkin** | OTLP Collector → Zipkin |
|
|
187
|
+
| **AWS X-Ray** | AWS ADOT Collector |
|
|
188
|
+
| **Google Cloud Trace** | GCP OTLP Collector |
|
|
189
|
+
| **Datadog** | Datadog Agent (OTLP) |
|
|
190
|
+
|
|
191
|
+
### Configuration
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
new MonitorOrbit({
|
|
195
|
+
tracing: {
|
|
196
|
+
enabled: true,
|
|
197
|
+
serviceName: 'my-app',
|
|
198
|
+
serviceVersion: '1.0.0',
|
|
199
|
+
endpoint: 'http://localhost:4318/v1/traces', // OTLP HTTP
|
|
200
|
+
sampleRate: 1.0, // 100% sampling
|
|
201
|
+
resourceAttributes: {
|
|
202
|
+
'deployment.environment': 'production',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Manual Spans
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const tracer = core.services.get('tracing')
|
|
212
|
+
|
|
213
|
+
// Start a span
|
|
214
|
+
const span = tracer.startSpan('process-order', {
|
|
215
|
+
attributes: { 'order.id': '12345' },
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
// Do work...
|
|
220
|
+
tracer.addEvent(span, 'payment-processed')
|
|
221
|
+
tracer.setAttribute(span, 'order.total', 99.99)
|
|
222
|
+
tracer.endSpan(span, 'ok')
|
|
223
|
+
} catch (error) {
|
|
224
|
+
tracer.endSpan(span, 'error')
|
|
225
|
+
throw error
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Trace Context Propagation
|
|
230
|
+
|
|
231
|
+
The tracing middleware automatically:
|
|
232
|
+
- Extracts `traceparent` header from incoming requests
|
|
233
|
+
- Injects trace context into outgoing requests
|
|
234
|
+
- Records HTTP method, path, status code
|
|
235
|
+
|
|
236
|
+
## Kubernetes Integration
|
|
237
|
+
|
|
238
|
+
### Deployment Example
|
|
239
|
+
|
|
240
|
+
```yaml
|
|
241
|
+
apiVersion: apps/v1
|
|
242
|
+
kind: Deployment
|
|
243
|
+
metadata:
|
|
244
|
+
name: my-gravito-app
|
|
245
|
+
spec:
|
|
246
|
+
template:
|
|
247
|
+
spec:
|
|
248
|
+
containers:
|
|
249
|
+
- name: app
|
|
250
|
+
image: my-app:latest
|
|
251
|
+
ports:
|
|
252
|
+
- containerPort: 3000
|
|
253
|
+
livenessProbe:
|
|
254
|
+
httpGet:
|
|
255
|
+
path: /live
|
|
256
|
+
port: 3000
|
|
257
|
+
initialDelaySeconds: 5
|
|
258
|
+
periodSeconds: 10
|
|
259
|
+
readinessProbe:
|
|
260
|
+
httpGet:
|
|
261
|
+
path: /ready
|
|
262
|
+
port: 3000
|
|
263
|
+
initialDelaySeconds: 5
|
|
264
|
+
periodSeconds: 5
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### ServiceMonitor for Prometheus
|
|
268
|
+
|
|
269
|
+
```yaml
|
|
270
|
+
apiVersion: monitoring.coreos.com/v1
|
|
271
|
+
kind: ServiceMonitor
|
|
272
|
+
metadata:
|
|
273
|
+
name: my-gravito-app
|
|
274
|
+
spec:
|
|
275
|
+
selector:
|
|
276
|
+
matchLabels:
|
|
277
|
+
app: my-gravito-app
|
|
278
|
+
endpoints:
|
|
279
|
+
- port: http
|
|
280
|
+
path: /metrics
|
|
281
|
+
interval: 15s
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Configuration Reference
|
|
285
|
+
|
|
286
|
+
| Option | Type | Default | Description |
|
|
287
|
+
|--------|------|---------|-------------|
|
|
288
|
+
| `health.enabled` | boolean | `true` | Enable health endpoints |
|
|
289
|
+
| `health.path` | string | `/health` | Full health check path |
|
|
290
|
+
| `health.readyPath` | string | `/ready` | Readiness probe path |
|
|
291
|
+
| `health.livePath` | string | `/live` | Liveness probe path |
|
|
292
|
+
| `health.timeout` | number | `5000` | Check timeout (ms) |
|
|
293
|
+
| `health.cacheTtl` | number | `0` | Cache duration (ms) |
|
|
294
|
+
| `metrics.enabled` | boolean | `true` | Enable metrics endpoint |
|
|
295
|
+
| `metrics.path` | string | `/metrics` | Metrics endpoint path |
|
|
296
|
+
| `metrics.prefix` | string | `gravito_` | Metric name prefix |
|
|
297
|
+
| `metrics.defaultMetrics` | boolean | `true` | Collect default metrics |
|
|
298
|
+
| `tracing.enabled` | boolean | `false` | Enable tracing |
|
|
299
|
+
| `tracing.serviceName` | string | `gravito-app` | Service name |
|
|
300
|
+
| `tracing.endpoint` | string | `http://localhost:4318/v1/traces` | OTLP endpoint |
|
|
301
|
+
| `tracing.sampleRate` | number | `1.0` | Sample rate (0.0-1.0) |
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
MIT
|