@siglo/monitor 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +514 -2
- package/dist/client.d.ts +53 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +185 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.d.ts +15 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +79 -0
- package/dist/metrics.js.map +1 -0
- package/dist/middleware/express.d.ts +9 -0
- package/dist/middleware/express.d.ts.map +1 -0
- package/dist/middleware/express.js +33 -0
- package/dist/middleware/express.js.map +1 -0
- package/dist/middleware/fastify.d.ts +8 -0
- package/dist/middleware/fastify.d.ts.map +1 -0
- package/dist/middleware/fastify.js +29 -0
- package/dist/middleware/fastify.js.map +1 -0
- package/dist/middleware/hono.d.ts +8 -0
- package/dist/middleware/hono.d.ts.map +1 -0
- package/dist/middleware/hono.js +27 -0
- package/dist/middleware/hono.js.map +1 -0
- package/dist/server.d.ts +30 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +546 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +19 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +173 -0
- package/dist/store.js.map +1 -0
- package/dist/transports/redis.d.ts +26 -0
- package/dist/transports/redis.d.ts.map +1 -0
- package/dist/transports/redis.js +70 -0
- package/dist/transports/redis.js.map +1 -0
- package/dist/transports/sse.d.ts +24 -0
- package/dist/transports/sse.d.ts.map +1 -0
- package/dist/transports/sse.js +98 -0
- package/dist/transports/sse.js.map +1 -0
- package/dist/transports/websocket.d.ts +37 -0
- package/dist/transports/websocket.d.ts.map +1 -0
- package/dist/transports/websocket.js +277 -0
- package/dist/transports/websocket.js.map +1 -0
- package/dist/types.d.ts +131 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/dashboard.d.ts +2 -0
- package/dist/ui/dashboard.d.ts.map +1 -0
- package/dist/ui/dashboard.js +43 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/wait-state.d.ts +12 -0
- package/dist/wait-state.d.ts.map +1 -0
- package/dist/wait-state.js +27 -0
- package/dist/wait-state.js.map +1 -0
- package/grafana/siglo-live-monitoring.json +109 -0
- package/package.json +54 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Jerico de guzman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,515 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @siglo/monitor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Real-time workflow telemetry server, modern React DevTools web dashboard, SSE/WebSocket streaming, and Prometheus metrics exporter for [Siglo](https://github.com/jsoftgem/siglo) workflows.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@siglo/monitor)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Overview
|
|
11
|
+
|
|
12
|
+
`@siglo/monitor` provides complete runtime observability, telemetry, and interactive developer tooling for `Siglo` workflows. It captures fine-grained execution events (`flow:start`, `step:start`, `step:complete`, `step:retry`, `step:error`, `step:skipped`, `flow:suspended`, `flow:resumed`, `context:change`, etc.) and streams them to a modern **React 18 + Vite + Tailwind CSS** DevTools dashboard, Server-Sent Events (SSE) clients, WebSockets, or distributed Redis pub/sub channels.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
+---------------------------+
|
|
16
|
+
| Siglo Workflow Run |
|
|
17
|
+
+-------------+-------------+
|
|
18
|
+
|
|
|
19
|
+
v
|
|
20
|
+
+--------------------+--------------------+
|
|
21
|
+
| Workflow Event Bus / Monitoring Adapter |
|
|
22
|
+
+--------------------+--------------------+
|
|
23
|
+
|
|
|
24
|
+
+-----------------------+-----------------------+
|
|
25
|
+
| |
|
|
26
|
+
v (SSE / WebSocket) v (Prometheus / Metrics)
|
|
27
|
+
+------------+------------+ +------------+------------+
|
|
28
|
+
| React DevTools UI | | Production Telemetry |
|
|
29
|
+
| - Live DAG Visualizer | | - Prometheus Metrics |
|
|
30
|
+
| - Context Diff Viewer | | - Grafana Dashboards |
|
|
31
|
+
| - Latency Waterfall | | - Multi-Worker Pub/Sub |
|
|
32
|
+
| - Interactive Resume | | |
|
|
33
|
+
+-------------------------+ +-------------------------+
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Key Capabilities
|
|
37
|
+
|
|
38
|
+
- ⚛️ **Modern React DevTools UI**: Built with React 18, Vite, and Tailwind CSS. Packaged as a self-contained, zero-dependency SPA with no external CDN or asset server required at runtime.
|
|
39
|
+
- 🔗 **Flexible Attachment**: Attach workflows to a newly created server, an active in-process server, or a remotely running server (e.g. started via CLI `siglo monitor`).
|
|
40
|
+
- 🗺️ **Interactive DAG Topology**: Dynamic visual representation of workflow steps, live execution states (pulsing running state, completed, failed, suspended), attempt counts, and step details inspector.
|
|
41
|
+
- ⏱️ **Latency Waterfall Timeline**: Visual duration breakdown of each step relative to total execution time with attempt indicators.
|
|
42
|
+
- 🔍 **Context & State Diff Inspector**: Syntax-highlighted JSON viewer tracking state mutations, initial input, and diff history with one-click clipboard copying.
|
|
43
|
+
- ⚡ **Interactive Durable Resumption**: Resume suspended workflows (`waitForEvent`) directly from the web UI with custom signal event names and JSON payloads.
|
|
44
|
+
- 🔄 **Replay Workflows**: Trigger execution replays directly from the dashboard or REST endpoints.
|
|
45
|
+
- 📡 **Multi-Transport Streaming**: Native Server-Sent Events (SSE) and RFC 6455 WebSockets with automatic reconnection, heartbeat pings, and connection tracking.
|
|
46
|
+
- 📊 **Prometheus Telemetry**: Standard `/metrics` endpoint exporting active flow gauges, completion counters, execution summaries, and step retry counters.
|
|
47
|
+
- 📈 **Pre-Packaged Grafana Dashboard**: Ready-to-import Grafana JSON template (`grafana/siglo-live-monitoring.json`).
|
|
48
|
+
- 🛡️ **Automated Data Redaction**: Automatic masking of sensitive fields (`password`, `token`, `secret`, `apiKey`) and tenant-isolated `$namespace` filtering.
|
|
49
|
+
- 🔌 **Framework Middlewares**: One-line integration for Express, Fastify, and Hono applications.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 2. Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install @siglo/monitor @siglo/core
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For developer CLI commands (`siglo monitor`):
|
|
60
|
+
```bash
|
|
61
|
+
npm install --save-dev @siglo/cli
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 3. Quick Start: Standalone Dev Server
|
|
67
|
+
|
|
68
|
+
Start a standalone monitor server and attach it to your workflow runs:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { Step, flow } from '@siglo/core';
|
|
72
|
+
import { createMonitorServer } from '@siglo/monitor';
|
|
73
|
+
|
|
74
|
+
async function main() {
|
|
75
|
+
// 1. Launch monitor server on port 4000
|
|
76
|
+
const monitor = await createMonitorServer({
|
|
77
|
+
port: 4000,
|
|
78
|
+
host: '0.0.0.0'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
console.log(`Live DevTools available at: http://localhost:${monitor.port}`);
|
|
82
|
+
|
|
83
|
+
// 2. Define workflow steps
|
|
84
|
+
const fetchUser = Step.create('fetchUser', async () => ({ id: 'usr_100', name: 'Alice' }));
|
|
85
|
+
const chargeCard = Step.create('chargeCard', async (ctx) => {
|
|
86
|
+
return { charged: true, amount: 49.99 };
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const orderPipeline = flow(fetchUser, chargeCard)
|
|
90
|
+
.monitor(monitor.emitter); // Attach live monitoring
|
|
91
|
+
|
|
92
|
+
// 3. Execute workflow
|
|
93
|
+
await orderPipeline.run({ orderId: 'ord_999' });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
main();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Open `http://localhost:4000` in your browser to inspect the interactive DAG, step latency waterfall, state diffs, and live event log in real time.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 4. Attaching to an Already Running Monitor Server
|
|
104
|
+
|
|
105
|
+
Instead of spinning up a new HTTP server every time, workflows can attach to a monitor server that is **already running** (e.g. launched via the CLI `npm exec --package=@siglo/cli -- siglo monitor`, in a Docker container, or started once at application bootstrap).
|
|
106
|
+
|
|
107
|
+
### Scenario A: Remote / Separate Process (CLI or Dedicated Server)
|
|
108
|
+
|
|
109
|
+
When your monitor server is running in a different process (such as `npm exec --package=@siglo/cli -- siglo monitor --port 4000` in another terminal):
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { flow } from '@siglo/core';
|
|
113
|
+
import { attachToMonitorServer } from '@siglo/monitor';
|
|
114
|
+
|
|
115
|
+
// Attach workflow directly to the running server by port or URL
|
|
116
|
+
const orderPipeline = flow(fetchUser, chargeCard)
|
|
117
|
+
.monitor(attachToMonitorServer('https://monitor.internal.corp:4000', {
|
|
118
|
+
apiKey: process.env.MONITOR_API_KEY
|
|
119
|
+
}));
|
|
120
|
+
// or local dev: .monitor(attachToMonitorServer(4000))
|
|
121
|
+
|
|
122
|
+
await orderPipeline.run({ orderId: 'ord_123' });
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Events are automatically dispatched asynchronously to the monitor server's `POST /api/events` endpoint without blocking your workflow execution or throwing errors if the server is temporarily unreachable.
|
|
126
|
+
|
|
127
|
+
### Scenario B: Same Process (In-Memory Singleton / App Bootstrap)
|
|
128
|
+
|
|
129
|
+
If your application starts the monitor server once during startup, other files and services can connect without creating redundant HTTP servers:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { flow } from '@siglo/core';
|
|
133
|
+
import { createMonitorServer, attachToMonitorServer, getMonitorEmitter } from '@siglo/monitor';
|
|
134
|
+
|
|
135
|
+
// In server startup file (e.g., server.ts):
|
|
136
|
+
const monitor = await createMonitorServer({
|
|
137
|
+
port: 4000,
|
|
138
|
+
reuseExisting: true // Reuses existing instance instead of throwing EADDRINUSE
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// In any other file / workflow definition:
|
|
142
|
+
const orderPipeline = flow(fetchUser, chargeCard)
|
|
143
|
+
.monitor(attachToMonitorServer()); // Automatically resolves the active in-process server
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
You can also retrieve the global emitter directly:
|
|
147
|
+
```typescript
|
|
148
|
+
import { getMonitorEmitter } from '@siglo/monitor';
|
|
149
|
+
|
|
150
|
+
const emitter = getMonitorEmitter();
|
|
151
|
+
const orderPipeline = flow(fetchUser, chargeCard).monitor(emitter!);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Scenario C: High-Throughput Remote Client
|
|
155
|
+
|
|
156
|
+
For distributed workers or background jobs pushing events to a central monitor server, use `createMonitorClient` to configure batching and debounce intervals:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { createMonitorClient } from '@siglo/monitor';
|
|
160
|
+
|
|
161
|
+
const client = createMonitorClient({
|
|
162
|
+
url: 'http://monitor-service:4000',
|
|
163
|
+
batchSize: 20, // Flush when 20 events accumulate
|
|
164
|
+
flushIntervalMs: 50, // Or flush every 50ms
|
|
165
|
+
redaction: {
|
|
166
|
+
redactKeys: ['password', 'creditCard']
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const orderPipeline = flow(fetchUser, chargeCard)
|
|
171
|
+
.monitor(client.monitor);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 5. Web Framework Middlewares
|
|
177
|
+
|
|
178
|
+
Embed the live monitoring UI and telemetry endpoints directly inside your existing web applications without running a separate server.
|
|
179
|
+
|
|
180
|
+
### Express Integration
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import express from 'express';
|
|
184
|
+
import { createExpressMonitorMiddleware } from '@siglo/monitor';
|
|
185
|
+
|
|
186
|
+
const app = express();
|
|
187
|
+
|
|
188
|
+
// Mount dashboard UI, /events SSE, and /api endpoints on /_siglo
|
|
189
|
+
app.use('/_siglo', createExpressMonitorMiddleware());
|
|
190
|
+
|
|
191
|
+
app.listen(3000, () => {
|
|
192
|
+
console.log('Monitor dashboard available at http://localhost:3000/_siglo');
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Fastify Integration
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import Fastify from 'fastify';
|
|
200
|
+
import { fastifyMonitorPlugin } from '@siglo/monitor';
|
|
201
|
+
|
|
202
|
+
const fastify = Fastify();
|
|
203
|
+
|
|
204
|
+
await fastify.register(fastifyMonitorPlugin, { prefix: '/_siglo' });
|
|
205
|
+
await fastify.listen({ port: 3000 });
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Hono Integration
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { Hono } from 'hono';
|
|
212
|
+
import { honoMonitorMiddleware } from '@siglo/monitor';
|
|
213
|
+
|
|
214
|
+
const app = new Hono();
|
|
215
|
+
|
|
216
|
+
app.use('/_siglo/*', honoMonitorMiddleware());
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 6. Live DevTools Dashboard Features
|
|
222
|
+
|
|
223
|
+
The web dashboard is a responsive single-page application built with React, Vite, and Tailwind CSS:
|
|
224
|
+
|
|
225
|
+
| View / Feature | Description |
|
|
226
|
+
|---|---|
|
|
227
|
+
| **Topology (DAG)** | Interactive step sequence diagram highlighting active nodes (`RUNNING`), completions, failures, and retry counters. Clicking a node opens an inspector with execution duration and errors. |
|
|
228
|
+
| **Latency Waterfall** | Horizontal timeline chart showing execution offset, relative latency, and attempt counts for each step. |
|
|
229
|
+
| **Context & State Diff** | Monospace JSON viewer with tabs for current state and chronological field mutations (`context:change`), plus one-click copy. |
|
|
230
|
+
| **Live Events Stream** | Chronological feed of all 14 Siglo events with filtering by event type and expandable raw payloads. |
|
|
231
|
+
| **Interactive Resume** | Modal for durable workflows suspended on `waitForEvent()`. Enter signal event name and JSON payload to resume execution. |
|
|
232
|
+
| **Replay Trigger** | One-click workflow replay button to re-trigger executions with recorded input context. |
|
|
233
|
+
| **Search & Status Filter** | Instant client-side search by flow name, namespace, or stack ID with status filter tabs (`ALL`, `RUNNING`, `SUSPENDED`, `FAILED`, `COMPLETED`). |
|
|
234
|
+
| **Multi-Tenant Filter** | Top header dropdown to isolate telemetry to a specific `$namespace`. |
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 7. Transports & Streaming
|
|
239
|
+
|
|
240
|
+
### Server-Sent Events (SSE)
|
|
241
|
+
|
|
242
|
+
Clients can subscribe to `/events` for one-way live event streaming with automated heartbeat keep-alive:
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
const es = new EventSource('http://localhost:4000/events');
|
|
246
|
+
|
|
247
|
+
es.addEventListener('flow:start', (e) => {
|
|
248
|
+
console.log('Flow started:', JSON.parse(e.data));
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
es.addEventListener('step:complete', (e) => {
|
|
252
|
+
console.log('Step finished:', JSON.parse(e.data));
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
es.addEventListener('flow:suspended', (e) => {
|
|
256
|
+
console.log('Waiting for signal:', JSON.parse(e.data));
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Filter events by namespace via query parameter:
|
|
261
|
+
```javascript
|
|
262
|
+
const es = new EventSource('http://localhost:4000/events?namespace=tenant-a');
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### WebSocket Streaming
|
|
266
|
+
|
|
267
|
+
For bidirectional communication or interactive controls, connect to `ws://localhost:4000/ws`:
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
const ws = new WebSocket('ws://localhost:4000/ws');
|
|
271
|
+
|
|
272
|
+
ws.onmessage = (event) => {
|
|
273
|
+
const data = JSON.parse(event.data);
|
|
274
|
+
console.log('WebSocket event:', data);
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 8. Distributed Monitoring with Redis Pub/Sub
|
|
281
|
+
|
|
282
|
+
When scaling workflows across multiple worker processes or Kubernetes pods, aggregate telemetry through Redis:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { RedisMonitoringAdapter, createMonitorServer } from '@siglo/monitor';
|
|
286
|
+
import { WorkflowEventEmitter } from '@siglo/core';
|
|
287
|
+
import Redis from 'ioredis';
|
|
288
|
+
|
|
289
|
+
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
290
|
+
|
|
291
|
+
// 1. In Worker Process: Publish events to Redis
|
|
292
|
+
const publisher = new Redis(redisUrl);
|
|
293
|
+
const workerAdapter = new RedisMonitoringAdapter({
|
|
294
|
+
publisher,
|
|
295
|
+
channel: 'siglo:monitor:events'
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
emitter.on('*', (event) => {
|
|
299
|
+
workerAdapter.publish(event);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// 2. In Central Monitor Server: Ingest events via subscriber and deliver to server emitter
|
|
303
|
+
const subscriber = new Redis(redisUrl);
|
|
304
|
+
const monitor = await createMonitorServer({ port: 4000 });
|
|
305
|
+
|
|
306
|
+
const serverAdapter = new RedisMonitoringAdapter({
|
|
307
|
+
subscriber,
|
|
308
|
+
channel: 'siglo:monitor:events',
|
|
309
|
+
emitter: monitor.emitter // Automatically routes incoming Redis events to monitor store & SSE
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## 9. Prometheus Metrics & Grafana
|
|
316
|
+
|
|
317
|
+
Expose standard Prometheus metrics for cluster alerting and visualization:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { PrometheusExporter, createMonitorServer } from '@siglo/monitor';
|
|
321
|
+
|
|
322
|
+
const monitor = await createMonitorServer({ port: 4000 });
|
|
323
|
+
|
|
324
|
+
// GET /metrics exposes:
|
|
325
|
+
// - siglo_active_flows
|
|
326
|
+
// - siglo_flow_executions_total{status="completed|failed"}
|
|
327
|
+
// - siglo_flow_duration_seconds
|
|
328
|
+
// - siglo_step_retries_total
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Import the ready-to-use Grafana JSON dashboard located in:
|
|
332
|
+
[`grafana/siglo-live-monitoring.json`](./grafana/siglo-live-monitoring.json)
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 10. Security, Authentication & Production Hardening
|
|
337
|
+
|
|
338
|
+
When deploying `@siglo/monitor` across internal networks or attaching remote workers, apply production-grade security controls:
|
|
339
|
+
|
|
340
|
+
### 10.1 API Key & Token Authentication
|
|
341
|
+
Protect telemetry ingestion, control-plane endpoints, and event streams with API keys:
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
const monitor = await createMonitorServer({
|
|
345
|
+
port: 4000,
|
|
346
|
+
auth: {
|
|
347
|
+
ingestionKey: 'ingest-secret-token', // Required for POST /api/events
|
|
348
|
+
adminKey: 'admin-secret-token', // Required for /resume, /replay, /api/workflows
|
|
349
|
+
}
|
|
350
|
+
// Or shorthand for general single key: auth: 'my-secret-key'
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Remote clients attach with their key:
|
|
355
|
+
```typescript
|
|
356
|
+
const monitor = attachToMonitorServer('https://monitor.corp.internal:4000', {
|
|
357
|
+
apiKey: 'ingest-secret-token'
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The Web UI and SSE clients authenticate via `Authorization: Bearer <token>`, `X-API-Key: <token>`, or URL query parameter `?token=<token>`.
|
|
362
|
+
|
|
363
|
+
### 10.2 Disabling Remote Control in Sensitive Environments
|
|
364
|
+
In production, disable interactive workflow resumption (`/resume`) and replays (`/replay`) to prevent remote state manipulation:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
const monitor = await createMonitorServer({
|
|
368
|
+
allowRemoteResume: false // Returns 403 Forbidden on resume/replay
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 10.3 CORS Hardening
|
|
373
|
+
Restrict browser DevTools access to explicit trusted origins (preventing drive-by intranet CSRF):
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
const monitor = await createMonitorServer({
|
|
377
|
+
cors: {
|
|
378
|
+
origin: ['https://devtools.internal.corp', 'http://localhost:3000'],
|
|
379
|
+
credentials: true
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### 10.4 Payload Caps & Client Memory Protection
|
|
385
|
+
- **Payload Limits**: Limits JSON ingestion payloads to 1MB (configurable via `maxPayloadBytes`). Exceeding requests receive `413 Payload Too Large`.
|
|
386
|
+
- **Bounded Client Queue**: Remote client automatically drops oldest events if telemetry buffer exceeds `maxQueueSize` (default: 1000) when the network is slow or unreachable.
|
|
387
|
+
|
|
388
|
+
### 10.5 Context & Credential Redaction
|
|
389
|
+
Prevent sensitive credentials, API keys, or personal identifiable information (PII) from leaking to dashboards and event streams:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const monitor = await createMonitorServer({
|
|
393
|
+
redaction: {
|
|
394
|
+
redactKeys: ['apiKey', 'password', 'creditCard', 'secret', 'token'],
|
|
395
|
+
redactHook: (key, val) => {
|
|
396
|
+
if (key === 'email') return val.replace(/(?<=.).(?=[^@]*?@)/g, '*');
|
|
397
|
+
return undefined; // use default '[REDACTED]'
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## 11. Dashboard UI Development (React + Vite + Tailwind)
|
|
406
|
+
|
|
407
|
+
The live monitor web interface source code is located in [`packages/monitor/ui`](./ui) and adheres to modular, industry-standard frontend architecture.
|
|
408
|
+
|
|
409
|
+
### Tech Stack
|
|
410
|
+
- **React 18** with typed hooks and functional components
|
|
411
|
+
- **Tailwind CSS** for dark-mode DevTools styling
|
|
412
|
+
- **Lucide React** for icons
|
|
413
|
+
- **Vite** with `vite-plugin-singlefile` for self-contained distribution
|
|
414
|
+
|
|
415
|
+
### Directory Layout
|
|
416
|
+
```
|
|
417
|
+
packages/monitor/ui/
|
|
418
|
+
├── src/
|
|
419
|
+
│ ├── api/
|
|
420
|
+
│ │ └── workflowApi.ts # REST client for workflow fetch, resume, and replay
|
|
421
|
+
│ ├── constants/
|
|
422
|
+
│ │ ├── events.ts # Siglo event types enumeration
|
|
423
|
+
│ │ └── status.ts # Workflow status filters list
|
|
424
|
+
│ ├── hooks/
|
|
425
|
+
│ │ ├── useWorkflowMonitor.ts # SSE connection, event reducer & state sync hook
|
|
426
|
+
│ │ └── useClipboard.ts # Clipboard copy helper with timeout
|
|
427
|
+
│ ├── types/
|
|
428
|
+
│ │ ├── workflow.ts # WorkflowRun, StepRun, ContextDiff types
|
|
429
|
+
│ │ ├── events.ts # MonitoringEvent, SigloEventType types
|
|
430
|
+
│ │ └── index.ts # Centralized type exports
|
|
431
|
+
│ ├── utils/
|
|
432
|
+
│ │ └── formatters.ts # Time, duration, ID, and JSON formatters
|
|
433
|
+
│ ├── components/
|
|
434
|
+
│ │ ├── ui/ # Reusable design system atoms
|
|
435
|
+
│ │ │ ├── StatusBadge.tsx # Color-coded status badge
|
|
436
|
+
│ │ │ ├── Modal.tsx # Accessible dialog modal
|
|
437
|
+
│ │ │ └── EmptyState.tsx # Empty state illustration card
|
|
438
|
+
│ │ ├── layout/ # Layout shells
|
|
439
|
+
│ │ │ └── Header.tsx # Navigation header & SSE connectivity badge
|
|
440
|
+
│ │ └── workflows/ # Feature-specific components
|
|
441
|
+
│ │ ├── RunList/ # Workflow execution sidebar & filters
|
|
442
|
+
│ │ ├── Dag/ # Interactive DAG topology visualizer
|
|
443
|
+
│ │ ├── Waterfall/ # Latency waterfall chart
|
|
444
|
+
│ │ ├── Context/ # Context JSON & mutation diff inspector
|
|
445
|
+
│ │ ├── Events/ # Live streaming telemetry log
|
|
446
|
+
│ │ ├── ResumeModal/ # Resumption modal dialog
|
|
447
|
+
│ │ ├── Stats/ # High-level metrics grid
|
|
448
|
+
│ │ └── WorkflowDetail.tsx # Tabbed workflow execution view
|
|
449
|
+
│ ├── App.tsx # Root layout orchestrator
|
|
450
|
+
│ ├── main.tsx # React DOM entry point
|
|
451
|
+
│ └── index.css # Tailwind base & utilities
|
|
452
|
+
├── scripts/
|
|
453
|
+
│ └── embed-html.js # Inlines dist/index.html into src/ui/dashboard.ts
|
|
454
|
+
├── vite.config.ts # Vite config with backend proxy and singlefile plugin
|
|
455
|
+
├── tailwind.config.js # Tailwind configuration
|
|
456
|
+
└── package.json
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Local Development Server
|
|
460
|
+
|
|
461
|
+
Run Vite with hot module replacement (HMR) and backend proxy forwarding `/events` and `/api` to `http://localhost:4000`:
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
npm run dev:ui
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Production Build
|
|
468
|
+
|
|
469
|
+
Builds the SPA into a single inlined bundle and updates [`src/ui/dashboard.ts`](./src/ui/dashboard.ts):
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
npm run build:ui
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## 12. REST API Reference
|
|
478
|
+
|
|
479
|
+
The monitor server exposes REST endpoints for programmatic inspection and control:
|
|
480
|
+
|
|
481
|
+
| Method | Endpoint | Description |
|
|
482
|
+
|---|---|---|
|
|
483
|
+
| `GET` | `/` or `/index.html` | Serves the single-page DevTools web dashboard |
|
|
484
|
+
| `GET` | `/events` | Server-Sent Events (SSE) stream (`?namespace=...`) |
|
|
485
|
+
| `POST` | `/api/events` | Ingests telemetry events from external processes / clients |
|
|
486
|
+
| `GET` | `/metrics` | Prometheus metrics exposition format |
|
|
487
|
+
| `GET` | `/api/workflows` | List recorded workflow runs (`?namespace=...&status=...`) |
|
|
488
|
+
| `GET` | `/api/workflows/:stackId` | Get execution details and step history for a workflow |
|
|
489
|
+
| `POST` | `/api/workflows/:stackId/resume` | Resume a suspended workflow (`{ eventName, payload }`) |
|
|
490
|
+
| `POST` | `/api/workflows/:stackId/replay` | Trigger replay of a recorded workflow |
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## 13. Programmatic API Reference
|
|
495
|
+
|
|
496
|
+
### `attachToMonitorServer(target?: string | number | MonitorServerInstance | MonitorClientOptions): (event: WorkflowExecutionEvent) => void`
|
|
497
|
+
Convenient hook to attach a workflow to a running monitor server (in-process or remote over HTTP).
|
|
498
|
+
|
|
499
|
+
### `createMonitorClient(options?: MonitorClientOptions): MonitorClientInstance`
|
|
500
|
+
Creates a remote client with configurable buffering and auto-flush to stream events to an external monitor server.
|
|
501
|
+
|
|
502
|
+
### `getActiveMonitorServer(port?: number): MonitorServerInstance | undefined`
|
|
503
|
+
Returns the active in-process monitor server instance.
|
|
504
|
+
|
|
505
|
+
### `getMonitorEmitter(port?: number): WorkflowEventEmitter | undefined`
|
|
506
|
+
Returns the event emitter of the currently active in-process monitor server.
|
|
507
|
+
|
|
508
|
+
### `createMonitorServer(options?: MonitorServerOptions): Promise<MonitorServerInstance>`
|
|
509
|
+
Creates and starts an HTTP monitor server. Supports `reuseExisting: true` to reuse an already running instance.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## 14. License
|
|
514
|
+
|
|
515
|
+
MIT © Jerico de Guzman
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { WorkflowEventEmitter, WorkflowExecutionEvent } from '@siglo/core';
|
|
2
|
+
import { MonitorClientOptions, MonitorClientInstance } from './types';
|
|
3
|
+
import { MonitorServerInstance } from './server';
|
|
4
|
+
export declare class RemoteMonitorClient implements MonitorClientInstance {
|
|
5
|
+
readonly emitter: WorkflowEventEmitter;
|
|
6
|
+
private readonly baseUrl;
|
|
7
|
+
private readonly batchSize;
|
|
8
|
+
private readonly flushIntervalMs;
|
|
9
|
+
private readonly redaction?;
|
|
10
|
+
private readonly apiKey?;
|
|
11
|
+
private readonly customHeaders;
|
|
12
|
+
private readonly maxQueueSize;
|
|
13
|
+
private queue;
|
|
14
|
+
private flushTimer;
|
|
15
|
+
private isClosing;
|
|
16
|
+
private activeFlushPromise;
|
|
17
|
+
constructor(options?: MonitorClientOptions);
|
|
18
|
+
monitor: (event: WorkflowExecutionEvent) => void;
|
|
19
|
+
sendEvent(event: WorkflowExecutionEvent): Promise<void>;
|
|
20
|
+
private queueEvent;
|
|
21
|
+
flush(): Promise<void>;
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a client that streams workflow telemetry to an external or running monitor server.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createMonitorClient(options?: MonitorClientOptions): MonitorClientInstance;
|
|
28
|
+
/**
|
|
29
|
+
* Attaches a workflow to an already running monitor server.
|
|
30
|
+
*
|
|
31
|
+
* Supports:
|
|
32
|
+
* - No arguments: Attaches to the active in-process server if running, or defaults to http://127.0.0.1:4000.
|
|
33
|
+
* - Port number (e.g. 4000): Attaches to the in-process server on that port if present, or connects over HTTP.
|
|
34
|
+
* - URL string (e.g. 'http://localhost:4000'): Connects to the remote monitor server over HTTP.
|
|
35
|
+
* - MonitorServerInstance: Directly pipes events into the server's event emitter in memory.
|
|
36
|
+
* - MonitorClientOptions: Configures remote batching and connection parameters.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // 1. Attach to running server on default port (4000)
|
|
41
|
+
* const orderFlow = flow(step1, step2).monitor(attachToMonitorServer());
|
|
42
|
+
*
|
|
43
|
+
* // 2. Attach to authenticated remote monitor server
|
|
44
|
+
* const orderFlow = flow(step1, step2).monitor(attachToMonitorServer('https://monitor.corp.internal:4000', {
|
|
45
|
+
* apiKey: 'secret-token'
|
|
46
|
+
* }));
|
|
47
|
+
*
|
|
48
|
+
* // 3. Attach by port
|
|
49
|
+
* const orderFlow = flow(step1, step2).monitor(attachToMonitorServer(4000));
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function attachToMonitorServer(target?: string | number | MonitorServerInstance | MonitorClientOptions, clientOptions?: MonitorClientOptions): (event: WorkflowExecutionEvent) => void;
|
|
53
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAiC,MAAM,aAAa,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACtE,OAAO,EAA0B,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEzE,qBAAa,mBAAoB,YAAW,qBAAqB;IAC7D,SAAgB,OAAO,EAAE,oBAAoB,CAAC;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,kBAAkB,CAA8B;gBAE5C,OAAO,GAAE,oBAAyB;IAuBvC,OAAO,UAAW,sBAAsB,KAAG,IAAI,CAEpD;IAEW,SAAS,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE,OAAO,CAAC,UAAU;IAqBL,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2CtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAItC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,qBAAqB,CAE7F;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,qBAAqB,GAAG,oBAAoB,EACvE,aAAa,CAAC,EAAE,oBAAoB,GACrC,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CA8CzC"}
|