@camstack/system 1.2.12 → 1.2.14
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/dist/addon-runner.js +2 -2
- package/dist/addon-runner.mjs +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.d.ts +4 -0
- package/dist/builtins/loki-logging/index.js +445 -0
- package/dist/builtins/loki-logging/index.mjs +431 -0
- package/dist/builtins/loki-logging/loki-destination.d.ts +88 -0
- package/dist/builtins/loki-logging/loki-logging.addon.d.ts +36 -0
- package/dist/builtins/loki-logging/loki-payload.d.ts +46 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-DpKeSZel.mjs → dist-eOaraBhT.mjs} +21 -1
- package/dist/{dist-BQOCTD5b.js → dist-yttC1aUI.js} +26 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +128 -15
- package/dist/index.mjs +127 -16
- package/dist/kernel/config-schema.d.ts +38 -1
- package/dist/logging/log-manager.d.ts +14 -4
- package/dist/logging/log-ring-buffer.d.ts +15 -0
- package/dist/logging/partitioned-log-buffer.d.ts +49 -6
- package/dist/{manifest-python-deps-1I7WdPDD.js → manifest-python-deps-DSrmih6E.js} +1 -1
- package/dist/{manifest-python-deps-I2MGvDvo.mjs → manifest-python-deps-bn3qrsxR.mjs} +1 -1
- package/package.json +13 -1
|
@@ -5,8 +5,8 @@ export declare const DEFAULT_DATA_PATH = "camstack-data";
|
|
|
5
5
|
* All other settings live in SQL (system_settings table). */
|
|
6
6
|
export declare const bootstrapSchema: z.ZodObject<{
|
|
7
7
|
mode: z.ZodDefault<z.ZodEnum<{
|
|
8
|
-
agent: "agent";
|
|
9
8
|
hub: "hub";
|
|
9
|
+
agent: "agent";
|
|
10
10
|
}>>;
|
|
11
11
|
server: z.ZodDefault<z.ZodObject<{
|
|
12
12
|
port: z.ZodDefault<z.ZodNumber>;
|
|
@@ -70,7 +70,44 @@ export type AppConfig = BootstrapConfig & {
|
|
|
70
70
|
retentionDays: number;
|
|
71
71
|
};
|
|
72
72
|
eventBus: {
|
|
73
|
+
/** System-EVENT ring size. Separate from the log buffer below. */
|
|
73
74
|
ringBufferSize: number;
|
|
75
|
+
/**
|
|
76
|
+
* Per-addon log ring-buffer capacity, in entries. Default 5000.
|
|
77
|
+
*
|
|
78
|
+
* A HARD bound on EACH addon's bucket, not the total — the buffer is
|
|
79
|
+
* partitioned by `addonId` (`PartitionedLogBuffer`), so a chatty addon evicts
|
|
80
|
+
* only its own lines and a quiet one keeps its sparse history. Worst-case
|
|
81
|
+
* memory is therefore `this × number of addons that have logged`, which is
|
|
82
|
+
* why the total below exists.
|
|
83
|
+
*
|
|
84
|
+
* Hub-only: the agent constructs its `LogManager` with a hardcoded 5000.
|
|
85
|
+
*/
|
|
86
|
+
perAddonLogBufferSize?: number;
|
|
87
|
+
/**
|
|
88
|
+
* SOFT ceiling on retained entries across every addon bucket. `null` (the
|
|
89
|
+
* default) means the per-addon rings are the only bound — the historical
|
|
90
|
+
* behaviour, unchanged unless you set this.
|
|
91
|
+
*
|
|
92
|
+
* Set it when `perAddonLogBufferSize × addons` is more than the box can spare:
|
|
93
|
+
* 70 addons × 5000 is 350k retained entries, which is a lot on a mini PC.
|
|
94
|
+
*
|
|
95
|
+
* Soft, and deliberately so: it is met by discarding only entries at or below
|
|
96
|
+
* `logBufferPruneLevel`. If pruning every prunable entry still leaves the total
|
|
97
|
+
* above this number, the buffer stays above it. A cap that could evict an
|
|
98
|
+
* `error` would trade the lines that explain an incident for lines about frame
|
|
99
|
+
* timings.
|
|
100
|
+
*/
|
|
101
|
+
maxTotalLogBufferSize?: number | null;
|
|
102
|
+
/**
|
|
103
|
+
* Highest severity the total-cap sweep may discard. Default `debug`.
|
|
104
|
+
*
|
|
105
|
+
* `debug` reclaims nearly all the space on any busy buffer while leaving
|
|
106
|
+
* `info`/`warn`/`error` untouched. Raise it to `info` only if debug alone is
|
|
107
|
+
* not enough; `warn` and `error` are then still safe. Setting it to `error`
|
|
108
|
+
* means "evict anything", which defeats the point.
|
|
109
|
+
*/
|
|
110
|
+
logBufferPruneLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
74
111
|
};
|
|
75
112
|
retention: {
|
|
76
113
|
detectionEventsDays: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LogEntry, LogFilter } from './log-ring-buffer.js';
|
|
2
|
+
import { PartitionedLogBufferOptions } from './partitioned-log-buffer.js';
|
|
2
3
|
import { IScopedLogger } from './scoped-logger.js';
|
|
3
4
|
export interface ILogDestination {
|
|
4
5
|
initialize(): Promise<void>;
|
|
@@ -11,10 +12,19 @@ export declare class LogManager {
|
|
|
11
12
|
private readonly destinations;
|
|
12
13
|
private readonly subscribers;
|
|
13
14
|
private deviceNameLookup;
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
15
|
+
/**
|
|
16
|
+
* `perAddonCapacity` bounds EACH addon's bucket, not the total — a chatty addon
|
|
17
|
+
* evicts only its own lines, so quiet addons keep their sparse history.
|
|
18
|
+
*
|
|
19
|
+
* `options.maxTotalEntries` adds a soft ceiling across all buckets, because the
|
|
20
|
+
* per-bucket bound scales with addon count. When it is exceeded, only entries at
|
|
21
|
+
* or below `options.pruneLevel` (default `debug`) are discarded — `warn` and
|
|
22
|
+
* `error` are never evicted to satisfy it. Both default to the previous
|
|
23
|
+
* behaviour: no total cap. See {@link PartitionedLogBuffer}.
|
|
24
|
+
*/
|
|
25
|
+
constructor(perAddonCapacity?: number, options?: PartitionedLogBufferOptions);
|
|
26
|
+
/** Entries currently retained across every bucket. */
|
|
27
|
+
bufferSize(): number;
|
|
18
28
|
/**
|
|
19
29
|
* Register a callback that resolves `deviceId → deviceName`. Called
|
|
20
30
|
* for every emitted entry that carries `tags.deviceId` but no
|
|
@@ -44,4 +44,19 @@ export declare class LogRingBuffer {
|
|
|
44
44
|
* gets removed.
|
|
45
45
|
*/
|
|
46
46
|
clear(filter?: LogFilter): number;
|
|
47
|
+
/** Entries currently retained. */
|
|
48
|
+
size(): number;
|
|
49
|
+
/**
|
|
50
|
+
* Drop up to `max` entries, OLDEST first, whose level is at or below
|
|
51
|
+
* `threshold`. Returns how many were removed.
|
|
52
|
+
*
|
|
53
|
+
* This is what lets a total-memory cap be enforced without losing the entries
|
|
54
|
+
* that matter: sweeping `debug` reclaims almost all of the space (debug is the
|
|
55
|
+
* overwhelming majority of any busy buffer) while `warn` and `error` are never
|
|
56
|
+
* touched. Losing the one error line that explains an incident, in order to keep
|
|
57
|
+
* a thousand debug lines about frame timings, would be the wrong trade.
|
|
58
|
+
*
|
|
59
|
+
* Oldest-first because recent context is what an operator is looking at.
|
|
60
|
+
*/
|
|
61
|
+
pruneOldestAtOrBelow(threshold: LogLevel, max: number): number;
|
|
47
62
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import { LogEntry, LogFilter } from '@camstack/types';
|
|
1
|
+
import { LogEntry, LogFilter, LogLevel } from '@camstack/types';
|
|
2
|
+
export interface PartitionedLogBufferOptions {
|
|
3
|
+
/** Hard ring size for EACH addon's bucket. */
|
|
4
|
+
readonly perAddonCapacity?: number;
|
|
5
|
+
/**
|
|
6
|
+
* Soft ceiling on entries across all buckets. `null` (the default) means the
|
|
7
|
+
* only bound is the per-addon rings.
|
|
8
|
+
*/
|
|
9
|
+
readonly maxTotalEntries?: number | null;
|
|
10
|
+
/** Highest severity the total-cap sweep may discard. Default `debug`. */
|
|
11
|
+
readonly pruneLevel?: LogLevel;
|
|
12
|
+
}
|
|
2
13
|
/**
|
|
3
14
|
* A log buffer partitioned into one fixed-capacity {@link LogRingBuffer} per
|
|
4
15
|
* `addonId`. A chatty addon (e.g. detection-pipeline) only ever evicts its OWN
|
|
@@ -6,16 +17,48 @@ import { LogEntry, LogFilter } from '@camstack/types';
|
|
|
6
17
|
* survive far longer than they would in a single shared FIFO ring.
|
|
7
18
|
*
|
|
8
19
|
* Drop-in for {@link LogRingBuffer} from {@link LogManager}'s perspective —
|
|
9
|
-
* exposes the same `push` / `getAll` / `query` / `clear` surface.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
20
|
+
* exposes the same `push` / `getAll` / `query` / `clear` surface.
|
|
21
|
+
*
|
|
22
|
+
* ## Two bounds, doing different jobs
|
|
23
|
+
*
|
|
24
|
+
* **`perAddonCapacity`** is a HARD bound: each bucket is a fixed-size ring, so
|
|
25
|
+
* total memory can never exceed `perAddonCapacity × buckets` whatever else
|
|
26
|
+
* happens. This is the safety net.
|
|
27
|
+
*
|
|
28
|
+
* **`maxTotalEntries`** is a SOFT target across all buckets, and it exists because
|
|
29
|
+
* the hard bound scales with addon count — 70 addons × 5000 is a lot of retained
|
|
30
|
+
* entries on a small box. When the total is exceeded, the sweep discards only
|
|
31
|
+
* entries at or below `pruneLevel` (default `debug`), oldest first, from the
|
|
32
|
+
* largest buckets first.
|
|
33
|
+
*
|
|
34
|
+
* It is deliberately soft. Meeting a total cap by discarding `warn` and `error`
|
|
35
|
+
* would trade the entries that explain an incident for entries about frame
|
|
36
|
+
* timings; if pruning every prunable entry still leaves the total above the cap,
|
|
37
|
+
* the buffer stays above it and the hard per-bucket bound is what holds. A cap
|
|
38
|
+
* that can evict an error is not a feature.
|
|
39
|
+
*
|
|
40
|
+
* Largest-bucket-first because the noisy addon is the one creating the pressure —
|
|
41
|
+
* the same principle that motivated partitioning in the first place.
|
|
12
42
|
*/
|
|
13
43
|
export declare class PartitionedLogBuffer {
|
|
14
|
-
private readonly perAddonCapacity;
|
|
15
44
|
private readonly buffers;
|
|
16
|
-
|
|
45
|
+
private readonly perAddonCapacity;
|
|
46
|
+
private readonly maxTotalEntries;
|
|
47
|
+
private readonly pruneLevel;
|
|
48
|
+
/** Running total, so `push` does not walk every bucket to decide. */
|
|
49
|
+
private totalEntries;
|
|
50
|
+
constructor(perAddonCapacity?: number, options?: PartitionedLogBufferOptions);
|
|
17
51
|
private bufferFor;
|
|
18
52
|
push(entry: LogEntry): void;
|
|
53
|
+
/**
|
|
54
|
+
* Bring the total down to `PRUNE_TARGET_RATIO × cap` by discarding prunable
|
|
55
|
+
* entries, largest bucket first. Stops early when nothing prunable is left —
|
|
56
|
+
* see the class docblock on why that is the correct outcome rather than a
|
|
57
|
+
* failure to enforce.
|
|
58
|
+
*/
|
|
59
|
+
private enforceTotalCap;
|
|
60
|
+
/** Entries retained across every bucket. */
|
|
61
|
+
size(): number;
|
|
19
62
|
/** Every retained entry across all buckets, newest-first (mirrors
|
|
20
63
|
* {@link LogRingBuffer.getAll}). Used to replay history to a destination. */
|
|
21
64
|
getAll(): LogEntry[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-yttC1aUI.js");
|
|
3
3
|
let _camstack_types_node = require("@camstack/types/node");
|
|
4
4
|
let node_http = require("node:http");
|
|
5
5
|
let node_fs = require("node:fs");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Y as readNodePin } from "./dist-eOaraBhT.mjs";
|
|
2
2
|
import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
import * as fs from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/system",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.14",
|
|
4
4
|
"description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -81,6 +81,18 @@
|
|
|
81
81
|
}
|
|
82
82
|
]
|
|
83
83
|
},
|
|
84
|
+
{
|
|
85
|
+
"id": "loki-logging",
|
|
86
|
+
"category": "system",
|
|
87
|
+
"name": "Loki Logging",
|
|
88
|
+
"description": "Opt-in log destination — batches this node's log entries and pushes them to a Grafana Loki instance via /loki/api/v1/push. Registered always, inert until enabled with a URL.",
|
|
89
|
+
"entry": "./dist/builtins/loki-logging/index.js",
|
|
90
|
+
"capabilities": [
|
|
91
|
+
{
|
|
92
|
+
"name": "log-destination"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
},
|
|
84
96
|
{
|
|
85
97
|
"id": "hub-forwarder",
|
|
86
98
|
"category": "system",
|