@lunora/observability 1.0.0-alpha.1 → 1.0.0-alpha.10
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/index.d.mts +195 -45
- package/dist/index.d.ts +195 -45
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-BB8kcFBe.mjs +56 -0
- package/dist/packem_shared/REQUEST_LOG_TABLE-BvpprPd_.mjs +1 -0
- package/dist/packem_shared/createDatabaseTally-DBs7wDeF.mjs +1 -0
- package/dist/packem_shared/createMetrics-BXNmqy0o.mjs +1 -0
- package/dist/packem_shared/readMetricHistory-CVcUgQEL.mjs +31 -0
- package/dist/packem_shared/readQueryInsights-DN07YcQy.mjs +32 -0
- package/dist/packem_shared/request-log-BwFic6VV.mjs +21 -0
- package/package.json +4 -4
- package/dist/packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-B1U7xWMo.mjs +0 -56
- package/dist/packem_shared/REQUEST_LOG_TABLE-Q_BYgAzY.mjs +0 -20
- package/dist/packem_shared/createDatabaseTally-BTqRpC0j.mjs +0 -1
- package/dist/packem_shared/createMetrics-fpVig63l.mjs +0 -1
- package/dist/packem_shared/log-fields-d5ouN1Pe.mjs +0 -1
- package/dist/packem_shared/readMetricHistory-DtnhufUq.mjs +0 -31
- package/dist/packem_shared/readQueryInsights-CwSKB0I1.mjs +0 -32
package/dist/index.d.mts
CHANGED
|
@@ -488,6 +488,15 @@ type HostTracingResolver = () => HostTracingLike | Promise<HostTracingLike | und
|
|
|
488
488
|
interface TracerDeps {
|
|
489
489
|
/** The trace this ctx's spans belong to. */
|
|
490
490
|
anchor: TraceAnchor;
|
|
491
|
+
/**
|
|
492
|
+
* Whether to record a span body's error message (and a `recordException`
|
|
493
|
+
* stacktrace) verbatim rather than redacted. Mirrors the request log's
|
|
494
|
+
* `captureRaw`: `true` in dev (`isDevEnvironment`), `false` in production —
|
|
495
|
+
* the span pipeline is the one sink third-party collectors (Datadog/Axiom
|
|
496
|
+
* via `otlpSink`) receive, so it must not ship raw PII/internals by default
|
|
497
|
+
* the way the request log and function-metrics sinks already don't.
|
|
498
|
+
*/
|
|
499
|
+
captureRaw?: boolean;
|
|
491
500
|
/** Function path the spans are attributed to. */
|
|
492
501
|
functionPath: string;
|
|
493
502
|
/**
|
|
@@ -544,11 +553,17 @@ interface SpanCollector {
|
|
|
544
553
|
* attributes become the canonical one-event-per-request summary. Sharing the
|
|
545
554
|
* implementation is what makes those two feel like the same API instead of two
|
|
546
555
|
* that happen to resemble each other.
|
|
556
|
+
*
|
|
557
|
+
* `captureRaw` (default `false`) gates `recordException`'s `exception.message`/
|
|
558
|
+
* `exception.stacktrace` the same way {@link createTracer} gates a span's own
|
|
559
|
+
* error message — a stack is file paths and internals by definition, the exact
|
|
560
|
+
* class `isInternalCode` redaction exists for, so it rides the same dev-only
|
|
561
|
+
* escape hatch rather than shipping to a third-party collector by default.
|
|
547
562
|
*/
|
|
548
563
|
declare const createSpanCollector: (ids: {
|
|
549
564
|
spanId: string;
|
|
550
565
|
traceId: string;
|
|
551
|
-
}) => SpanCollector;
|
|
566
|
+
}, captureRaw?: boolean) => SpanCollector;
|
|
552
567
|
/**
|
|
553
568
|
* Build the `ctx.trace` span factory for one dispatched function.
|
|
554
569
|
*
|
|
@@ -673,6 +688,14 @@ declare const createMetrics: (deps: MetricsDeps) => ContextMetrics;
|
|
|
673
688
|
*/
|
|
674
689
|
declare const dispatchRootSpan: (input: {
|
|
675
690
|
anchor: TraceAnchor;
|
|
691
|
+
/**
|
|
692
|
+
* Whether to record the failure message verbatim rather than redacted —
|
|
693
|
+
* the same dev-only escape hatch as {@link TracerDeps.captureRaw}. This
|
|
694
|
+
* synthetic root span carries the SAME error message the request log and
|
|
695
|
+
* function-metrics sinks already redact by default, so it must not be the
|
|
696
|
+
* one durable copy that ships it raw to a third-party collector.
|
|
697
|
+
*/
|
|
698
|
+
captureRaw?: boolean;
|
|
676
699
|
/**
|
|
677
700
|
* What the handler attached to the dispatch through `ctx.span` — the **wide
|
|
678
701
|
* event**. These are the attributes that would otherwise have been scattered
|
|
@@ -715,6 +738,14 @@ type DatabaseInstrumentation = "off" | "spans" | "summary";
|
|
|
715
738
|
interface DatabaseTelemetryDeps {
|
|
716
739
|
/** The trace produced spans belong to (`"spans"` mode only). */
|
|
717
740
|
anchor: TraceAnchor;
|
|
741
|
+
/**
|
|
742
|
+
* Whether to record a failed call's error message verbatim rather than
|
|
743
|
+
* redacted (`"spans"` mode only) — the same dev-only escape hatch as
|
|
744
|
+
* `TracerDeps.captureRaw`. A constraint-error message quotes the
|
|
745
|
+
* conflicting row, so this CLIENT span gets the same default-redacted
|
|
746
|
+
* posture as the request log and function-metrics sinks.
|
|
747
|
+
*/
|
|
748
|
+
captureRaw?: boolean;
|
|
718
749
|
/** Function path spans and attributes are attributed to. */
|
|
719
750
|
functionPath: string;
|
|
720
751
|
/** Detail level; see {@link DatabaseInstrumentation}. */
|
|
@@ -786,13 +817,23 @@ declare const FUNCTION_METRICS_BUCKET_RETENTION = 1440;
|
|
|
786
817
|
/**
|
|
787
818
|
* Maximum distinct function `path`s tracked in the accumulator table. Mirrors
|
|
788
819
|
* `query-metrics.ts`'s `QUERY_METRICS_MAX_STATEMENTS` cap (and exists for the
|
|
789
|
-
* same reason): the
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
*
|
|
820
|
+
* same reason): the real bound is the app's own registered-function set plus
|
|
821
|
+
* deploy churn (a rename/removal leaves its old path's row in place, still
|
|
822
|
+
* counted against the cap, until an operator's own retention/cleanup
|
|
823
|
+
* process — there is none built in today) — a few thousand registered
|
|
824
|
+
* functions is already far beyond any real app. `shard-do.ts`'s dispatch
|
|
825
|
+
* handler explicitly does NOT record per-function metrics for an
|
|
826
|
+
* unregistered/`FUNCTION_NOT_FOUND` dispatch (see the guard next to its
|
|
827
|
+
* `FUNCTION_NOT_FOUND` check), so a caller cannot mint arbitrary `path`s here
|
|
828
|
+
* the way a raw caller-supplied SQL shape can in `query-metrics.ts`. Without a
|
|
829
|
+
* cap, deploy churn across the app's lifetime would still grow
|
|
830
|
+
* `__lunora_metrics` (and its bucket/scan satellites) without bound,
|
|
831
|
+
* eventually filling the shard's SQLite store shared with the app's real
|
|
832
|
+
* data. At the cap, a brand-new path is refused — protecting the incumbent
|
|
833
|
+
* leaderboard from a flood of one-off paths is the point, so admission is
|
|
834
|
+
* refused rather than evicting an existing path to make room; already-tracked
|
|
835
|
+
* paths keep accumulating past the cap. `readFunctionMetricsTotals`'s
|
|
836
|
+
* `capped` is the read-side signal for this.
|
|
796
837
|
*/
|
|
797
838
|
declare const FUNCTION_METRICS_MAX_PATHS = 5e3;
|
|
798
839
|
/**
|
|
@@ -814,6 +855,22 @@ interface FunctionMetricBucket {
|
|
|
814
855
|
/** Subset of `calls` that threw. */
|
|
815
856
|
errors: number;
|
|
816
857
|
}
|
|
858
|
+
/** {@link readFunctionMetricBuckets} result: the time-series window plus whether the read limit cut it short. */
|
|
859
|
+
interface FunctionMetricBucketsResult {
|
|
860
|
+
buckets: (FunctionMetricBucket & {
|
|
861
|
+
path: string;
|
|
862
|
+
})[];
|
|
863
|
+
/**
|
|
864
|
+
* True when more rows existed than {@link FUNCTION_METRICS_READ_LIMIT} could
|
|
865
|
+
* return, so `buckets` is a partial (newest) window rather than the app's
|
|
866
|
+
* full retained history. Mirrors `readQueryInsights`'s `capped` and
|
|
867
|
+
* `foldTraces`'s `total`: a silently truncated read looks identical to a
|
|
868
|
+
* complete one to a caller that doesn't check for it — the Metrics chart's
|
|
869
|
+
* window would appear to shrink as the app grows, with a wrong leftmost
|
|
870
|
+
* bar, and nothing would say why.
|
|
871
|
+
*/
|
|
872
|
+
truncated: boolean;
|
|
873
|
+
}
|
|
817
874
|
/** One declared index a dispatch exercised (used to narrow a read). */
|
|
818
875
|
interface IndexHit {
|
|
819
876
|
/** The declared index name. */
|
|
@@ -854,7 +911,7 @@ interface RecordFunctionMetricInput {
|
|
|
854
911
|
* dispatch used no declared index, keeping the hot path unchanged.
|
|
855
912
|
*/
|
|
856
913
|
indexHits?: ReadonlyArray<IndexHit>;
|
|
857
|
-
/** The
|
|
914
|
+
/** The `<file>:<function>` identifier. */
|
|
858
915
|
path: string;
|
|
859
916
|
/**
|
|
860
917
|
* Distinct tables this dispatch full-scanned (read with no index / point
|
|
@@ -879,7 +936,9 @@ interface RecordFunctionMetricInput {
|
|
|
879
936
|
* than baked into the `CREATE` so a shard whose `__lunora_metrics` predates the
|
|
880
937
|
* causal-attribution feature gains the column on the next call without a
|
|
881
938
|
* migration. SQLite has no `ADD COLUMN IF NOT EXISTS`, so the duplicate-column
|
|
882
|
-
* error from a re-run is swallowed.
|
|
939
|
+
* error from a re-run is swallowed. Both the `CREATE`s and the back-fill only
|
|
940
|
+
* run once per handle (see {@link ensuredHandles}) — a handle already marked
|
|
941
|
+
* ensured returns immediately.
|
|
883
942
|
*/
|
|
884
943
|
declare const ensureFunctionMetricsTables: (sql: SqlExec) => void;
|
|
885
944
|
/**
|
|
@@ -934,18 +993,21 @@ declare const readFunctionMetrics: (sql: SqlExec) => FunctionCallStat[];
|
|
|
934
993
|
/**
|
|
935
994
|
* Read the coarse time-series buckets for `path` (every path when omitted),
|
|
936
995
|
* oldest-bucket first so a chart can plot them left-to-right. Creates the table
|
|
937
|
-
* first so reads on a never-called shard return `[]`.
|
|
996
|
+
* first so reads on a never-called shard return `{ buckets: [], truncated: false }`.
|
|
938
997
|
*/
|
|
939
|
-
declare const readFunctionMetricBuckets: (sql: SqlExec, path?: string) =>
|
|
940
|
-
path: string;
|
|
941
|
-
})[];
|
|
998
|
+
declare const readFunctionMetricBuckets: (sql: SqlExec, path?: string) => FunctionMetricBucketsResult;
|
|
942
999
|
/**
|
|
943
1000
|
* Aggregate the persisted accumulators into the lifetime totals the metrics
|
|
944
|
-
* health snapshot reports: total calls (`requests`), total `errors
|
|
945
|
-
*
|
|
946
|
-
*
|
|
1001
|
+
* health snapshot reports: total calls (`requests`), total `errors`. Returns
|
|
1002
|
+
* zeroes on a never-called shard.
|
|
1003
|
+
*
|
|
1004
|
+
* `capped` is true when the distinct-path cap ({@link FUNCTION_METRICS_MAX_PATHS})
|
|
1005
|
+
* has been reached — the write-side signal that a brand-new function path is
|
|
1006
|
+
* currently being refused (see `admitPath`), mirroring `readQueryInsights`'s
|
|
1007
|
+
* `capped` for query-metrics and `readMetricHistory`'s for metric-history.
|
|
947
1008
|
*/
|
|
948
1009
|
declare const readFunctionMetricsTotals: (sql: SqlExec) => {
|
|
1010
|
+
capped: boolean;
|
|
949
1011
|
errors: number;
|
|
950
1012
|
requests: number;
|
|
951
1013
|
};
|
|
@@ -978,7 +1040,7 @@ interface AiRunBinding {
|
|
|
978
1040
|
}
|
|
979
1041
|
/** Parsed `__lunora_admin__:explainIssue` payload: the folded Issue's identifying facts, plus an optional model override. */
|
|
980
1042
|
interface ExplainIssueArgs {
|
|
981
|
-
/** The Issue's culprit (
|
|
1043
|
+
/** The Issue's culprit (`<file>:<function>` or `container:<name>`), for grounding context. */
|
|
982
1044
|
culprit?: string;
|
|
983
1045
|
/** Per-request model-id override; falls back to the caller's `defaultModel`, then {@link DEFAULT_EXPLAIN_ISSUE_MODEL}. */
|
|
984
1046
|
model?: string;
|
|
@@ -1127,7 +1189,7 @@ type LogLevel = ContextLogLevel;
|
|
|
1127
1189
|
*/
|
|
1128
1190
|
interface LogEntry {
|
|
1129
1191
|
exitCode?: number;
|
|
1130
|
-
/** Structured fields from a `ctx.log
|
|
1192
|
+
/** Structured fields from a `ctx.log.<level>(message, fields)` / `ctx.log.with(fields)` call, when present. */
|
|
1131
1193
|
fields?: Record<string, unknown>;
|
|
1132
1194
|
functionPath?: string;
|
|
1133
1195
|
instance?: string;
|
|
@@ -1261,6 +1323,17 @@ interface MetricHistorySeries {
|
|
|
1261
1323
|
}
|
|
1262
1324
|
/** {@link readMetricHistory} result: every tracked series with its buckets. */
|
|
1263
1325
|
interface MetricHistoryResult {
|
|
1326
|
+
/**
|
|
1327
|
+
* True when the distinct-series cap has been reached — a **write-side**
|
|
1328
|
+
* signal ("this shard can no longer admit a brand-new series", see
|
|
1329
|
+
* `admitNewSeries`), not a read-side truncation flag. It is computed over
|
|
1330
|
+
* the whole table regardless of `options.sinceMs`/the row-count read
|
|
1331
|
+
* limit, so it can be `true` even when every series `readMetricHistory`
|
|
1332
|
+
* actually returned fits comfortably: the caller should read it as "a
|
|
1333
|
+
* flood of new series would currently be refused", the same thing
|
|
1334
|
+
* `readQueryInsights`'s `capped` already signals for query-metrics.
|
|
1335
|
+
*/
|
|
1336
|
+
capped: boolean;
|
|
1264
1337
|
series: MetricHistorySeries[];
|
|
1265
1338
|
}
|
|
1266
1339
|
/**
|
|
@@ -1269,7 +1342,7 @@ interface MetricHistoryResult {
|
|
|
1269
1342
|
* omitted field keeps the historical behaviour.
|
|
1270
1343
|
*/
|
|
1271
1344
|
interface MetricHistoryOptions {
|
|
1272
|
-
/** Distinct series tracked before
|
|
1345
|
+
/** Distinct series tracked before the least-recently-updated one is evicted to admit a new one (default {@link METRIC_HISTORY_MAX_SERIES}). */
|
|
1273
1346
|
maxSeries?: number;
|
|
1274
1347
|
/** Minute-buckets kept per series before older rows are trimmed (default {@link METRIC_HISTORY_BUCKET_RETENTION}). */
|
|
1275
1348
|
retentionBuckets?: number;
|
|
@@ -1306,9 +1379,12 @@ declare const recordMetricHistory: (sql: SqlExec, event: MetricEvent, exemplarTr
|
|
|
1306
1379
|
* trend line reads oldest→newest.
|
|
1307
1380
|
*
|
|
1308
1381
|
* `options.sinceMs`, when set, returns only buckets at or after this epoch-ms —
|
|
1309
|
-
* the studio's time-window selector.
|
|
1382
|
+
* the studio's time-window selector. `options.maxSeries`, mirroring the write
|
|
1383
|
+
* side's tunable, is only used to compute `capped` — it does not affect which
|
|
1384
|
+
* rows are read.
|
|
1310
1385
|
*/
|
|
1311
1386
|
declare const readMetricHistory: (sql: SqlExec, options?: {
|
|
1387
|
+
maxSeries?: number;
|
|
1312
1388
|
sinceMs?: number;
|
|
1313
1389
|
}) => MetricHistoryResult;
|
|
1314
1390
|
/** One row of the `__lunora_metrics_queries` table, as returned by `readQueryMetrics`. */
|
|
@@ -1369,14 +1445,23 @@ interface QueryInsightsResult {
|
|
|
1369
1445
|
*/
|
|
1370
1446
|
declare const readQueryInsights: (sql: SqlExec, rangeMs: number, now?: number) => QueryInsightsResult;
|
|
1371
1447
|
/**
|
|
1372
|
-
* Record one statement
|
|
1448
|
+
* Record one statement's activity. Creates the table on first call. Silently
|
|
1373
1449
|
* skips recording when the normalised statement is empty (shouldn't happen
|
|
1374
1450
|
* in practice) or when the table is already at the
|
|
1375
1451
|
* {@link QUERY_METRICS_MAX_STATEMENTS} cap and the statement is not yet
|
|
1376
|
-
* tracked.
|
|
1377
|
-
*
|
|
1452
|
+
* tracked. See `admitStatement` for how the cap check avoids an unconditional
|
|
1453
|
+
* `COUNT(*)` on every execution.
|
|
1454
|
+
*
|
|
1455
|
+
* `execCount` (default 1) lets a caller fold several executions of the SAME
|
|
1456
|
+
* statement into one call — `shard-do.ts` does this per dispatch so a
|
|
1457
|
+
* query-in-a-loop handler pays one upsert here instead of one per raw
|
|
1458
|
+
* execution. `durationMs`/`rowsRead`/`rowsWritten` are then the SUM across
|
|
1459
|
+
* `execCount` executions, exactly as `exec_count`/`total_duration_ms` already
|
|
1460
|
+
* accumulate sums across separate calls — folding before calling is
|
|
1461
|
+
* indistinguishable, from this table's point of view, from `execCount`
|
|
1462
|
+
* separate calls with the same totals.
|
|
1378
1463
|
*/
|
|
1379
|
-
declare const recordQueryMetric: (sql: SqlExec, rawSql: string, durationMs: number, rowsRead: number, rowsWritten: number, now?: number) => void;
|
|
1464
|
+
declare const recordQueryMetric: (sql: SqlExec, rawSql: string, durationMs: number, rowsRead: number, rowsWritten: number, now?: number, execCount?: number) => void;
|
|
1380
1465
|
/**
|
|
1381
1466
|
* Read all tracked statement aggregates, ordered by `total_duration_ms DESC`
|
|
1382
1467
|
* (the leaderboard's default). Creates the table first so a read on a
|
|
@@ -1393,9 +1478,9 @@ interface RequestLogEntry {
|
|
|
1393
1478
|
cacheHit?: boolean;
|
|
1394
1479
|
/** Handler wall-clock duration in milliseconds (before the subscription write-flush, matching the per-function metrics). */
|
|
1395
1480
|
durationMs: number;
|
|
1396
|
-
/** Error message when `outcome === "error"
|
|
1481
|
+
/** Error message when `outcome === "error"`, redacted like args/identity; absent on success. */
|
|
1397
1482
|
errorMessage?: string;
|
|
1398
|
-
/** The
|
|
1483
|
+
/** The `<file>:<function>` identifier dispatched, e.g. `messages:list`. */
|
|
1399
1484
|
functionPath: string;
|
|
1400
1485
|
/** Identity-claim envelope forwarded by the runtime, JSON-decoded; leaf values are redacted (the claims are PII), so only the shape survives. Absent for anonymous requests. Correlate on `userId` instead. */
|
|
1401
1486
|
identity?: Record<string, unknown>;
|
|
@@ -1443,7 +1528,7 @@ interface RequestLogWriteOptions {
|
|
|
1443
1528
|
}
|
|
1444
1529
|
/** Filters for {@link readRequestLog}, all AND-combined; every value is a bound SQL parameter, so nothing here injects SQL. */
|
|
1445
1530
|
interface ReadRequestLogOptions {
|
|
1446
|
-
/** Functions whose path begins with this prefix (a
|
|
1531
|
+
/** Functions whose path begins with this prefix (a `<file>:` or `<file>:<fn>` correlation). */
|
|
1447
1532
|
functionPathPrefix?: string;
|
|
1448
1533
|
/** Upper bound on returned rows, clamped to [1, 10000]. */
|
|
1449
1534
|
limit?: number;
|
|
@@ -1473,15 +1558,20 @@ interface ErrorIssue {
|
|
|
1473
1558
|
assignee?: string;
|
|
1474
1559
|
/** Number of `error` rows folded into this Issue within the scanned window. */
|
|
1475
1560
|
count: number;
|
|
1476
|
-
/** The
|
|
1561
|
+
/** The `<file>:<function>` (or `container:<name>`) the errors came from. */
|
|
1477
1562
|
culprit: string;
|
|
1478
1563
|
/** Wall-clock millis of the oldest folded row. */
|
|
1479
1564
|
firstSeen: number;
|
|
1480
|
-
/**
|
|
1565
|
+
/**
|
|
1566
|
+
* Stable 16-char grouping hash over `functionPath :: bucket(message)`,
|
|
1567
|
+
* computed from the RAW (pre-redaction) message at write time and stored on
|
|
1568
|
+
* the row — see {@link appendRequestLogEntry} — so redacting `sampleMessage`
|
|
1569
|
+
* below can't change the grouping.
|
|
1570
|
+
*/
|
|
1481
1571
|
hash: string;
|
|
1482
1572
|
/** Wall-clock millis of the newest folded row. */
|
|
1483
1573
|
lastSeen: number;
|
|
1484
|
-
/** A representative
|
|
1574
|
+
/** A representative error message (redacted, like the durable row) — taken from the most recent folded row. */
|
|
1485
1575
|
sampleMessage: string;
|
|
1486
1576
|
/** Developer-tagged severity from the persisted triage state; absent when untriaged. */
|
|
1487
1577
|
severity?: IssueSeverity;
|
|
@@ -1507,7 +1597,7 @@ interface IssuesResult {
|
|
|
1507
1597
|
}
|
|
1508
1598
|
/** Filters for {@link readErrorIssues}; forwarded to {@link readRequestLog} with `outcome` forced to `error`. */
|
|
1509
1599
|
interface ReadIssuesOptions {
|
|
1510
|
-
/** Functions whose path begins with this prefix (a
|
|
1600
|
+
/** Functions whose path begins with this prefix (a `<file>:` or `<file>:<fn>` correlation). */
|
|
1511
1601
|
functionPathPrefix?: string;
|
|
1512
1602
|
/** Upper bound on error rows scanned before grouping, clamped to [1, 10000]. */
|
|
1513
1603
|
limit?: number;
|
|
@@ -1518,21 +1608,73 @@ interface ReadIssuesOptions {
|
|
|
1518
1608
|
/** Exact acting-userId match. */
|
|
1519
1609
|
userId?: string;
|
|
1520
1610
|
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Redact the secrets / PII out of a value before it reaches the durable log or a
|
|
1613
|
+
* Logpush event, via `@visulima/redact`'s `standardRules`. Unlike a blunt
|
|
1614
|
+
* type-tag stamp this masks sensitive values by PATTERN (not just by key name)
|
|
1615
|
+
* while leaving benign values readable, so the studio's args/identity columns
|
|
1616
|
+
* stay useful. `null` / `undefined` pass through unchanged.
|
|
1617
|
+
*
|
|
1618
|
+
* What `standardRules` actually catches differs by shape, verified against its
|
|
1619
|
+
* real behavior rather than assumed from its name: on a KEYED object (`args`,
|
|
1620
|
+
* `identity`) it also matches by key name, so `{ password: "hunter2" }` and
|
|
1621
|
+
* `{ token: "…" }` ARE masked regardless of the value's shape. On a PLAIN
|
|
1622
|
+
* STRING — which is what `errorMessage`/log `fields`-as-rendered-text are —
|
|
1623
|
+
* only pattern-shaped matches apply: emails, long digit runs / structured
|
|
1624
|
+
* numeric IDs (credit-card, phone, SSN, AWS-access-key-style), and an explicit
|
|
1625
|
+
* `Bearer <token>` / `token=…`-shaped substring. A free-text `password=hunter2`
|
|
1626
|
+
* or a bare provider API key embedded in prose (e.g. `sk-live-…`) is NOT
|
|
1627
|
+
* caught on a plain string — there is no key to match against, and neither is
|
|
1628
|
+
* a recognized value pattern. So this is a PII-pattern net for rendered text,
|
|
1629
|
+
* not a general secrets scrubber; a handler that echoes a raw credential into
|
|
1630
|
+
* an error message or a log string can still leak it through here. Works on a
|
|
1631
|
+
* plain string too (`redact` traverses whatever value it's handed), which is
|
|
1632
|
+
* how {@link appendRequestLogEntry} and {@link emitRequestLogEvent} reuse this
|
|
1633
|
+
* for `errorMessage` — a validation error echoes the offending value, a
|
|
1634
|
+
* constraint error quotes the conflicting row, so the error message is at
|
|
1635
|
+
* least as PII-dense as args and gets the same treatment (with the free-text
|
|
1636
|
+
* caveat above).
|
|
1637
|
+
*
|
|
1638
|
+
* `captureRaw` is the development escape hatch: in a dev environment the dispatch
|
|
1639
|
+
* site (`isDevEnvironment`) passes `true` to skip redaction so a developer can
|
|
1640
|
+
* see real arg/identity/error values; production always redacts. The dev
|
|
1641
|
+
* decision is made at the call site from the deployment env, never inferred
|
|
1642
|
+
* here — so a real deploy that omits the env var stays redacted.
|
|
1643
|
+
*/
|
|
1644
|
+
declare const redactArgs: (value: unknown, captureRaw?: boolean) => unknown;
|
|
1521
1645
|
/**
|
|
1522
1646
|
* Create the `__lunora_reqlog__` table. `seq` is an `AUTOINCREMENT` primary
|
|
1523
1647
|
* key, giving each shard a monotonic cursor the Logs tab pages through; the
|
|
1524
1648
|
* `args`/`identity`/`tables_read`/`tables_written` columns hold JSON and are
|
|
1525
1649
|
* `NULL`/empty when none was recorded. Idempotent, so read and write paths can
|
|
1526
1650
|
* call it defensively.
|
|
1651
|
+
*
|
|
1652
|
+
* `error_fingerprint` is the {@link fingerprintError} grouping hash captured
|
|
1653
|
+
* from the RAW `error_message` at write time, before {@link appendRequestLogEntry}
|
|
1654
|
+
* redacts it — see that function's docstring. It is added via a guarded
|
|
1655
|
+
* `ALTER TABLE` rather than baked into the `CREATE`, mirroring
|
|
1656
|
+
* `function-metrics.ts`'s `ensureFunctionMetricsTables`, so a shard whose
|
|
1657
|
+
* `__lunora_reqlog__` predates this column gains it on the next call without a
|
|
1658
|
+
* migration. SQLite has no `ADD COLUMN IF NOT EXISTS`, so the duplicate-column
|
|
1659
|
+
* error from a re-run (or the freshly-created schema above) is swallowed.
|
|
1527
1660
|
*/
|
|
1528
1661
|
declare const ensureRequestLogTable: (sql: SqlExec) => void;
|
|
1529
1662
|
/**
|
|
1530
1663
|
* Append one dispatch to the request log, then trim the log back to the most
|
|
1531
1664
|
* recent `retention` rows (default {@link REQUEST_LOG_RETENTION}). Creates the
|
|
1532
|
-
* table first so callers needn't. Args/identity are redacted here
|
|
1533
|
-
* never reaches the durable table — callers pass the unredacted
|
|
1534
|
-
* this, unless `captureRaw` (dev only) is set. `retention` is
|
|
1535
|
-
* `LUNORA_REQUEST_LOG_RETENTION` override, threaded in by the
|
|
1665
|
+
* table first so callers needn't. Args/identity/error message are redacted here
|
|
1666
|
+
* so a raw value never reaches the durable table — callers pass the unredacted
|
|
1667
|
+
* entry and rely on this, unless `captureRaw` (dev only) is set. `retention` is
|
|
1668
|
+
* the operator's `LUNORA_REQUEST_LOG_RETENTION` override, threaded in by the
|
|
1669
|
+
* dispatch site.
|
|
1670
|
+
*
|
|
1671
|
+
* The error-grouping fingerprint is computed from `entry.errorMessage` BEFORE
|
|
1672
|
+
* it's redacted below, and the resulting hash is persisted in
|
|
1673
|
+
* `error_fingerprint`. `readErrorIssues` groups off that stored hash instead of
|
|
1674
|
+
* recomputing `fingerprintError` from the (redacted) `error_message` column, so
|
|
1675
|
+
* masking a PII-bearing value — e.g. two different `<n>`-bucketed IDs that
|
|
1676
|
+
* redact to two different tag lengths (`<DL>` vs `<BANKACC>`) — can't split an
|
|
1677
|
+
* existing Issue or change its identity.
|
|
1536
1678
|
*/
|
|
1537
1679
|
declare const appendRequestLogEntry: (sql: SqlExec, entry: AppendRequestLogEntry, options?: RequestLogWriteOptions) => void;
|
|
1538
1680
|
/**
|
|
@@ -1541,8 +1683,8 @@ declare const appendRequestLogEntry: (sql: SqlExec, entry: AppendRequestLogEntry
|
|
|
1541
1683
|
* NOT reimplement a transport: it produces a richer, lunora-attributed event and
|
|
1542
1684
|
* lets CF's existing trace-log pipe ship it. The event mirrors the durable
|
|
1543
1685
|
* `__lunora_reqlog__` row (function path, shard, user, outcome, duration, tables
|
|
1544
|
-
* read/written, cache hit), with `args` AND `
|
|
1545
|
-
* durable write so no raw PII/secret reaches the log pipeline.
|
|
1686
|
+
* read/written, cache hit), with `args`, `identity`, AND `error` redacted
|
|
1687
|
+
* exactly like the durable write so no raw PII/secret reaches the log pipeline.
|
|
1546
1688
|
*
|
|
1547
1689
|
* An `error` outcome goes to `console.error` (surfacing at error level in the
|
|
1548
1690
|
* trace so a SIEM can alert on it); everything else to `console.log`. The
|
|
@@ -1560,7 +1702,7 @@ declare const emitRequestLogEvent: (entry: AppendRequestLogEntry, options?: Requ
|
|
|
1560
1702
|
*/
|
|
1561
1703
|
type LogEventInput = LogEvent;
|
|
1562
1704
|
/**
|
|
1563
|
-
* Split a `ctx.log
|
|
1705
|
+
* Split a `ctx.log.<level>(...)` call's raw arguments into a display `message`
|
|
1564
1706
|
* and optional structured `fields`. The structured form — a message string plus
|
|
1565
1707
|
* a plain-object fields bag — is matched only for exactly `(string, object)`;
|
|
1566
1708
|
* every other shape is console-style and rendered whole (so existing
|
|
@@ -1591,11 +1733,19 @@ declare const parseLogArgs: (args: unknown[], boundFields?: LogFields) => {
|
|
|
1591
1733
|
*
|
|
1592
1734
|
* Structured `fields` (plus `traceId`/`spanId` for correlation) ARE emitted here
|
|
1593
1735
|
* — they are intentional metadata a log pipeline filters on, unlike raw `args`.
|
|
1594
|
-
*
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1597
|
-
|
|
1598
|
-
|
|
1736
|
+
* Unlike `args`, `fields` IS redacted before it rides this console line — a
|
|
1737
|
+
* developer can attach anything to a fields bag (`ctx.log.info("charged",
|
|
1738
|
+
* { email, cardLast4 })`), and this is the one line that's told to a SIEM as
|
|
1739
|
+
* trustworthy, exactly like the request-log `args`/`identity`/`error` columns.
|
|
1740
|
+
* `options.captureRaw` (dev only) skips it, mirroring every other redaction
|
|
1741
|
+
* point in this module; the sole current caller (`ShardDO.recordUserLog`)
|
|
1742
|
+
* doesn't yet thread a dev flag through, so `fields` redacts unconditionally
|
|
1743
|
+
* there today — a conservative default, never a correctness gap. A field value
|
|
1744
|
+
* that can't be serialised (a circular object) would make `JSON.stringify`
|
|
1745
|
+
* throw and drop the whole line, so serialisation falls back to a fields-free
|
|
1746
|
+
* line rather than losing the event.
|
|
1747
|
+
*/
|
|
1748
|
+
declare const emitLogEvent: (input: LogEventInput, options?: RequestLogWriteOptions) => void;
|
|
1599
1749
|
/**
|
|
1600
1750
|
* Read request-log entries newest-first, AND-combining the supplied filters
|
|
1601
1751
|
* (function-path prefix, exact userId/shardKey/outcome, and a table-touched
|
|
@@ -1815,4 +1965,4 @@ declare const resolveTraceAnchor: (traceparent: string | undefined) => {
|
|
|
1815
1965
|
sampled: boolean;
|
|
1816
1966
|
traceId: string;
|
|
1817
1967
|
};
|
|
1818
|
-
export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, type AiRunBinding, type AppendRequestLogEntry, type AuthMetrics, type AuthMetricsBucket, type ContextFetch, type ContextLogLevel, type ContextMetrics, type ContextTracer, DEFAULT_EXPLAIN_ISSUE_MODEL, type DatabaseInstrumentation, type DatabaseTally, type ExplainIssueArgs, type ExplainIssueDegradedReason, type ExplainIssueGrounding, type ExplainIssueResult, FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_MAX_PATHS, FUNCTION_METRICS_READ_LIMIT, FUNCTION_METRICS_SCANS_TABLE, FUNCTION_METRICS_TABLE, type FunctionMetricBucket, type FunctionMetricIndexHit, type HostTracingLike, ISSUE_SEVERITIES, ISSUE_STATE_TABLE, ISSUE_STATUSES, type IndexHit, type IssueSeverity, type IssueState, type IssueStatePatch, type IssueStatus, type IssuesResult, LogBuffer, type LogEntry, type LogEventInput, type LogLevel, MIN_ADMIN_TOKEN_LENGTH, MIN_AUTH_SECRET_LENGTH, MetricBuffer, type MetricHistoryOptions, type MetricHistoryPoint, type MetricHistorySeries, type MetricSeries, type MetricsDeps, type QueryStatEntry, REQUEST_LOG_TABLE, type RecordAuthEventInput, type RecordFunctionMetricInput, type RequestLogResult, type RequestLogWriteOptions, type SecurityAuditResult, type SecurityFinding, type SecurityFindingKind, type SecurityFindingLevel, SpanBuffer, type SpanCollection, type SpanCollector, type SpanHandle, type TraceAnchor, type TraceSpan, type TraceSummary, type TracerDeps, appendRequestLogEntry, buildSecurityAudit, createDatabaseTally, createMetrics, createSpanCollector, createTracedFetch, createTracer, dispatchRootSpan, emitLogEvent, emitRequestLogEvent, ensureAuthMetricsTables, ensureFunctionMetricsTables, ensureRequestLogTable, explainIssue, findDanglingReferences, foldTraces, formatTally, instrumentDatabase, mergeScanAttribution, parseExplainIssueArgs, parseLogArgs, readAuthMetrics, readErrorIssues, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetricScans, readFunctionMetrics, readFunctionMetricsTotals, readMetricHistory, readQueryInsights, readQueryMetrics, readRequestLog, recordAuthEvent, recordFunctionMetric, recordMetricHistory, recordQueryMetric, resolveTraceAnchor, upsertIssueState };
|
|
1968
|
+
export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, type AiRunBinding, type AppendRequestLogEntry, type AuthMetrics, type AuthMetricsBucket, type ContextFetch, type ContextLogLevel, type ContextMetrics, type ContextTracer, DEFAULT_EXPLAIN_ISSUE_MODEL, type DanglingReference, type DanglingReferenceResult, type DatabaseInstrumentation, type DatabaseTally, type DatabaseTelemetryDeps, type ErrorIssue, type ExplainIssueArgs, type ExplainIssueDegradedReason, type ExplainIssueGrounding, type ExplainIssueResult, FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_MAX_PATHS, FUNCTION_METRICS_READ_LIMIT, FUNCTION_METRICS_SCANS_TABLE, FUNCTION_METRICS_TABLE, type FoldedTraces, type FunctionMetricBucket, type FunctionMetricBucketsResult, type FunctionMetricIndexHit, type HostSpanLike, type HostTracingLike, type HostTracingResolver, ISSUE_SEVERITIES, ISSUE_STATE_TABLE, ISSUE_STATUSES, type IndexHit, type IssueSeverity, type IssueState, type IssueStatePatch, type IssueStatus, type IssuesResult, LogBuffer, type LogEntry, type LogEventInput, type LogLevel, MIN_ADMIN_TOKEN_LENGTH, MIN_AUTH_SECRET_LENGTH, MetricBuffer, type MetricEvent, type MetricHistoryOptions, type MetricHistoryPoint, type MetricHistoryResult, type MetricHistorySeries, type MetricKind, type MetricSeries, type MetricsDeps, type QueryInsightBucket, type QueryInsightEntry, type QueryInsightsResult, type QueryStatEntry, REQUEST_LOG_TABLE, type ReadIssuesOptions, type ReadRequestLogOptions, type RecordAuthEventInput, type RecordFunctionMetricInput, type RequestLogEntry, type RequestLogResult, type RequestLogWriteOptions, type RequestOutcome, type SecurityAuditResult, type SecurityFinding, type SecurityFindingKind, type SecurityFindingLevel, SpanBuffer, type SpanCollection, type SpanCollector, type SpanEvent, type SpanEventPoint, type SpanHandle, type OtlpSpanKind as SpanKind, type SpanLink, type SpanOptions, type TraceAnchor, type TraceSpan, type TraceSummary, type TracedFetchDeps, type TracerDeps, appendRequestLogEntry, buildSecurityAudit, createDatabaseTally, createMetrics, createSpanCollector, createTracedFetch, createTracer, dispatchRootSpan, emitLogEvent, emitRequestLogEvent, ensureAuthMetricsTables, ensureFunctionMetricsTables, ensureRequestLogTable, explainIssue, findDanglingReferences, foldTraces, formatTally, instrumentDatabase, mergeScanAttribution, parseExplainIssueArgs, parseLogArgs, readAuthMetrics, readErrorIssues, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetricScans, readFunctionMetrics, readFunctionMetricsTotals, readMetricHistory, readQueryInsights, readQueryMetrics, readRequestLog, recordAuthEvent, recordFunctionMetric, recordMetricHistory, recordQueryMetric, redactArgs, resolveTraceAnchor, upsertIssueState };
|