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
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced Topic Router Features Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates:
|
|
5
|
+
* 1. Concurrency control per route
|
|
6
|
+
* 2. Metrics tracking and monitoring
|
|
7
|
+
* 3. Pluggable backend handlers
|
|
8
|
+
* 4. Production-grade observability
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
createDspPipeline,
|
|
13
|
+
createTopicRouter,
|
|
14
|
+
createConsoleHandler,
|
|
15
|
+
createMockHandler,
|
|
16
|
+
} from "../../index.js";
|
|
17
|
+
|
|
18
|
+
console.log("Advanced Topic Router Features\n");
|
|
19
|
+
|
|
20
|
+
// Example 1: Concurrency Control
|
|
21
|
+
console.log("1. Concurrency Control (Prevent Alert Storms)\n");
|
|
22
|
+
{
|
|
23
|
+
let alertCount = 0;
|
|
24
|
+
const slowAlertHandler = async () => {
|
|
25
|
+
alertCount++;
|
|
26
|
+
console.log(
|
|
27
|
+
` [Alert ${alertCount}] Processing (simulating network call)...`
|
|
28
|
+
);
|
|
29
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
30
|
+
console.log(` [Alert ${alertCount}] Complete`);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const router = createTopicRouter()
|
|
34
|
+
.errors(slowAlertHandler, {
|
|
35
|
+
concurrency: 2, // Max 2 concurrent alerts
|
|
36
|
+
trackMetrics: true,
|
|
37
|
+
})
|
|
38
|
+
.default(createConsoleHandler())
|
|
39
|
+
.build();
|
|
40
|
+
|
|
41
|
+
const pipeline = createDspPipeline();
|
|
42
|
+
pipeline
|
|
43
|
+
.pipeline({
|
|
44
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
45
|
+
})
|
|
46
|
+
.MovingAverage({ mode: "moving", windowSize: 3 });
|
|
47
|
+
|
|
48
|
+
console.log(" Processing with concurrency limit of 2...\n");
|
|
49
|
+
|
|
50
|
+
const samples = new Float32Array([1, 2, 3]);
|
|
51
|
+
await pipeline.process(samples, { sampleRate: 1000 });
|
|
52
|
+
|
|
53
|
+
console.log("\n Metrics:");
|
|
54
|
+
const metrics = router.getMetrics();
|
|
55
|
+
metrics.forEach((m) => {
|
|
56
|
+
console.log(` âĸ Route: ${m.name}`);
|
|
57
|
+
console.log(` Executions: ${m.executionCount}`);
|
|
58
|
+
console.log(` Avg Duration: ${m.averageDuration.toFixed(2)}ms`);
|
|
59
|
+
console.log(
|
|
60
|
+
` Min/Max: ${m.minDuration.toFixed(2)}ms / ${m.maxDuration.toFixed(
|
|
61
|
+
2
|
|
62
|
+
)}ms`
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Example 2: Metrics Tracking
|
|
70
|
+
console.log("2. Metrics Tracking (Mini-OpenTelemetry)\n");
|
|
71
|
+
{
|
|
72
|
+
const mock = createMockHandler((log) => {
|
|
73
|
+
console.log(` Tracked: [${log.topic}] ${log.message}`);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const router = createTopicRouter()
|
|
77
|
+
.performance(mock.handler, {
|
|
78
|
+
trackMetrics: true,
|
|
79
|
+
concurrency: 5,
|
|
80
|
+
})
|
|
81
|
+
.debug(mock.handler, {
|
|
82
|
+
trackMetrics: true,
|
|
83
|
+
})
|
|
84
|
+
.default(mock.handler, {
|
|
85
|
+
trackMetrics: false, // No tracking for default route
|
|
86
|
+
})
|
|
87
|
+
.build();
|
|
88
|
+
|
|
89
|
+
const pipeline = createDspPipeline();
|
|
90
|
+
pipeline
|
|
91
|
+
.pipeline({
|
|
92
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
93
|
+
})
|
|
94
|
+
.MovingAverage({ mode: "moving", windowSize: 3 })
|
|
95
|
+
.Rms({ mode: "moving", windowSize: 5 });
|
|
96
|
+
|
|
97
|
+
const samples = new Float32Array([1, -2, 3, -4, 5]);
|
|
98
|
+
await pipeline.process(samples, { sampleRate: 1000 });
|
|
99
|
+
|
|
100
|
+
console.log("\n Route Metrics:");
|
|
101
|
+
const metrics = router.getMetrics();
|
|
102
|
+
metrics.forEach((m) => {
|
|
103
|
+
console.log(`\n Route: ${m.name}`);
|
|
104
|
+
console.log(` âĸ Executions: ${m.executionCount}`);
|
|
105
|
+
console.log(` âĸ Total Duration: ${m.totalDuration.toFixed(2)}ms`);
|
|
106
|
+
console.log(` âĸ Avg Duration: ${m.averageDuration.toFixed(2)}ms`);
|
|
107
|
+
console.log(
|
|
108
|
+
` âĸ Min/Max: ${m.minDuration.toFixed(2)}ms / ${m.maxDuration.toFixed(
|
|
109
|
+
2
|
|
110
|
+
)}ms`
|
|
111
|
+
);
|
|
112
|
+
console.log(` âĸ Errors: ${m.errorCount}`);
|
|
113
|
+
console.log(
|
|
114
|
+
` âĸ Last Executed: ${
|
|
115
|
+
m.lastExecuted ? new Date(m.lastExecuted).toISOString() : "Never"
|
|
116
|
+
}`
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(`\n Total logs captured: ${mock.getLogs().length}`);
|
|
121
|
+
console.log();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Example 3: Pluggable Backends
|
|
125
|
+
console.log("3. Pluggable Backend Handlers\n");
|
|
126
|
+
{
|
|
127
|
+
console.log(" Using built-in handlers:\n");
|
|
128
|
+
|
|
129
|
+
// Simulate backend configurations
|
|
130
|
+
const mockPagerDuty = createMockHandler((log) => {
|
|
131
|
+
console.log(` [PagerDuty] Alert triggered: ${log.message}`);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const mockPrometheus = createMockHandler((log) => {
|
|
135
|
+
console.log(` [Prometheus] Metric recorded: ${log.topic}`);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const mockLoki = createMockHandler((log) => {
|
|
139
|
+
console.log(` [Loki] Log stored: [${log.level}] ${log.message}`);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const router = createTopicRouter()
|
|
143
|
+
.errors(mockPagerDuty.handler, { trackMetrics: true })
|
|
144
|
+
.performance(mockPrometheus.handler, { trackMetrics: true })
|
|
145
|
+
.debug(mockLoki.handler, { trackMetrics: true })
|
|
146
|
+
.build();
|
|
147
|
+
|
|
148
|
+
const pipeline = createDspPipeline();
|
|
149
|
+
pipeline
|
|
150
|
+
.pipeline({
|
|
151
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
152
|
+
})
|
|
153
|
+
.MovingAverage({ mode: "moving", windowSize: 3 });
|
|
154
|
+
|
|
155
|
+
const samples = new Float32Array([1, 2, 3]);
|
|
156
|
+
await pipeline.process(samples, { sampleRate: 1000 });
|
|
157
|
+
|
|
158
|
+
console.log("\n Backend Summary:");
|
|
159
|
+
console.log(` âĸ PagerDuty logs: ${mockPagerDuty.getLogs().length}`);
|
|
160
|
+
console.log(` âĸ Prometheus logs: ${mockPrometheus.getLogs().length}`);
|
|
161
|
+
console.log(` âĸ Loki logs: ${mockLoki.getLogs().length}`);
|
|
162
|
+
console.log();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Example 4: Production-Grade Setup
|
|
166
|
+
console.log("4. Production-Grade Configuration\n");
|
|
167
|
+
{
|
|
168
|
+
console.log(" Multi-tier routing with metrics + concurrency:\n");
|
|
169
|
+
|
|
170
|
+
const criticalAlerts = createMockHandler((log) => {
|
|
171
|
+
console.log(` [CRITICAL] ${log.message}`);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const performanceMetrics = createMockHandler((log) => {
|
|
175
|
+
console.log(` [METRICS] ${log.topic}: ${JSON.stringify(log.context)}`);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const debugLogs = createMockHandler();
|
|
179
|
+
|
|
180
|
+
const router = createTopicRouter()
|
|
181
|
+
// Critical errors: Limited concurrency to prevent PagerDuty overload
|
|
182
|
+
.errors(criticalAlerts.handler, {
|
|
183
|
+
concurrency: 3,
|
|
184
|
+
trackMetrics: true,
|
|
185
|
+
})
|
|
186
|
+
// Performance: Higher concurrency for metrics
|
|
187
|
+
.performance(performanceMetrics.handler, {
|
|
188
|
+
concurrency: 10,
|
|
189
|
+
trackMetrics: true,
|
|
190
|
+
})
|
|
191
|
+
// Debug: No concurrency limit, but track metrics
|
|
192
|
+
.debug(debugLogs.handler, {
|
|
193
|
+
trackMetrics: true,
|
|
194
|
+
})
|
|
195
|
+
// Default: Console with no limits
|
|
196
|
+
.default(createConsoleHandler(), {
|
|
197
|
+
trackMetrics: false,
|
|
198
|
+
})
|
|
199
|
+
.build();
|
|
200
|
+
|
|
201
|
+
const pipeline = createDspPipeline();
|
|
202
|
+
pipeline
|
|
203
|
+
.pipeline({
|
|
204
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
205
|
+
})
|
|
206
|
+
.MovingAverage({ mode: "moving", windowSize: 10 })
|
|
207
|
+
.Rectify()
|
|
208
|
+
.Rms({ mode: "moving", windowSize: 5 });
|
|
209
|
+
|
|
210
|
+
const samples = new Float32Array(50).map(() => Math.random() * 10 - 5);
|
|
211
|
+
await pipeline.process(samples, { sampleRate: 48000 });
|
|
212
|
+
|
|
213
|
+
console.log("\n Final Metrics Report:");
|
|
214
|
+
const metrics = router.getMetrics();
|
|
215
|
+
|
|
216
|
+
console.log(
|
|
217
|
+
"\n âââââââââââââââââââââââŦâââââââââââŦââââââââââââââŦâââââââââââââ"
|
|
218
|
+
);
|
|
219
|
+
console.log(
|
|
220
|
+
" â Route â Exec â Avg (ms) â Errors â"
|
|
221
|
+
);
|
|
222
|
+
console.log(
|
|
223
|
+
" âââââââââââââââââââââââŧâââââââââââŧââââââââââââââŧâââââââââââââ¤"
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
metrics.forEach((m) => {
|
|
227
|
+
const route = m.name.padEnd(19);
|
|
228
|
+
const exec = String(m.executionCount).padEnd(8);
|
|
229
|
+
const avg = m.averageDuration.toFixed(2).padEnd(11);
|
|
230
|
+
const errors = String(m.errorCount).padEnd(10);
|
|
231
|
+
console.log(` â ${route} â ${exec} â ${avg} â ${errors} â`);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
console.log(
|
|
235
|
+
" âââââââââââââââââââââââ´âââââââââââ´ââââââââââââââ´âââââââââââââ"
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
console.log("\n Performance Insights:");
|
|
239
|
+
const totalExec = metrics.reduce((sum, m) => sum + m.executionCount, 0);
|
|
240
|
+
const avgLatency =
|
|
241
|
+
metrics.reduce((sum, m) => sum + m.averageDuration, 0) / metrics.length;
|
|
242
|
+
const totalErrors = metrics.reduce((sum, m) => sum + m.errorCount, 0);
|
|
243
|
+
|
|
244
|
+
console.log(` âĸ Total Route Executions: ${totalExec}`);
|
|
245
|
+
console.log(` âĸ Average Route Latency: ${avgLatency.toFixed(2)}ms`);
|
|
246
|
+
console.log(` âĸ Total Errors: ${totalErrors}`);
|
|
247
|
+
console.log(
|
|
248
|
+
` âĸ Success Rate: ${((1 - totalErrors / totalExec) * 100).toFixed(2)}%`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Example 5: Priority-Based Routing
|
|
253
|
+
console.log("\n5. Priority-Based Routing (NEW)\n");
|
|
254
|
+
{
|
|
255
|
+
console.log(
|
|
256
|
+
" Route critical errors to PagerDuty, warnings to Prometheus\n"
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const pagerDuty = createMockHandler((log) => {
|
|
260
|
+
console.log(
|
|
261
|
+
` [PagerDuty] ALERT: ${log.message} (priority: ${log.priority})`
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const prometheus = createMockHandler((log) => {
|
|
266
|
+
console.log(
|
|
267
|
+
` [Prometheus] Metric: ${log.message} (priority: ${log.priority})`
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const loki = createMockHandler((log) => {
|
|
272
|
+
console.log(` [Loki] Log: ${log.message} (priority: ${log.priority})`);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const router = createTopicRouter()
|
|
276
|
+
// Critical errors (9-10) â PagerDuty
|
|
277
|
+
.errors(pagerDuty.handler, {
|
|
278
|
+
minPriority: 9,
|
|
279
|
+
maxPriority: 10,
|
|
280
|
+
concurrency: 3,
|
|
281
|
+
})
|
|
282
|
+
// Warnings (7-8) â Prometheus
|
|
283
|
+
.custom(/^pipeline\./, prometheus.handler, {
|
|
284
|
+
minPriority: 7,
|
|
285
|
+
maxPriority: 8,
|
|
286
|
+
})
|
|
287
|
+
// All logs â Loki
|
|
288
|
+
.default(loki.handler, {
|
|
289
|
+
minPriority: 1,
|
|
290
|
+
maxPriority: 10,
|
|
291
|
+
})
|
|
292
|
+
.build();
|
|
293
|
+
|
|
294
|
+
const pipeline = createDspPipeline();
|
|
295
|
+
pipeline
|
|
296
|
+
.pipeline({
|
|
297
|
+
onLogBatch: (logs) => router.routeBatch(logs),
|
|
298
|
+
})
|
|
299
|
+
.MovingAverage({ mode: "moving", windowSize: 5 });
|
|
300
|
+
|
|
301
|
+
const samples = new Float32Array([1, 2, 3, 4, 5]);
|
|
302
|
+
await pipeline.process(samples, { sampleRate: 1000 });
|
|
303
|
+
|
|
304
|
+
console.log(`\n Priority Summary:`);
|
|
305
|
+
console.log(
|
|
306
|
+
` âĸ PagerDuty (critical 9-10): ${pagerDuty.getLogs().length} alerts`
|
|
307
|
+
);
|
|
308
|
+
console.log(
|
|
309
|
+
` âĸ Prometheus (warn 7-8): ${prometheus.getLogs().length} metrics`
|
|
310
|
+
);
|
|
311
|
+
console.log(` âĸ Loki (all): ${loki.getLogs().length} logs`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
console.log("\nAdvanced Features Summary:");
|
|
315
|
+
console.log(" - Concurrency Control - Prevent backend overload");
|
|
316
|
+
console.log(" - Metrics Tracking - Built-in observability");
|
|
317
|
+
console.log(" - Pluggable Backends - Drop-in integrations");
|
|
318
|
+
console.log(" - Priority Routing - 10-level smart routing (NEW)");
|
|
319
|
+
console.log(" - Production-Ready - Real-world patterns");
|
|
320
|
+
|
|
321
|
+
console.log("\nUse Cases:");
|
|
322
|
+
console.log(" âĸ Rate-limit PagerDuty alerts (concurrency: 3)");
|
|
323
|
+
console.log(" âĸ Track route performance (trackMetrics: true)");
|
|
324
|
+
console.log(" âĸ Monitor error rates per backend");
|
|
325
|
+
console.log(" âĸ Route by priority (critical â PagerDuty, warn â metrics)");
|
|
326
|
+
console.log(" âĸ Optimize routing strategy with metrics");
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Benchmark: Circular Buffer vs Array for Log Pooling
|
|
3
|
+
* Demonstrates memory and performance benefits of circular buffer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { CircularLogBuffer } from "../../CircularLogBuffer.js";
|
|
7
|
+
import type { LogEntry } from "../../types.js";
|
|
8
|
+
|
|
9
|
+
function benchmarkArray(iterations: number, logsPerIteration: number): number {
|
|
10
|
+
const startTime = performance.now();
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < iterations; i++) {
|
|
13
|
+
const logPool: LogEntry[] = [];
|
|
14
|
+
|
|
15
|
+
// Simulate log accumulation
|
|
16
|
+
for (let j = 0; j < logsPerIteration; j++) {
|
|
17
|
+
logPool.push({
|
|
18
|
+
level: "info",
|
|
19
|
+
message: `Log entry ${j}`,
|
|
20
|
+
context: { iteration: i, index: j },
|
|
21
|
+
timestamp: performance.now(),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Simulate flush
|
|
26
|
+
const logs = [...logPool];
|
|
27
|
+
// In real app: send logs to callback
|
|
28
|
+
const _sum = logs.length;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return performance.now() - startTime;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function benchmarkCircularBuffer(
|
|
35
|
+
iterations: number,
|
|
36
|
+
logsPerIteration: number
|
|
37
|
+
): number {
|
|
38
|
+
const buffer = new CircularLogBuffer(32);
|
|
39
|
+
const startTime = performance.now();
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < iterations; i++) {
|
|
42
|
+
// Simulate log accumulation
|
|
43
|
+
for (let j = 0; j < logsPerIteration; j++) {
|
|
44
|
+
buffer.push({
|
|
45
|
+
level: "info",
|
|
46
|
+
message: `Log entry ${j}`,
|
|
47
|
+
context: { iteration: i, index: j },
|
|
48
|
+
timestamp: performance.now(),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Simulate flush
|
|
53
|
+
const logs = buffer.flush();
|
|
54
|
+
// In real app: send logs to callback
|
|
55
|
+
const _sum = logs.length;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return performance.now() - startTime;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log("Benchmarking Log Pooling: Array vs Circular Buffer\n");
|
|
62
|
+
|
|
63
|
+
const testCases = [
|
|
64
|
+
{
|
|
65
|
+
iterations: 1000,
|
|
66
|
+
logsPerIteration: 3,
|
|
67
|
+
description: "1000 iterations à 3 logs (typical usage)",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
iterations: 10000,
|
|
71
|
+
logsPerIteration: 5,
|
|
72
|
+
description: "10000 iterations à 5 logs (high frequency)",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
iterations: 100000,
|
|
76
|
+
logsPerIteration: 2,
|
|
77
|
+
description: "100000 iterations à 2 logs (extreme load)",
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
for (const testCase of testCases) {
|
|
82
|
+
console.log(`Test: ${testCase.description}`);
|
|
83
|
+
|
|
84
|
+
// Warm-up
|
|
85
|
+
benchmarkArray(10, testCase.logsPerIteration);
|
|
86
|
+
benchmarkCircularBuffer(10, testCase.logsPerIteration);
|
|
87
|
+
|
|
88
|
+
// Run benchmarks
|
|
89
|
+
const arrayTime = benchmarkArray(
|
|
90
|
+
testCase.iterations,
|
|
91
|
+
testCase.logsPerIteration
|
|
92
|
+
);
|
|
93
|
+
const circularTime = benchmarkCircularBuffer(
|
|
94
|
+
testCase.iterations,
|
|
95
|
+
testCase.logsPerIteration
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
console.log(` Array approach: ${arrayTime.toFixed(3)}ms`);
|
|
99
|
+
console.log(` Circular buffer approach: ${circularTime.toFixed(3)}ms`);
|
|
100
|
+
console.log(` Speedup: ${(arrayTime / circularTime).toFixed(2)}x faster`);
|
|
101
|
+
console.log(` Time saved: ${(arrayTime - circularTime).toFixed(3)}ms\n`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log("Key Benefits of Circular Buffer:");
|
|
105
|
+
console.log(" - Fixed memory footprint (no array reallocations)");
|
|
106
|
+
console.log(" - No garbage collection pressure from temporary arrays");
|
|
107
|
+
console.log(" - Cache-friendly memory access pattern");
|
|
108
|
+
console.log(" - Predictable performance under load");
|
|
109
|
+
console.log(" - Handles burst logging gracefully (overwrites oldest)");
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { createDspPipeline } from "../../bindings.js";
|
|
2
|
+
import type { PipelineCallbacks, LogLevel } from "../../types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Example: Real-time audio monitoring with callbacks
|
|
6
|
+
* Demonstrates selective callback usage for performance monitoring
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
class PerformanceMonitor {
|
|
10
|
+
private stageTimes = new Map<string, number[]>();
|
|
11
|
+
|
|
12
|
+
recordStageTime(stage: string, durationMs: number) {
|
|
13
|
+
if (!this.stageTimes.has(stage)) {
|
|
14
|
+
this.stageTimes.set(stage, []);
|
|
15
|
+
}
|
|
16
|
+
this.stageTimes.get(stage)!.push(durationMs);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getStats(stage: string) {
|
|
20
|
+
const times = this.stageTimes.get(stage) || [];
|
|
21
|
+
if (times.length === 0) {
|
|
22
|
+
return { min: 0, max: 0, avg: 0, count: 0 };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
min: Math.min(...times),
|
|
27
|
+
max: Math.max(...times),
|
|
28
|
+
avg: times.reduce((a, b) => a + b, 0) / times.length,
|
|
29
|
+
count: times.length,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
printReport() {
|
|
34
|
+
console.log("\nPerformance Report:");
|
|
35
|
+
console.log("â".repeat(70));
|
|
36
|
+
console.log(
|
|
37
|
+
"Stage".padEnd(30),
|
|
38
|
+
"Count".padEnd(10),
|
|
39
|
+
"Avg (ms)".padEnd(10),
|
|
40
|
+
"Min (ms)".padEnd(10),
|
|
41
|
+
"Max (ms)"
|
|
42
|
+
);
|
|
43
|
+
console.log("â".repeat(70));
|
|
44
|
+
|
|
45
|
+
for (const [stage, _] of this.stageTimes) {
|
|
46
|
+
const stats = this.getStats(stage);
|
|
47
|
+
console.log(
|
|
48
|
+
stage.padEnd(30),
|
|
49
|
+
stats.count.toString().padEnd(10),
|
|
50
|
+
stats.avg.toFixed(3).padEnd(10),
|
|
51
|
+
stats.min.toFixed(3).padEnd(10),
|
|
52
|
+
stats.max.toFixed(3)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
console.log("â".repeat(70));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class SignalAnalyzer {
|
|
60
|
+
private peakCount = 0;
|
|
61
|
+
private clipCount = 0;
|
|
62
|
+
|
|
63
|
+
analyzeSample(value: number, index: number, stage: string) {
|
|
64
|
+
const absValue = Math.abs(value);
|
|
65
|
+
|
|
66
|
+
// Detect clipping (value at maximum)
|
|
67
|
+
if (absValue >= 0.99) {
|
|
68
|
+
this.clipCount++;
|
|
69
|
+
console.log(
|
|
70
|
+
`â ī¸ Clipping detected at sample ${index} in ${stage}: ${value.toFixed(
|
|
71
|
+
4
|
|
72
|
+
)}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
// Detect peaks (high amplitude)
|
|
76
|
+
else if (absValue > 0.85) {
|
|
77
|
+
this.peakCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getReport() {
|
|
82
|
+
return {
|
|
83
|
+
peaks: this.peakCount,
|
|
84
|
+
clips: this.clipCount,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function monitoringExample() {
|
|
90
|
+
console.log("=".repeat(70));
|
|
91
|
+
console.log("Real-time Audio Monitoring with Callbacks");
|
|
92
|
+
console.log("=".repeat(70));
|
|
93
|
+
console.log();
|
|
94
|
+
|
|
95
|
+
const monitor = new PerformanceMonitor();
|
|
96
|
+
const analyzer = new SignalAnalyzer();
|
|
97
|
+
|
|
98
|
+
const callbacks: PipelineCallbacks = {
|
|
99
|
+
// Analyze every sample for clipping/peaks (can be disabled for performance)
|
|
100
|
+
onSample: (value, index, stage) => {
|
|
101
|
+
analyzer.analyzeSample(value, index, stage);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Track performance of each processing run
|
|
105
|
+
onStageComplete: (stage, durationMs) => {
|
|
106
|
+
monitor.recordStageTime(stage, durationMs);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// Handle errors gracefully
|
|
110
|
+
onError: (stage, error) => {
|
|
111
|
+
console.error(`â Error in ${stage}:`, error.message);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
// Structured logging
|
|
115
|
+
onLog: (level, msg, ctx) => {
|
|
116
|
+
const timestamp = new Date().toISOString();
|
|
117
|
+
const emoji = {
|
|
118
|
+
debug: "đ",
|
|
119
|
+
info: "âšī¸",
|
|
120
|
+
warn: "â ī¸",
|
|
121
|
+
error: "â",
|
|
122
|
+
}[level];
|
|
123
|
+
|
|
124
|
+
if (level !== "debug") {
|
|
125
|
+
console.log(
|
|
126
|
+
`${emoji} [${timestamp}] [${level.toUpperCase()}] ${msg}`,
|
|
127
|
+
ctx ? JSON.stringify(ctx) : ""
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Build pipeline with comprehensive processing
|
|
134
|
+
const pipeline = createDspPipeline()
|
|
135
|
+
.pipeline(callbacks)
|
|
136
|
+
.MovingAverage({ mode: "moving", windowSize: 5 })
|
|
137
|
+
.Rectify({ mode: "full" })
|
|
138
|
+
.Rms({ mode: "moving", windowSize: 10 });
|
|
139
|
+
|
|
140
|
+
console.log("Processing audio batches...\n");
|
|
141
|
+
|
|
142
|
+
// Simulate multiple processing batches (like streaming audio)
|
|
143
|
+
const sampleRate = 44100;
|
|
144
|
+
const batchSize = 512; // Typical audio buffer size
|
|
145
|
+
const numBatches = 5;
|
|
146
|
+
|
|
147
|
+
for (let batch = 0; batch < numBatches; batch++) {
|
|
148
|
+
console.log(`\nProcessing batch ${batch + 1}/${numBatches}...`);
|
|
149
|
+
|
|
150
|
+
// Generate test signal with varying characteristics
|
|
151
|
+
const signal = new Float32Array(batchSize);
|
|
152
|
+
for (let i = 0; i < batchSize; i++) {
|
|
153
|
+
// Add some variation between batches
|
|
154
|
+
const amplitude = 0.5 + batch * 0.1;
|
|
155
|
+
signal[i] = Math.sin((2 * Math.PI * 440 * i) / sampleRate) * amplitude;
|
|
156
|
+
|
|
157
|
+
// Add occasional peaks
|
|
158
|
+
if (i % 100 === 0) {
|
|
159
|
+
signal[i] = 0.95;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Add occasional clips in later batches
|
|
163
|
+
if (batch >= 3 && i % 150 === 0) {
|
|
164
|
+
signal[i] = 1.0; // Clipping!
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
await pipeline.process(signal, { sampleRate, channels: 1 });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Print reports
|
|
172
|
+
monitor.printReport();
|
|
173
|
+
|
|
174
|
+
const signalStats = analyzer.getReport();
|
|
175
|
+
console.log("\nSignal Analysis:");
|
|
176
|
+
console.log("â".repeat(70));
|
|
177
|
+
console.log(` Peak samples (> 0.85): ${signalStats.peaks}`);
|
|
178
|
+
console.log(` Clipped samples (>= 0.99): ${signalStats.clips}`);
|
|
179
|
+
console.log("â".repeat(70));
|
|
180
|
+
|
|
181
|
+
console.log("\nMonitoring complete!\n");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function selectiveCallbacksExample() {
|
|
185
|
+
console.log("\n" + "=".repeat(70));
|
|
186
|
+
console.log("Selective Callbacks Example (Performance-Optimized)");
|
|
187
|
+
console.log("=".repeat(70));
|
|
188
|
+
console.log();
|
|
189
|
+
|
|
190
|
+
let processCount = 0;
|
|
191
|
+
|
|
192
|
+
// Use only the callbacks you need for better performance
|
|
193
|
+
const lightweightCallbacks: PipelineCallbacks = {
|
|
194
|
+
// No onSample callback - saves significant overhead for large buffers
|
|
195
|
+
// onSample: undefined,
|
|
196
|
+
|
|
197
|
+
onStageComplete: (stage, durationMs) => {
|
|
198
|
+
processCount++;
|
|
199
|
+
console.log(
|
|
200
|
+
`â Batch ${processCount}: ${stage} completed in ${durationMs.toFixed(
|
|
201
|
+
3
|
|
202
|
+
)}ms`
|
|
203
|
+
);
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
// Only log errors and warnings
|
|
207
|
+
onLog: (level, msg, ctx) => {
|
|
208
|
+
if (level === "error" || level === "warn") {
|
|
209
|
+
console.log(`[${level.toUpperCase()}] ${msg}`, ctx || "");
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const pipeline = createDspPipeline()
|
|
215
|
+
.pipeline(lightweightCallbacks)
|
|
216
|
+
.MovingAverage({ mode: "moving", windowSize: 3 })
|
|
217
|
+
.Rms({ mode: "moving", windowSize: 5 });
|
|
218
|
+
|
|
219
|
+
console.log("Processing large batches without per-sample callbacks...\n");
|
|
220
|
+
|
|
221
|
+
// Process larger buffers more efficiently
|
|
222
|
+
const largeBuffer = new Float32Array(4096);
|
|
223
|
+
for (let i = 0; i < largeBuffer.length; i++) {
|
|
224
|
+
largeBuffer[i] = Math.random() * 0.5;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const iterations = 10;
|
|
228
|
+
const startTime = performance.now();
|
|
229
|
+
|
|
230
|
+
for (let i = 0; i < iterations; i++) {
|
|
231
|
+
await pipeline.process(largeBuffer, { sampleRate: 44100, channels: 1 });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const totalTime = performance.now() - startTime;
|
|
235
|
+
const avgTime = totalTime / iterations;
|
|
236
|
+
|
|
237
|
+
console.log("\n" + "â".repeat(70));
|
|
238
|
+
console.log(
|
|
239
|
+
`Processed ${iterations} batches of ${largeBuffer.length} samples`
|
|
240
|
+
);
|
|
241
|
+
console.log(`Total time: ${totalTime.toFixed(2)}ms`);
|
|
242
|
+
console.log(`Average per batch: ${avgTime.toFixed(3)}ms`);
|
|
243
|
+
console.log(
|
|
244
|
+
`Throughput: ${(
|
|
245
|
+
(largeBuffer.length * iterations) /
|
|
246
|
+
(totalTime / 1000)
|
|
247
|
+
).toFixed(0)} samples/sec`
|
|
248
|
+
);
|
|
249
|
+
console.log("â".repeat(70));
|
|
250
|
+
|
|
251
|
+
console.log("\nPerformance test complete!\n");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function main() {
|
|
255
|
+
try {
|
|
256
|
+
// Run both examples
|
|
257
|
+
await monitoringExample();
|
|
258
|
+
await selectiveCallbacksExample();
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error("Example failed:", error);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
main();
|