monten 0.1.0 → 0.1.2
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 +231 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./banner.png" alt="monten observability banner" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">monten</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Lightweight, production-ready observability for Node.js backends</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img src="https://img.shields.io/badge/version-0.1.0-blue" alt="Version" />
|
|
13
|
+
<img src="https://img.shields.io/badge/status-experimental-orange" alt="Status" />
|
|
14
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="License" />
|
|
15
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node Version" />
|
|
16
|
+
<img src="https://img.shields.io/npm/v/monten?color=red" alt="npm" />
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="#features">Features</a> •
|
|
21
|
+
<a href="#technologies">Technologies</a> •
|
|
22
|
+
<a href="#installation">Installation</a> •
|
|
23
|
+
<a href="#quick-start">Quick Start</a> •
|
|
24
|
+
<a href="#api-reference">API Reference</a> •
|
|
25
|
+
<a href="#contributing">Contributing</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
> ⚠️ **Experimental:** APIs and behavior may change in minor versions. Use with caution in critical systems.
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
| Feature | Description |
|
|
35
|
+
| ------------------------- | ----------------------------------------------------- |
|
|
36
|
+
| 🕐 **HTTP Timing** | Measure total request latency with drop-in middleware |
|
|
37
|
+
| 📊 **Error Tracking** | Automatic error rate tracking with stack traces |
|
|
38
|
+
| 🗄️ **DB Timing** | Explicit instrumentation via `withDbTiming` helper |
|
|
39
|
+
| 🔗 **Request Context** | Per-request scoping with `AsyncLocalStorage` |
|
|
40
|
+
| 📝 **Structured Logging** | JSON-only logs with requestId correlation |
|
|
41
|
+
| 📦 **Metrics Batching** | In-memory buffer with periodic flushing |
|
|
42
|
+
| 🔌 **Zero Coupling** | Fully removable without breaking your app |
|
|
43
|
+
|
|
44
|
+
## Technologies
|
|
45
|
+
|
|
46
|
+
<p align="center">
|
|
47
|
+
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" />
|
|
48
|
+
<img src="https://img.shields.io/badge/Node.js-339933?style=for-the-badge&logo=nodedotjs&logoColor=white" alt="Node.js" />
|
|
49
|
+
<img src="https://img.shields.io/badge/Express-000000?style=for-the-badge&logo=express&logoColor=white" alt="Express" />
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
| Technology | Purpose |
|
|
53
|
+
| --------------------- | ---------------------------------------------------- |
|
|
54
|
+
| **TypeScript** | Type-safe implementation with full declaration files |
|
|
55
|
+
| **Node.js** | Runtime environment (v18+) |
|
|
56
|
+
| **AsyncLocalStorage** | Native request-scoped context propagation |
|
|
57
|
+
| **Express** | Compatible middleware architecture |
|
|
58
|
+
| **JSON** | Structured logging format |
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install monten
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
yarn add monten
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pnpm add monten
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import express from 'express'
|
|
78
|
+
import { initObservability, httpObservabilityMiddleware } from 'monten'
|
|
79
|
+
|
|
80
|
+
const app = express()
|
|
81
|
+
|
|
82
|
+
// Initialize observability
|
|
83
|
+
initObservability({
|
|
84
|
+
serviceName: 'users-service',
|
|
85
|
+
enableLogging: true,
|
|
86
|
+
enableMetrics: true,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// Add middleware (single line!)
|
|
90
|
+
app.use(httpObservabilityMiddleware())
|
|
91
|
+
|
|
92
|
+
app.get('/health', (_req, res) => {
|
|
93
|
+
res.status(200).json({ ok: true })
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
app.listen(3000)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Database Timing
|
|
100
|
+
|
|
101
|
+
Use `withDbTiming` to measure any async operation — works with Prisma, Sequelize, raw SQL, Redis, HTTP calls, etc.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { withDbTiming } from 'monten'
|
|
105
|
+
import { prisma } from './prismaClient'
|
|
106
|
+
|
|
107
|
+
app.get('/users/:id', async (req, res, next) => {
|
|
108
|
+
try {
|
|
109
|
+
const user = await withDbTiming(() =>
|
|
110
|
+
prisma.user.findUnique({ where: { id: req.params.id } })
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if (!user) {
|
|
114
|
+
return res.status(404).json({ error: 'Not found' })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
res.json(user)
|
|
118
|
+
} catch (err) {
|
|
119
|
+
next(err)
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## API Reference
|
|
125
|
+
|
|
126
|
+
### `initObservability(config)`
|
|
127
|
+
|
|
128
|
+
Initialize the observability system. Call once at app startup.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
initObservability({
|
|
132
|
+
serviceName: 'my-service', // Service identifier in logs/metrics
|
|
133
|
+
enableLogging: true, // Enable structured JSON logging
|
|
134
|
+
enableMetrics: true, // Enable metrics collection & flushing
|
|
135
|
+
metricsFlushIntervalMs: 10000, // Optional: flush interval (default: 10s)
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `httpObservabilityMiddleware()`
|
|
140
|
+
|
|
141
|
+
Express middleware that captures request timing, errors, and emits logs/metrics.
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
app.use(httpObservabilityMiddleware())
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `withDbTiming<T>(fn: () => Promise<T>): Promise<T>`
|
|
148
|
+
|
|
149
|
+
Wrap any async function to measure its duration and accumulate it in the request context.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const result = await withDbTiming(() => db.query('SELECT * FROM users'))
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Log Output
|
|
156
|
+
|
|
157
|
+
Each request produces a structured JSON log entry:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"level": "info",
|
|
162
|
+
"message": "http_request",
|
|
163
|
+
"timestamp": 1704307200000,
|
|
164
|
+
"serviceName": "users-service",
|
|
165
|
+
"requestId": "550e8400-e29b-41d4-a716-446655440000",
|
|
166
|
+
"fields": {
|
|
167
|
+
"method": "GET",
|
|
168
|
+
"path": "/users/123",
|
|
169
|
+
"statusCode": 200,
|
|
170
|
+
"latencyMs": 45,
|
|
171
|
+
"dbTimeMs": 12
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Architecture
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
┌─────────────────────────────────────────────────────────┐
|
|
180
|
+
│ Express App │
|
|
181
|
+
├─────────────────────────────────────────────────────────┤
|
|
182
|
+
│ httpObservabilityMiddleware() │
|
|
183
|
+
│ ┌───────────────────────────────────────────────────┐ │
|
|
184
|
+
│ │ AsyncLocalStorage Context │ │
|
|
185
|
+
│ │ • requestId │ │
|
|
186
|
+
│ │ • startTimeMs │ │
|
|
187
|
+
│ │ • dbTimeMs (accumulated) │ │
|
|
188
|
+
│ └───────────────────────────────────────────────────┘ │
|
|
189
|
+
├─────────────────────────────────────────────────────────┤
|
|
190
|
+
│ Route Handlers │
|
|
191
|
+
│ └─> withDbTiming(() => prisma.user.find(...)) │
|
|
192
|
+
├─────────────────────────────────────────────────────────┤
|
|
193
|
+
│ On Response Finish: │
|
|
194
|
+
│ • Structured JSON log → stdout │
|
|
195
|
+
│ • Metric record → in-memory buffer │
|
|
196
|
+
├─────────────────────────────────────────────────────────┤
|
|
197
|
+
│ Background Flusher (setInterval) │
|
|
198
|
+
│ • Drains buffer periodically │
|
|
199
|
+
│ • Sends to pluggable sink │
|
|
200
|
+
└─────────────────────────────────────────────────────────┘
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Removing the Library
|
|
204
|
+
|
|
205
|
+
This library is designed to be fully removable:
|
|
206
|
+
|
|
207
|
+
1. Remove `initObservability()` call
|
|
208
|
+
2. Remove `app.use(httpObservabilityMiddleware())`
|
|
209
|
+
3. Remove `withDbTiming()` wrappers (just call the inner function directly)
|
|
210
|
+
|
|
211
|
+
Your application will continue to function normally.
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
216
|
+
|
|
217
|
+
1. Fork the repository
|
|
218
|
+
2. Create your feature branch (`git checkout -b feat/amazing-feature`)
|
|
219
|
+
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
|
|
220
|
+
4. Push to the branch (`git push origin feat/amazing-feature`)
|
|
221
|
+
5. Open a Pull Request
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT © 2026
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
<p align="center">
|
|
230
|
+
<sub>Built with ❤️ for the Node.js community</sub>
|
|
231
|
+
</p>
|