dspx 0.1.1-alpha.0
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/.github/workflows/ci.yml +185 -0
- package/.vscode/c_cpp_properties.json +17 -0
- package/.vscode/settings.json +68 -0
- package/.vscode/tasks.json +28 -0
- package/DISCLAIMER.md +32 -0
- package/LICENSE +21 -0
- package/README.md +1803 -0
- package/ROADMAP.md +192 -0
- package/TECHNICAL_DEBT.md +165 -0
- package/binding.gyp +65 -0
- package/docs/ADVANCED_LOGGER_FEATURES.md +598 -0
- package/docs/AUTHENTICATION_SECURITY.md +396 -0
- package/docs/BACKEND_IMPROVEMENTS.md +399 -0
- package/docs/CHEBYSHEV_BIQUAD_EQ_IMPLEMENTATION.md +405 -0
- package/docs/FFT_IMPLEMENTATION.md +490 -0
- package/docs/FFT_IMPROVEMENTS_SUMMARY.md +387 -0
- package/docs/FFT_USER_GUIDE.md +494 -0
- package/docs/FILTERS_IMPLEMENTATION.md +260 -0
- package/docs/FILTER_API_GUIDE.md +418 -0
- package/docs/FIR_SIMD_OPTIMIZATION.md +175 -0
- package/docs/LOGGER_API_REFERENCE.md +350 -0
- package/docs/NOTCH_FILTER_QUICK_REF.md +121 -0
- package/docs/PHASE2_TESTS_AND_NOTCH_FILTER.md +341 -0
- package/docs/PHASES_5_7_SUMMARY.md +403 -0
- package/docs/PIPELINE_FILTER_INTEGRATION.md +446 -0
- package/docs/SIMD_OPTIMIZATIONS.md +211 -0
- package/docs/TEST_MIGRATION_SUMMARY.md +173 -0
- package/docs/TIMESERIES_IMPLEMENTATION_SUMMARY.md +322 -0
- package/docs/TIMESERIES_QUICK_REF.md +85 -0
- package/docs/advanced.md +559 -0
- package/docs/time-series-guide.md +617 -0
- package/docs/time-series-migration.md +376 -0
- package/jest.config.js +37 -0
- package/package.json +42 -0
- package/prebuilds/linux-x64/dsp-ts-redis.node +0 -0
- package/prebuilds/win32-x64/dsp-ts-redis.node +0 -0
- package/scripts/test.js +24 -0
- package/src/build/dsp-ts-redis.node +0 -0
- package/src/native/DspPipeline.cc +675 -0
- package/src/native/DspPipeline.h +44 -0
- package/src/native/FftBindings.cc +817 -0
- package/src/native/FilterBindings.cc +1001 -0
- package/src/native/IDspStage.h +53 -0
- package/src/native/adapters/InterpolatorStage.h +201 -0
- package/src/native/adapters/MeanAbsoluteValueStage.h +289 -0
- package/src/native/adapters/MovingAverageStage.h +306 -0
- package/src/native/adapters/RectifyStage.h +88 -0
- package/src/native/adapters/ResamplerStage.h +238 -0
- package/src/native/adapters/RmsStage.h +299 -0
- package/src/native/adapters/SscStage.h +121 -0
- package/src/native/adapters/VarianceStage.h +307 -0
- package/src/native/adapters/WampStage.h +114 -0
- package/src/native/adapters/WaveformLengthStage.h +115 -0
- package/src/native/adapters/ZScoreNormalizeStage.h +326 -0
- package/src/native/core/FftEngine.cc +441 -0
- package/src/native/core/FftEngine.h +224 -0
- package/src/native/core/FirFilter.cc +324 -0
- package/src/native/core/FirFilter.h +149 -0
- package/src/native/core/IirFilter.cc +576 -0
- package/src/native/core/IirFilter.h +210 -0
- package/src/native/core/MovingAbsoluteValueFilter.cc +17 -0
- package/src/native/core/MovingAbsoluteValueFilter.h +135 -0
- package/src/native/core/MovingAverageFilter.cc +18 -0
- package/src/native/core/MovingAverageFilter.h +135 -0
- package/src/native/core/MovingFftFilter.cc +291 -0
- package/src/native/core/MovingFftFilter.h +203 -0
- package/src/native/core/MovingVarianceFilter.cc +194 -0
- package/src/native/core/MovingVarianceFilter.h +114 -0
- package/src/native/core/MovingZScoreFilter.cc +215 -0
- package/src/native/core/MovingZScoreFilter.h +113 -0
- package/src/native/core/Policies.h +352 -0
- package/src/native/core/RmsFilter.cc +18 -0
- package/src/native/core/RmsFilter.h +131 -0
- package/src/native/core/SscFilter.cc +16 -0
- package/src/native/core/SscFilter.h +137 -0
- package/src/native/core/WampFilter.cc +16 -0
- package/src/native/core/WampFilter.h +101 -0
- package/src/native/core/WaveformLengthFilter.cc +17 -0
- package/src/native/core/WaveformLengthFilter.h +98 -0
- package/src/native/utils/CircularBufferArray.cc +336 -0
- package/src/native/utils/CircularBufferArray.h +62 -0
- package/src/native/utils/CircularBufferVector.cc +145 -0
- package/src/native/utils/CircularBufferVector.h +45 -0
- package/src/native/utils/NapiUtils.cc +53 -0
- package/src/native/utils/NapiUtils.h +21 -0
- package/src/native/utils/SimdOps.h +870 -0
- package/src/native/utils/SlidingWindowFilter.cc +239 -0
- package/src/native/utils/SlidingWindowFilter.h +159 -0
- package/src/native/utils/TimeSeriesBuffer.cc +205 -0
- package/src/native/utils/TimeSeriesBuffer.h +140 -0
- package/src/ts/CircularLogBuffer.ts +87 -0
- package/src/ts/DriftDetector.ts +331 -0
- package/src/ts/TopicRouter.ts +428 -0
- package/src/ts/__tests__/AdvancedDsp.test.ts +585 -0
- package/src/ts/__tests__/AuthAndEdgeCases.test.ts +241 -0
- package/src/ts/__tests__/Chaining.test.ts +387 -0
- package/src/ts/__tests__/ChebyshevBiquad.test.ts +229 -0
- package/src/ts/__tests__/CircularLogBuffer.test.ts +158 -0
- package/src/ts/__tests__/DriftDetector.test.ts +389 -0
- package/src/ts/__tests__/Fft.test.ts +484 -0
- package/src/ts/__tests__/ListState.test.ts +153 -0
- package/src/ts/__tests__/Logger.test.ts +208 -0
- package/src/ts/__tests__/LoggerAdvanced.test.ts +319 -0
- package/src/ts/__tests__/LoggerMinor.test.ts +247 -0
- package/src/ts/__tests__/MeanAbsoluteValue.test.ts +398 -0
- package/src/ts/__tests__/MovingAverage.test.ts +322 -0
- package/src/ts/__tests__/RMS.test.ts +315 -0
- package/src/ts/__tests__/Rectify.test.ts +272 -0
- package/src/ts/__tests__/Redis.test.ts +456 -0
- package/src/ts/__tests__/SlopeSignChange.test.ts +166 -0
- package/src/ts/__tests__/Tap.test.ts +164 -0
- package/src/ts/__tests__/TimeBasedExpiration.test.ts +124 -0
- package/src/ts/__tests__/TimeBasedRmsAndMav.test.ts +231 -0
- package/src/ts/__tests__/TimeBasedVarianceAndZScore.test.ts +284 -0
- package/src/ts/__tests__/TimeSeries.test.ts +254 -0
- package/src/ts/__tests__/TopicRouter.test.ts +332 -0
- package/src/ts/__tests__/TopicRouterAdvanced.test.ts +483 -0
- package/src/ts/__tests__/TopicRouterPriority.test.ts +487 -0
- package/src/ts/__tests__/Variance.test.ts +509 -0
- package/src/ts/__tests__/WaveformLength.test.ts +147 -0
- package/src/ts/__tests__/WillisonAmplitude.test.ts +197 -0
- package/src/ts/__tests__/ZScoreNormalize.test.ts +459 -0
- package/src/ts/advanced-dsp.ts +566 -0
- package/src/ts/backends.ts +1137 -0
- package/src/ts/bindings.ts +1225 -0
- package/src/ts/easter-egg.ts +42 -0
- package/src/ts/examples/MeanAbsoluteValue/test-state.ts +99 -0
- package/src/ts/examples/MeanAbsoluteValue/test-streaming.ts +269 -0
- package/src/ts/examples/MovingAverage/test-state.ts +85 -0
- package/src/ts/examples/MovingAverage/test-streaming.ts +188 -0
- package/src/ts/examples/RMS/test-state.ts +97 -0
- package/src/ts/examples/RMS/test-streaming.ts +253 -0
- package/src/ts/examples/Rectify/test-state.ts +107 -0
- package/src/ts/examples/Rectify/test-streaming.ts +242 -0
- package/src/ts/examples/Variance/test-state.ts +195 -0
- package/src/ts/examples/Variance/test-streaming.ts +260 -0
- package/src/ts/examples/ZScoreNormalize/test-state.ts +277 -0
- package/src/ts/examples/ZScoreNormalize/test-streaming.ts +306 -0
- package/src/ts/examples/advanced-dsp-examples.ts +397 -0
- package/src/ts/examples/callbacks/advanced-router-features.ts +326 -0
- package/src/ts/examples/callbacks/benchmark-circular-buffer.ts +109 -0
- package/src/ts/examples/callbacks/monitoring-example.ts +265 -0
- package/src/ts/examples/callbacks/pipeline-callbacks-example.ts +137 -0
- package/src/ts/examples/callbacks/pooled-callbacks-example.ts +274 -0
- package/src/ts/examples/callbacks/priority-routing-example.ts +277 -0
- package/src/ts/examples/callbacks/production-topic-router.ts +214 -0
- package/src/ts/examples/callbacks/topic-based-logging.ts +161 -0
- package/src/ts/examples/chaining/test-chaining-redis.ts +113 -0
- package/src/ts/examples/chaining/test-chaining.ts +52 -0
- package/src/ts/examples/emg-features-example.ts +284 -0
- package/src/ts/examples/fft-example.ts +309 -0
- package/src/ts/examples/fft-examples.ts +349 -0
- package/src/ts/examples/filter-examples.ts +320 -0
- package/src/ts/examples/list-state-example.ts +131 -0
- package/src/ts/examples/logger-example.ts +91 -0
- package/src/ts/examples/notch-filter-examples.ts +243 -0
- package/src/ts/examples/phase5/drift-detection-example.ts +290 -0
- package/src/ts/examples/phase6-7/production-observability.ts +476 -0
- package/src/ts/examples/phase6-7/redis-timeseries-integration.ts +446 -0
- package/src/ts/examples/redis/redis-example.ts +202 -0
- package/src/ts/examples/redis-example.ts +202 -0
- package/src/ts/examples/simd-benchmark.ts +126 -0
- package/src/ts/examples/tap-debugging.ts +230 -0
- package/src/ts/examples/timeseries/comparison-example.ts +290 -0
- package/src/ts/examples/timeseries/iot-sensor-example.ts +143 -0
- package/src/ts/examples/timeseries/redis-streaming-example.ts +233 -0
- package/src/ts/examples/waveform-length-example.ts +139 -0
- package/src/ts/fft.ts +722 -0
- package/src/ts/filters.ts +1078 -0
- package/src/ts/index.ts +120 -0
- package/src/ts/types.ts +589 -0
- package/tsconfig.json +15 -0
package/docs/advanced.md
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
# Advanced Features
|
|
2
|
+
|
|
3
|
+
This document covers advanced observability, monitoring, and debugging features for production deployments.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Pipeline Callbacks (Monitoring & Observability)](#pipeline-callbacks-monitoring--observability)
|
|
10
|
+
- [Topic-Based Logging (Kafka-Style Filtering)](#topic-based-logging-kafka-style-filtering)
|
|
11
|
+
- [Topic Router (Fan-Out to Multiple Backends)](#topic-router-fan-out-to-multiple-backends)
|
|
12
|
+
- [Priority-Based Routing (10-Level System)](#priority-based-routing-10-level-system)
|
|
13
|
+
- [Debugging with `.tap()`](#debugging-with-tap)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Pipeline Callbacks (Monitoring & Observability)
|
|
18
|
+
|
|
19
|
+
Configure callbacks for monitoring, alerting, and observability. The library supports both **individual** and **pooled/batched** callbacks:
|
|
20
|
+
|
|
21
|
+
### Basic Usage
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { createDspPipeline } from "dspx";
|
|
25
|
+
import type { PipelineCallbacks } from "dspx";
|
|
26
|
+
|
|
27
|
+
const callbacks: PipelineCallbacks = {
|
|
28
|
+
// Monitor individual samples (use sparingly - can impact performance)
|
|
29
|
+
onSample: (value, index, stage) => {
|
|
30
|
+
if (value > THRESHOLD) {
|
|
31
|
+
triggerAlert(index, stage);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// Track performance metrics
|
|
36
|
+
onStageComplete: (stage, durationMs) => {
|
|
37
|
+
metrics.record(`dsp.${stage}.duration`, durationMs);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// Handle errors gracefully
|
|
41
|
+
onError: (stage, error) => {
|
|
42
|
+
logger.error(`Stage ${stage} failed`, error);
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// Structured logging (called immediately for each log)
|
|
46
|
+
onLog: (level, msg, context) => {
|
|
47
|
+
if (level === "debug") return; // Filter debug logs
|
|
48
|
+
console.log(`[${level}] ${msg}`, context);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Configure callbacks before adding filters
|
|
53
|
+
const pipeline = createDspPipeline()
|
|
54
|
+
.pipeline(callbacks)
|
|
55
|
+
.MovingAverage({ windowSize: 10 })
|
|
56
|
+
.Rectify()
|
|
57
|
+
.Rms({ windowSize: 5 });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Pooled/Batched Callbacks (Better Performance)
|
|
61
|
+
|
|
62
|
+
For high-throughput scenarios, use **pooled callbacks** to reduce overhead:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const callbacks: PipelineCallbacks = {
|
|
66
|
+
// Process samples in batches (more efficient than onSample)
|
|
67
|
+
onBatch: (batch) => {
|
|
68
|
+
console.log(`Stage: ${batch.stage}`);
|
|
69
|
+
console.log(`Samples: ${batch.count}`);
|
|
70
|
+
|
|
71
|
+
// Process entire batch efficiently (SIMD-friendly)
|
|
72
|
+
for (let i = 0; i < batch.samples.length; i++) {
|
|
73
|
+
if (batch.samples[i] > THRESHOLD) {
|
|
74
|
+
triggerAlert(batch.startIndex + i, batch.stage);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
// Receive all logs at once (pooled during processing)
|
|
80
|
+
onLogBatch: (logs) => {
|
|
81
|
+
// Send all logs to external system in one request
|
|
82
|
+
await loggingService.sendBatch(
|
|
83
|
+
logs.map((log) => ({
|
|
84
|
+
level: log.level,
|
|
85
|
+
message: log.message,
|
|
86
|
+
timestamp: log.timestamp,
|
|
87
|
+
...log.context,
|
|
88
|
+
}))
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
onStageComplete: (stage, durationMs) => {
|
|
93
|
+
metrics.record(`dsp.${stage}.duration`, durationMs);
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Callback Comparison
|
|
99
|
+
|
|
100
|
+
| Callback Type | Best For | Throughput | Production Safety |
|
|
101
|
+
| ----------------- | ------------------------------------------------------------- | ---------------- | --------------------------------------- |
|
|
102
|
+
| `onSample` | Peak detection, threshold alerts, individual value monitoring | ~6M samples/sec | ⚠️ **RISKY** - Blocks event loop |
|
|
103
|
+
| `onBatch` | Batch aggregation, efficient sample processing | ~23M samples/sec | ✅ **SAFE** - Non-blocking |
|
|
104
|
+
| `onLog` | Real-time logging, immediate output | Variable | ⚠️ **RISKY** - Synchronous I/O per call |
|
|
105
|
+
| `onLogBatch` | External logging services, log aggregation | ~3M samples/sec | ✅ **SAFE** - Batched, non-blocking |
|
|
106
|
+
| `onStageComplete` | Performance metrics, timing | ✅ Minimal | ✅ **SAFE** - 1 call per process |
|
|
107
|
+
| `onError` | Error handling | ✅ Minimal | ✅ **SAFE** - Only on error |
|
|
108
|
+
|
|
109
|
+
### Critical Performance & Safety Notes
|
|
110
|
+
|
|
111
|
+
- **🚨 Individual callbacks (`onSample`, `onLog`) are fast but dangerous**:
|
|
112
|
+
|
|
113
|
+
- Higher raw throughput in microbenchmarks (~6M samples/sec)
|
|
114
|
+
- **Block the Node.js event loop** with millions of synchronous function calls
|
|
115
|
+
- Synchronous I/O operations in callbacks can stall entire pipeline
|
|
116
|
+
- Unpredictable GC pressure from per-call allocations
|
|
117
|
+
- **NOT recommended for production servers**
|
|
118
|
+
|
|
119
|
+
- **✅ Pooled callbacks (`onBatch`, `onLogBatch`) are production-safe**:
|
|
120
|
+
|
|
121
|
+
- Stable, predictable throughput (~3M samples/sec sustained)
|
|
122
|
+
- **Non-blocking**: Batched operations prevent event loop starvation
|
|
123
|
+
- **Backpressure-friendly**: Aligns with real-world telemetry systems (Kafka, Loki, Prometheus)
|
|
124
|
+
- Fixed memory footprint via circular buffer (no unbounded growth)
|
|
125
|
+
- **Recommended for high-throughput production environments**
|
|
126
|
+
|
|
127
|
+
- **Architecture trade-off**:
|
|
128
|
+
|
|
129
|
+
- Individual mode: 2x faster in synthetic benchmarks, but impractical for live servers
|
|
130
|
+
- Pooled mode: Slight raw speed reduction, but guarantees non-blocking safety
|
|
131
|
+
- **Industry standard**: Pooled/batched callbacks match production observability patterns (Kafka producers, OpenTelemetry exporters, Loki agents)
|
|
132
|
+
|
|
133
|
+
- **Circular buffer implementation**:
|
|
134
|
+
- Fixed capacity: 32 log entries (typical: 2-3 logs per process call)
|
|
135
|
+
- Zero reallocations after initialization
|
|
136
|
+
- Cache-friendly memory access pattern
|
|
137
|
+
- Graceful overflow: Overwrites oldest entries (prevents memory leaks)
|
|
138
|
+
|
|
139
|
+
See `src/ts/examples/callbacks/` for complete examples including performance comparisons.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Topic-Based Logging (Kafka-Style Filtering)
|
|
144
|
+
|
|
145
|
+
Filter logs using **Kafka-style hierarchical topics** for efficient, selective subscription:
|
|
146
|
+
|
|
147
|
+
### Topic Structure
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
pipeline.debug # General debug logs
|
|
151
|
+
pipeline.info # General info logs
|
|
152
|
+
pipeline.warn # General warnings
|
|
153
|
+
pipeline.error # General errors
|
|
154
|
+
pipeline.stage.<stageName>.<category> # Stage-specific logs
|
|
155
|
+
├── samples # Sample-level data
|
|
156
|
+
├── performance # Timing/metrics
|
|
157
|
+
└── error # Stage errors
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Basic Topic Filtering
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
const pipeline = createDspPipeline();
|
|
164
|
+
|
|
165
|
+
// Subscribe to ALL logs (no filter)
|
|
166
|
+
pipeline.pipeline({
|
|
167
|
+
onLogBatch: (logs) => {
|
|
168
|
+
logs.forEach((log) => {
|
|
169
|
+
console.log(`[${log.topic}] ${log.level}: ${log.message}`);
|
|
170
|
+
// [pipeline.debug] debug: Starting pipeline processing
|
|
171
|
+
// [pipeline.stage.rms.performance] info: RMS processing complete
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Filter by stage (only RMS logs)
|
|
177
|
+
pipeline.pipeline({
|
|
178
|
+
onLogBatch: (logs) => {
|
|
179
|
+
logs.forEach((log) => console.log(log.message));
|
|
180
|
+
},
|
|
181
|
+
topicFilter: "pipeline.stage.rms.*", // Only RMS stage logs
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Filter by category (only errors)
|
|
185
|
+
pipeline.pipeline({
|
|
186
|
+
onLogBatch: (logs) => {
|
|
187
|
+
if (logs.length > 0) {
|
|
188
|
+
alertService.notify("Pipeline errors detected", logs);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
topicFilter: "pipeline.*.error", // All errors from any stage
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Multiple filters (errors + performance)
|
|
195
|
+
pipeline.pipeline({
|
|
196
|
+
onLogBatch: (logs) => {
|
|
197
|
+
logs.forEach((log) => {
|
|
198
|
+
if (log.topic.includes("error")) {
|
|
199
|
+
errorAlerts.push(log);
|
|
200
|
+
} else {
|
|
201
|
+
metrics.push(log);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
topicFilter: [
|
|
206
|
+
"pipeline.*.error", // All errors
|
|
207
|
+
"pipeline.*.performance", // All performance metrics
|
|
208
|
+
],
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Topic-Based Routing (Production Pattern)
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const pipeline = createDspPipeline();
|
|
216
|
+
|
|
217
|
+
pipeline.pipeline({
|
|
218
|
+
onLogBatch: (logs) => {
|
|
219
|
+
// Route logs to different backends based on topic
|
|
220
|
+
logs.forEach((log) => {
|
|
221
|
+
if (log.topic.includes("error")) {
|
|
222
|
+
// Send errors to alerting system (PagerDuty, Slack, etc.)
|
|
223
|
+
await alerting.send(log);
|
|
224
|
+
} else if (
|
|
225
|
+
log.topic.includes("performance") ||
|
|
226
|
+
log.topic.includes("samples")
|
|
227
|
+
) {
|
|
228
|
+
// Send metrics to monitoring (Prometheus, Datadog, etc.)
|
|
229
|
+
await metrics.record(log.topic, log.context);
|
|
230
|
+
} else {
|
|
231
|
+
// Send debug logs to centralized logging (Loki, Elasticsearch, etc.)
|
|
232
|
+
await logging.send(log);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Topic Filter Patterns
|
|
240
|
+
|
|
241
|
+
| Pattern | Matches |
|
|
242
|
+
| ---------------------------------------------- | ----------------------------------------- |
|
|
243
|
+
| `pipeline.stage.*` | All logs from any stage |
|
|
244
|
+
| `pipeline.stage.rms.*` | Only RMS stage logs |
|
|
245
|
+
| `pipeline.*.error` | All errors (any stage) |
|
|
246
|
+
| `pipeline.*.performance` | All performance metrics |
|
|
247
|
+
| `['pipeline.error', 'pipeline.stage.*.error']` | Multiple patterns (errors from any stage) |
|
|
248
|
+
|
|
249
|
+
### Production Benefits
|
|
250
|
+
|
|
251
|
+
- ✅ **Selective subscription** - Filter at source, reduce processing overhead
|
|
252
|
+
- ✅ **Topic-based routing** - Different topics → different backends (Kafka, Loki, Prometheus)
|
|
253
|
+
- ✅ **Industry alignment** - Matches telemetry standards (Kafka topics, NATS subjects, MQTT topics)
|
|
254
|
+
- ✅ **Efficient filtering** - Wildcard patterns processed before callback invocation
|
|
255
|
+
|
|
256
|
+
See `src/ts/examples/callbacks/topic-based-logging.ts` for comprehensive examples.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Topic Router (Fan-Out to Multiple Backends)
|
|
261
|
+
|
|
262
|
+
The `TopicRouter` provides **production-grade fan-out routing** to multiple observability backends, matching patterns used by Grafana Loki, OpenTelemetry, and FluentBit:
|
|
263
|
+
|
|
264
|
+
### Builder Pattern (Recommended)
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { createDspPipeline, createTopicRouter } from "dspx";
|
|
268
|
+
|
|
269
|
+
const router = createTopicRouter()
|
|
270
|
+
// Critical errors → PagerDuty
|
|
271
|
+
.errors(async (log) => {
|
|
272
|
+
await pagerDuty.alert(log);
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
// Performance metrics → Prometheus
|
|
276
|
+
.performance(async (log) => {
|
|
277
|
+
await prometheus.record(log.topic, log.context);
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
// Debug logs → Loki
|
|
281
|
+
.debug(async (log) => {
|
|
282
|
+
await loki.send(log);
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
// Everything else → CloudWatch (backup)
|
|
286
|
+
.default(async (log) => {
|
|
287
|
+
await cloudwatch.send(log);
|
|
288
|
+
})
|
|
289
|
+
.build();
|
|
290
|
+
|
|
291
|
+
const pipeline = createDspPipeline();
|
|
292
|
+
pipeline
|
|
293
|
+
.pipeline({
|
|
294
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
295
|
+
})
|
|
296
|
+
.MovingAverage({ windowSize: 10 })
|
|
297
|
+
.Rms({ windowSize: 5 });
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Custom Route Patterns
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const router = createTopicRouter()
|
|
304
|
+
.custom(/^pipeline\.error/, pagerDuty.alert, "error-alerts")
|
|
305
|
+
.custom(/^pipeline\.stage\.rms/, prometheusHandler, "rms-metrics")
|
|
306
|
+
.custom(/^pipeline\.performance/, prometheusHandler, "performance")
|
|
307
|
+
.custom(/.*/, loki.send, "default-logs")
|
|
308
|
+
.build();
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Multi-Backend Fan-Out
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
// Route errors to BOTH PagerDuty AND CloudWatch
|
|
315
|
+
const router = createTopicRouter()
|
|
316
|
+
.errors(async (log) => {
|
|
317
|
+
await Promise.all([
|
|
318
|
+
pagerDuty.alert(log),
|
|
319
|
+
cloudwatch.send(log), // Backup for audit
|
|
320
|
+
]);
|
|
321
|
+
})
|
|
322
|
+
.build();
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Stage-Specific Routing
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
const router = createTopicRouter()
|
|
329
|
+
.stage("rms", async (log) => {
|
|
330
|
+
// Only RMS stage logs
|
|
331
|
+
await prometheus.record(log.topic, log.context);
|
|
332
|
+
})
|
|
333
|
+
.stage("movingAverage", async (log) => {
|
|
334
|
+
// Only MovingAverage stage logs
|
|
335
|
+
await loki.send(log);
|
|
336
|
+
})
|
|
337
|
+
.build();
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Router API
|
|
341
|
+
|
|
342
|
+
| Method | Purpose | Example |
|
|
343
|
+
| ---------------- | ---------------------------------------------- | ---------------------------- |
|
|
344
|
+
| `.errors()` | Route errors to alerting (PagerDuty, Slack) | Critical alerts |
|
|
345
|
+
| `.performance()` | Route metrics to monitoring (Prometheus, DD) | Timing, throughput |
|
|
346
|
+
| `.debug()` | Route debug logs to centralized logging (Loki) | Development traces |
|
|
347
|
+
| `.alerts()` | Route threshold crossings to alerting | Anomaly detection |
|
|
348
|
+
| `.stage(name)` | Route stage-specific logs | Per-filter monitoring |
|
|
349
|
+
| `.custom(regex)` | Route with custom pattern | Organization-specific topics |
|
|
350
|
+
| `.default()` | Catch-all route (add last) | Backup logging |
|
|
351
|
+
|
|
352
|
+
### Production Benefits
|
|
353
|
+
|
|
354
|
+
- ✅ **Parallel routing**: All backends called concurrently (`Promise.all`)
|
|
355
|
+
- ✅ **Non-blocking**: Async handlers prevent DSP throughput impact
|
|
356
|
+
- ✅ **Error isolation**: Failed backend doesn't break pipeline
|
|
357
|
+
- ✅ **Type-safe**: Full TypeScript support with RouteHandler type
|
|
358
|
+
- ✅ **Extensible**: Add routes without modifying pipeline code
|
|
359
|
+
- ✅ **Industry standard**: Matches Loki, OTEL, FluentBit, Vector.dev patterns
|
|
360
|
+
|
|
361
|
+
See `src/ts/examples/callbacks/production-topic-router.ts` for comprehensive examples.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Priority-Based Routing (10-Level System)
|
|
366
|
+
|
|
367
|
+
The library supports a **10-level priority system** for fine-grained log filtering and routing. Each log can be assigned a priority from 1 (lowest) to 10 (highest), with default priorities automatically assigned based on log level.
|
|
368
|
+
|
|
369
|
+
### Default Priority Mapping
|
|
370
|
+
|
|
371
|
+
| Log Level | Priority | Use Case |
|
|
372
|
+
| --------- | -------- | -------------------------- |
|
|
373
|
+
| `debug` | 2 | Development traces |
|
|
374
|
+
| `info` | 5 | General information |
|
|
375
|
+
| `warn` | 7 | Warnings, potential issues |
|
|
376
|
+
| `error` | 9 | Critical errors, failures |
|
|
377
|
+
|
|
378
|
+
Logs without an explicit priority default to **priority 1**.
|
|
379
|
+
|
|
380
|
+
### Basic Priority Filtering
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
import { createDspPipeline, createTopicRouter } from "dspx";
|
|
384
|
+
import type { LogPriority } from "dspx";
|
|
385
|
+
|
|
386
|
+
// Route only high-priority logs (priority >= 7) to alerting
|
|
387
|
+
const router = createTopicRouter()
|
|
388
|
+
.errors(pagerDuty.alert, {
|
|
389
|
+
minPriority: 7, // Only warnings (7) and errors (9)
|
|
390
|
+
})
|
|
391
|
+
.performance(prometheus.record, {
|
|
392
|
+
minPriority: 5, // Info (5) and above
|
|
393
|
+
maxPriority: 7, // Exclude critical errors
|
|
394
|
+
})
|
|
395
|
+
.build();
|
|
396
|
+
|
|
397
|
+
const pipeline = createDspPipeline();
|
|
398
|
+
pipeline
|
|
399
|
+
.pipeline({
|
|
400
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
401
|
+
})
|
|
402
|
+
.MovingAverage({ windowSize: 10 })
|
|
403
|
+
.Rms({ windowSize: 5 });
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Custom Priority Assignment
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import type { LogEntry, LogPriority } from "dspx";
|
|
410
|
+
|
|
411
|
+
// Assign custom priorities in your backend handlers
|
|
412
|
+
const router = createTopicRouter()
|
|
413
|
+
.custom(/^pipeline\.stage\.rms/, async (log: LogEntry) => {
|
|
414
|
+
// Override priority based on context
|
|
415
|
+
const priority: LogPriority = log.context?.rmsValue > 100 ? 10 : 5;
|
|
416
|
+
|
|
417
|
+
await monitoring.send({
|
|
418
|
+
...log,
|
|
419
|
+
priority,
|
|
420
|
+
customField: "rms-analysis",
|
|
421
|
+
});
|
|
422
|
+
})
|
|
423
|
+
.build();
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Multi-Tier Routing by Priority
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
// Route logs to different backends based on priority tiers
|
|
430
|
+
const router = createTopicRouter()
|
|
431
|
+
// Critical (9-10): Immediate alerting
|
|
432
|
+
.custom(/.*/, pagerDuty.alert, "critical-alerts", {
|
|
433
|
+
minPriority: 9,
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
// High (7-8): Slack notifications
|
|
437
|
+
.custom(/.*/, slack.notify, "high-priority", {
|
|
438
|
+
minPriority: 7,
|
|
439
|
+
maxPriority: 8,
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
// Medium (4-6): Centralized logging
|
|
443
|
+
.custom(/.*/, loki.send, "medium-priority", {
|
|
444
|
+
minPriority: 4,
|
|
445
|
+
maxPriority: 6,
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
// Low (1-3): Debug logs only
|
|
449
|
+
.custom(/.*/, debugLogger.write, "low-priority", {
|
|
450
|
+
maxPriority: 3,
|
|
451
|
+
})
|
|
452
|
+
.build();
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Priority with Metrics Tracking
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
const router = createTopicRouter()
|
|
459
|
+
.errors(async (log: LogEntry) => {
|
|
460
|
+
// Track priority distribution
|
|
461
|
+
metrics.increment("logs.priority", {
|
|
462
|
+
level: log.level,
|
|
463
|
+
priority: log.priority ?? 1,
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// Only alert on high-priority errors
|
|
467
|
+
if ((log.priority ?? 1) >= 8) {
|
|
468
|
+
await pagerDuty.alert(log);
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
.build();
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Dynamic Priority Assignment
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
const router = createTopicRouter()
|
|
478
|
+
.custom(/^pipeline\.performance/, async (log: LogEntry) => {
|
|
479
|
+
// Calculate priority based on performance metrics
|
|
480
|
+
const duration = log.context?.durationMs || 0;
|
|
481
|
+
const priority: LogPriority =
|
|
482
|
+
duration > 1000
|
|
483
|
+
? 10 // Critical slowdown
|
|
484
|
+
: duration > 500
|
|
485
|
+
? 8 // High latency
|
|
486
|
+
: duration > 100
|
|
487
|
+
? 5 // Normal
|
|
488
|
+
: 2; // Fast
|
|
489
|
+
|
|
490
|
+
await monitoring.send({
|
|
491
|
+
...log,
|
|
492
|
+
priority,
|
|
493
|
+
severity: priority >= 8 ? "high" : "normal",
|
|
494
|
+
});
|
|
495
|
+
})
|
|
496
|
+
.build();
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Priority Filtering Options
|
|
500
|
+
|
|
501
|
+
| Option | Type | Description |
|
|
502
|
+
| ------------- | ------------- | -------------------------------- |
|
|
503
|
+
| `minPriority` | `LogPriority` | Minimum priority to route (1-10) |
|
|
504
|
+
| `maxPriority` | `LogPriority` | Maximum priority to route (1-10) |
|
|
505
|
+
|
|
506
|
+
### Production Benefits
|
|
507
|
+
|
|
508
|
+
- **Fine-grained control**: 10 priority levels for precise filtering
|
|
509
|
+
- **Default mapping**: Automatic priority assignment based on log level
|
|
510
|
+
- **Cost optimization**: Route low-priority logs to cheaper storage
|
|
511
|
+
- **Alert fatigue reduction**: Only high-priority logs trigger pages
|
|
512
|
+
- **Flexible thresholds**: Adjust priority cutoffs without code changes
|
|
513
|
+
- **Type-safe**: `LogPriority` type enforces valid values (1-10)
|
|
514
|
+
|
|
515
|
+
See `src/ts/examples/callbacks/priority-routing-example.ts` for comprehensive examples.
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Debugging with `.tap()`
|
|
520
|
+
|
|
521
|
+
Inspect pipeline intermediate results at any point using `.tap()` - a pure TypeScript method (no C++ changes):
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
const pipeline = createDspPipeline()
|
|
525
|
+
.MovingAverage({ windowSize: 10 })
|
|
526
|
+
.tap((samples, stage) => {
|
|
527
|
+
console.log(`After ${stage}:`, samples.slice(0, 5));
|
|
528
|
+
})
|
|
529
|
+
.Rectify({ mode: "full" })
|
|
530
|
+
.tap((samples, stage) => {
|
|
531
|
+
const max = Math.max(...samples);
|
|
532
|
+
if (max > THRESHOLD) {
|
|
533
|
+
logger.warn(`High value detected at ${stage}: ${max}`);
|
|
534
|
+
}
|
|
535
|
+
})
|
|
536
|
+
.Rms({ windowSize: 5 });
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Use Cases
|
|
540
|
+
|
|
541
|
+
- 🐛 **Debug pipeline behavior** - Inspect values between stages
|
|
542
|
+
- 📊 **Collect statistics** - Calculate min/max/mean at any point
|
|
543
|
+
- ⚠️ **Threshold monitoring** - Alert on anomalies during processing
|
|
544
|
+
- 📝 **Logger integration** - Conditional logging based on sample values
|
|
545
|
+
- 🔍 **Development insights** - Understand signal transformations
|
|
546
|
+
|
|
547
|
+
### Performance
|
|
548
|
+
|
|
549
|
+
- Minimal overhead (~4% with empty callbacks in benchmarks)
|
|
550
|
+
- Remove `.tap()` calls in production or use conditional logic
|
|
551
|
+
- Errors in tap callbacks are caught and logged (won't break pipeline)
|
|
552
|
+
|
|
553
|
+
See `src/ts/examples/tap-debugging.ts` for comprehensive examples.
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Back to Main Documentation
|
|
558
|
+
|
|
559
|
+
[← Back to README](../README.md)
|