@zintrust/trace 0.5.5 → 0.5.8
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/config.js +2 -0
- package/dist/dashboard/ui.js +4 -4
- package/dist/types.d.ts +1 -0
- package/dist/utils/requestFilter.d.ts +7 -2
- package/dist/utils/requestFilter.js +30 -4
- package/dist/watchers/AuthWatcher.js +4 -1
- package/dist/watchers/BatchWatcher.js +4 -1
- package/dist/watchers/CacheWatcher.js +4 -1
- package/dist/watchers/CommandWatcher.js +4 -1
- package/dist/watchers/DumpWatcher.js +4 -1
- package/dist/watchers/EventWatcher.js +4 -1
- package/dist/watchers/ExceptionWatcher.js +5 -2
- package/dist/watchers/GateWatcher.js +4 -1
- package/dist/watchers/HttpClientWatcher.js +4 -1
- package/dist/watchers/HttpWatcher.js +1 -1
- package/dist/watchers/JobWatcher.js +4 -1
- package/dist/watchers/LogWatcher.js +1 -1
- package/dist/watchers/MailWatcher.js +4 -1
- package/dist/watchers/MiddlewareWatcher.js +4 -1
- package/dist/watchers/ModelWatcher.js +4 -1
- package/dist/watchers/NotificationWatcher.js +4 -1
- package/dist/watchers/QueryWatcher.js +1 -1
- package/dist/watchers/RedisWatcher.js +4 -1
- package/dist/watchers/ScheduleWatcher.js +4 -1
- package/dist/watchers/ViewWatcher.js +4 -1
- package/package.json +2 -2
- package/src/config.ts +2 -0
- package/src/dashboard/ui.ts +4 -4
- package/src/types.ts +1 -0
- package/src/utils/requestFilter.ts +57 -11
- package/src/watchers/AuthWatcher.ts +4 -1
- package/src/watchers/BatchWatcher.ts +4 -1
- package/src/watchers/CacheWatcher.ts +4 -1
- package/src/watchers/CommandWatcher.ts +4 -1
- package/src/watchers/DumpWatcher.ts +4 -1
- package/src/watchers/EventWatcher.ts +4 -1
- package/src/watchers/ExceptionWatcher.ts +5 -2
- package/src/watchers/GateWatcher.ts +4 -1
- package/src/watchers/HttpClientWatcher.ts +4 -1
- package/src/watchers/HttpWatcher.ts +1 -1
- package/src/watchers/JobWatcher.ts +4 -1
- package/src/watchers/LogWatcher.ts +2 -1
- package/src/watchers/MailWatcher.ts +4 -1
- package/src/watchers/MiddlewareWatcher.ts +4 -1
- package/src/watchers/ModelWatcher.ts +4 -1
- package/src/watchers/NotificationWatcher.ts +4 -1
- package/src/watchers/QueryWatcher.ts +1 -1
- package/src/watchers/RedisWatcher.ts +4 -1
- package/src/watchers/ScheduleWatcher.ts +4 -1
- package/src/watchers/ViewWatcher.ts +4 -1
|
@@ -3,10 +3,11 @@ import { EntryType } from '../types.js';
|
|
|
3
3
|
import { RequestFilter } from '../utils/requestFilter.js';
|
|
4
4
|
let _storage = null;
|
|
5
5
|
let _ignoreRoutes = [];
|
|
6
|
+
let _ignorePaths = [];
|
|
6
7
|
const emit = (template, duration) => {
|
|
7
8
|
if (!_storage)
|
|
8
9
|
return;
|
|
9
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes))
|
|
10
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths))
|
|
10
11
|
return;
|
|
11
12
|
const content = { template, duration, hostname: TraceContext.getHostname() };
|
|
12
13
|
_storage
|
|
@@ -28,9 +29,11 @@ export const ViewWatcher = Object.freeze({
|
|
|
28
29
|
return () => undefined;
|
|
29
30
|
_storage = storage;
|
|
30
31
|
_ignoreRoutes = config.ignoreRoutes;
|
|
32
|
+
_ignorePaths = config.ignorePaths;
|
|
31
33
|
return () => {
|
|
32
34
|
_storage = null;
|
|
33
35
|
_ignoreRoutes = [];
|
|
36
|
+
_ignorePaths = [];
|
|
34
37
|
};
|
|
35
38
|
},
|
|
36
39
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/trace",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
4
4
|
"description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=20.0.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@zintrust/core": "^0.5.
|
|
43
|
+
"@zintrust/core": "^0.5.5"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
package/src/config.ts
CHANGED
|
@@ -259,6 +259,7 @@ const DEFAULTS: ITraceConfig = Object.freeze({
|
|
|
259
259
|
observeConnection: undefined,
|
|
260
260
|
pruneAfterHours: 24,
|
|
261
261
|
ignoreRoutes: ['/trace', '/health', '/ping'],
|
|
262
|
+
ignorePaths: [],
|
|
262
263
|
slowQueryThreshold: 100,
|
|
263
264
|
captureCachePayloads: false,
|
|
264
265
|
captureQueryBindings: true,
|
|
@@ -350,6 +351,7 @@ export const TraceConfig = Object.freeze({
|
|
|
350
351
|
query: mergeStringLists(DEFAULTS.redaction.query, overrides.redaction?.query),
|
|
351
352
|
},
|
|
352
353
|
ignoreRoutes: overrides.ignoreRoutes ?? DEFAULTS.ignoreRoutes,
|
|
354
|
+
ignorePaths: overrides.ignorePaths ?? DEFAULTS.ignorePaths,
|
|
353
355
|
});
|
|
354
356
|
},
|
|
355
357
|
|
package/src/dashboard/ui.ts
CHANGED
|
@@ -76,13 +76,13 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
76
76
|
.main{padding:28px;min-width:0}.shell{max-width:1320px;margin:0 auto;display:grid;gap:18px}
|
|
77
77
|
.panel{border-radius:var(--radius);border:1px solid var(--line);background:var(--surface);box-shadow:var(--shadow);backdrop-filter:blur(16px)}.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:16px;margin-bottom:18px}.stat-card{padding:20px;position:relative;overflow:hidden}.stat-card::after{content:'';position:absolute;right:-18px;bottom:-26px;width:92px;height:92px;border-radius:28px;background:linear-gradient(135deg,rgba(56,189,248,.16),rgba(34,197,94,.08));transform:rotate(18deg)}.stat-label{font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:800;margin-bottom:12px}.stat-value{font-size:2.25rem;font-weight:800;line-height:1}.stat-meta{margin-top:10px;color:var(--muted);font-size:.9rem}.content-grid{display:grid;grid-template-columns:minmax(0,1.65fr) minmax(320px,.95fr);gap:18px}.side-stack{display:grid;gap:18px}
|
|
78
78
|
.section-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;padding:22px 24px 16px}.section-head h3{margin:0;font-size:1.04rem}.section-head p{margin:6px 0 0;color:var(--muted);font-size:.92rem}.toolbar{display:flex;flex-wrap:wrap;gap:10px;padding:0 24px 18px}.control,.toolbar input,.toolbar select{height:44px;border-radius:13px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);padding:0 14px;min-width:0}.toolbar input,.toolbar select{flex:1 1 180px}.toolbar input::placeholder{color:var(--muted)}.btn{height:44px;border:none;border-radius:13px;padding:0 16px;cursor:pointer;font-weight:800}.btn-primary{background:linear-gradient(135deg,var(--accent-strong),var(--accent));color:#fff}.btn-danger{background:rgba(239,68,68,.12);color:var(--danger);border:1px solid rgba(239,68,68,.18)}.btn-ghost{background:var(--surface-soft);color:var(--text);border:1px solid var(--line)}
|
|
79
|
-
.table-wrap{overflow:auto;padding:0 12px 12px}table{width:100%;border-collapse:separate;border-spacing:0;min-width:880px}th{padding:14px;color:var(--muted);font-size:.74rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;text-align:left;border-bottom:1px solid var(--line)}td{padding:15px 14px;border-bottom:1px solid var(--line);vertical-align:top}.row-button{cursor:pointer}.row-button:hover td{background:rgba(56,189,248,.05)}.summary{font-size:.93rem;font-weight:700;line-height:1.4;color:var(--text)}.summary-sub{margin-top:6px;color:var(--muted);font-size:.82rem;line-height:1.4}.mono{font-family:var(--mono)}.empty{padding:44px 24px;color:var(--muted);line-height:1.65;text-align:center}.pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:0 24px 24px;color:var(--muted);flex-wrap:wrap}.pagination-controls{display:flex;gap:8px}.pagination button{height:40px;min-width:92px;padding:0 14px;border-radius:12px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);cursor:pointer}.pagination button:disabled{opacity:.45;cursor:not-allowed}
|
|
79
|
+
.table-wrap{overflow:auto;padding:0 12px 12px}.table-wrap table{width:100%;border-collapse:separate;border-spacing:0;min-width:880px}th{padding:14px;color:var(--muted);font-size:.74rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;text-align:left;border-bottom:1px solid var(--line)}td{padding:15px 14px;border-bottom:1px solid var(--line);vertical-align:top}.row-button{cursor:pointer}.row-button:hover td{background:rgba(56,189,248,.05)}.summary{font-size:.93rem;font-weight:700;line-height:1.4;color:var(--text)}.summary-sub{margin-top:6px;color:var(--muted);font-size:.82rem;line-height:1.4}.mono{font-family:var(--mono)}.empty{padding:44px 24px;color:var(--muted);line-height:1.65;text-align:center}.pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:0 24px 24px;color:var(--muted);flex-wrap:wrap}.pagination-controls{display:flex;gap:8px}.pagination button{height:40px;min-width:92px;padding:0 14px;border-radius:12px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);cursor:pointer}.pagination button:disabled{opacity:.45;cursor:not-allowed}
|
|
80
80
|
.activity-list{list-style:none;margin:0;padding:0 24px 24px}.activity-item{padding:14px 0;border-top:1px solid var(--line)}.activity-item:first-child{border-top:none}.activity-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.activity-time{color:var(--muted);font-size:.85rem}.activity-summary{margin-top:8px;color:var(--text);line-height:1.48}.back-link{display:inline-flex;align-items:center;gap:8px;margin:0 0 14px;color:var(--accent);font-weight:800;cursor:pointer}.detail-card{padding:24px}.detail-meta{display:flex;flex-wrap:wrap;gap:10px;margin:14px 0 20px;color:var(--muted);font-size:.9rem;overflow-wrap:anywhere}.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}.detail-stack{display:grid;gap:16px;margin-top:18px}.detail-box{padding:16px;border-radius:16px;background:var(--surface-soft);border:1px solid var(--line)}.detail-box h4{margin:0 0 10px;font-size:.92rem}.detail-box dl{margin:0;display:grid;gap:8px}.detail-box dt{font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:800}.detail-box dd{margin:0;color:var(--text);line-height:1.45;overflow-wrap:anywhere}.trace-tabs{display:flex;gap:10px;flex-wrap:wrap;margin:20px 0 16px}.trace-tab{border:none;border-radius:12px;padding:10px 12px;background:transparent;color:var(--muted);cursor:pointer;box-shadow:inset 0 0 0 1px var(--line);font-weight:800}.trace-tab.active{background:rgba(56,189,248,.12);color:var(--text);box-shadow:inset 0 0 0 1px rgba(56,189,248,.28)}.trace-panel{display:grid;gap:14px}.trace-item{padding:18px;border-radius:16px;background:var(--surface-soft);border:1px solid var(--line)}.trace-item-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.trace-item-summary{margin-top:10px;display:grid;gap:10px}.trace-note{color:var(--muted);line-height:1.6}.trace-disclosure{padding:0;overflow:hidden}.trace-disclosure[open]{padding-bottom:18px}.trace-disclosure .trace-item-summary{margin-top:0}.trace-disclosure-body{display:grid;gap:12px;padding:0 18px}.trace-summary{list-style:none;cursor:pointer;padding:18px}.trace-summary::-webkit-details-marker{display:none}.trace-summary-main{display:grid;gap:10px;min-width:0;flex:1}.trace-summary-copy{display:grid;gap:6px;min-width:0}.trace-summary-copy .summary,.trace-summary-copy .summary-sub{display:block;overflow-wrap:anywhere}.trace-disclosure-body .summary-sub{overflow-wrap:anywhere}
|
|
81
81
|
.tag{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;background:rgba(56,189,248,.12);color:#bae6fd;font-size:.78rem;font-weight:800;margin:0 6px 6px 0;border:1px solid rgba(56,189,248,.18);text-decoration:none}button.tag{cursor:pointer}html[data-theme='light'] .tag{color:#075985}.tag.failed{background:rgba(239,68,68,.14);color:#fecaca;border-color:rgba(239,68,68,.2)}html[data-theme='light'] .tag.failed{color:#b91c1c}.tag.slow{background:rgba(245,158,11,.12);color:#fde68a;border-color:rgba(245,158,11,.18)}html[data-theme='light'] .tag.slow{color:#92400e}.type-pill{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;font-size:.74rem;font-weight:900;text-transform:uppercase;letter-spacing:.08em;border:1px solid transparent}.pill-request{background:rgba(56,189,248,.14);color:#93c5fd}.pill-request.method-get{background:rgba(34,197,94,.16);color:#bbf7d0}.pill-request.method-post{background:rgba(59,130,246,.16);color:#bfdbfe}.pill-request.method-other{background:rgba(245,158,11,.16);color:#fde68a}.pill-query{background:rgba(34,197,94,.12);color:#86efac}.pill-exception{background:rgba(239,68,68,.14);color:#fecaca}.pill-log{background:rgba(168,85,247,.14);color:#ddd6fe}.pill-job,.pill-batch{background:rgba(245,158,11,.14);color:#fde68a}.pill-cache{background:rgba(20,184,166,.12);color:#99f6e4}.pill-schedule,.pill-command{background:rgba(14,165,233,.14);color:#bae6fd}.pill-mail,.pill-notification{background:rgba(236,72,153,.14);color:#fbcfe8}.pill-auth{background:rgba(148,163,184,.16);color:#e2e8f0}.pill-event,.pill-model{background:rgba(74,222,128,.14);color:#bbf7d0}.pill-redis{background:rgba(239,68,68,.12);color:#fecaca}.pill-gate{background:rgba(99,102,241,.14);color:#c7d2fe}.pill-middleware{background:rgba(45,212,191,.12);color:#ccfbf1}.pill-dump,.pill-view{background:rgba(148,163,184,.14);color:#e2e8f0}.pill-client-request{background:rgba(59,130,246,.14);color:#bfdbfe}html[data-theme='light'] .pill-request{color:#1d4ed8}html[data-theme='light'] .pill-request.method-get{color:#166534}html[data-theme='light'] .pill-request.method-post{color:#1d4ed8}html[data-theme='light'] .pill-request.method-other{color:#92400e}html[data-theme='light'] .pill-query{color:#166534}html[data-theme='light'] .pill-exception{color:#b91c1c}html[data-theme='light'] .pill-log{color:#6d28d9}html[data-theme='light'] .pill-job,html[data-theme='light'] .pill-batch{color:#92400e}html[data-theme='light'] .pill-cache{color:#115e59}html[data-theme='light'] .pill-schedule,html[data-theme='light'] .pill-command{color:#0c4a6e}html[data-theme='light'] .pill-mail,html[data-theme='light'] .pill-notification{color:#9d174d}html[data-theme='light'] .pill-auth,html[data-theme='light'] .pill-dump,html[data-theme='light'] .pill-view{color:#334155}html[data-theme='light'] .pill-event,html[data-theme='light'] .pill-model{color:#166534}html[data-theme='light'] .pill-redis{color:#991b1b}html[data-theme='light'] .pill-gate{color:#3730a3}html[data-theme='light'] .pill-middleware{color:#155e75}html[data-theme='light'] .pill-client-request{color:#1d4ed8}
|
|
82
82
|
.monitoring-wrap{padding:0 24px 24px}.tag-list{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:18px}.tag-item{display:inline-flex;align-items:center;gap:10px;padding:10px 14px;border-radius:999px;border:1px solid var(--line);background:var(--surface-strong)}.tag-remove{border:none;background:rgba(239,68,68,.14);color:var(--danger);border-radius:999px;width:24px;height:24px;cursor:pointer;font-size:1rem;line-height:1}.helper-text{color:var(--muted);line-height:1.6}
|
|
83
83
|
.duration-chip{display:inline-flex;align-items:center;padding:5px 9px;border-radius:999px;border:1px solid transparent;font-size:.8rem;font-weight:700;color:var(--text);white-space:nowrap}.duration-chip.vfast{background:rgba(34,197,94,.14);border-color:rgba(34,197,94,.28);color:#bbf7d0}.duration-chip.fast{background:rgba(56,189,248,.12);border-color:rgba(56,189,248,.24);color:#bae6fd}.duration-chip.slow{background:rgba(245,158,11,.12);border-color:rgba(245,158,11,.22);color:#fde68a}.duration-chip.vslow{background:rgba(239,68,68,.14);border-color:rgba(239,68,68,.24);color:#fecaca}html[data-theme='light'] .duration-chip.vfast{color:#166534}html[data-theme='light'] .duration-chip.fast{color:#1d4ed8}html[data-theme='light'] .duration-chip.slow{color:#92400e}html[data-theme='light'] .duration-chip.vslow{color:#b91c1c}
|
|
84
84
|
.code-card{border-radius:16px;border:1px solid var(--code-border);background:var(--surface-soft);overflow:hidden}.code-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--line)}.code-label{font-size:.76rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:800}.copy-button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:38px;height:38px;border-radius:12px;border:1px solid var(--line);background:var(--surface-strong);color:var(--text);cursor:pointer;transition:border-color .16s ease,color .16s ease}.copy-button:hover{border-color:rgba(56,189,248,.35);color:var(--accent)}.copy-button[data-copied='true']{color:var(--success);border-color:rgba(34,197,94,.28)}.copy-button svg{width:16px;height:16px;display:block}.code-block{margin:0;padding:18px 20px;background:var(--code-bg);color:#dbeafe;border:0;overflow:auto;white-space:pre;line-height:1.72;font-family:var(--mono);font-size:.92rem}.code-block.wrap{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}.code-block code{font-family:inherit}.html-preview-wrap{padding:14px;background:var(--surface-strong);border-top:1px solid var(--line)}.html-preview{display:block;width:100%;min-height:320px;border:1px solid var(--line);border-radius:14px;background:#fff}.inline-collapse{margin:0;border-top:1px solid var(--line);background:var(--surface-strong)}.inline-collapse summary{cursor:pointer;list-style:none;padding:14px 16px;font-size:.82rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:800}.inline-collapse summary::-webkit-details-marker{display:none}.inline-collapse[open] summary{border-bottom:1px solid var(--line)}.inline-collapse .code-block{border-top:none}.tok-key{color:#93c5fd}.tok-string{color:#86efac}.tok-number{color:#f9a8d4}.tok-boolean{color:#facc15}.tok-null{color:#fb7185}.tok-punctuation{color:#94a3b8}.tok-sql-keyword{color:#f472b6;font-weight:700}.tok-sql-identifier{color:#93c5fd}.tok-sql-string{color:#86efac}.tok-sql-number{color:#facc15}.tok-sql-comment{color:#64748b;font-style:italic}html[data-theme='light'] .code-block{color:#0f172a}html[data-theme='light'] .tok-key{color:#1d4ed8}html[data-theme='light'] .tok-string{color:#15803d}html[data-theme='light'] .tok-number{color:#c026d3}html[data-theme='light'] .tok-boolean{color:#b45309}html[data-theme='light'] .tok-null{color:#dc2626}html[data-theme='light'] .tok-punctuation{color:#64748b}html[data-theme='light'] .tok-sql-keyword{color:#db2777}html[data-theme='light'] .tok-sql-identifier{color:#2563eb}html[data-theme='light'] .tok-sql-string{color:#15803d}html[data-theme='light'] .tok-sql-number{color:#b45309}html[data-theme='light'] .tok-sql-comment{color:#6b7280}
|
|
85
|
-
@media (max-width:1120px){.content-grid{grid-template-columns:1fr}}@media (max-width:920px){.layout{grid-template-columns:1fr}.sidebar{position:static;height:auto;border-right:none;border-bottom:1px solid var(--line);padding:20px 16px 18px}.brand-row{padding:0 0 16px}.sidebar-status{margin:0 0 16px}.sidebar-group{padding:0}.main{padding:20px}}@media (max-width:640px){.stats-grid{grid-template-columns:1fr}.detail-card{padding:18px}.toolbar,.section-head,.
|
|
85
|
+
@media (max-width:1120px){.content-grid{grid-template-columns:1fr}}@media (max-width:920px){.layout{grid-template-columns:1fr}.sidebar{position:static;height:auto;border-right:none;border-bottom:1px solid var(--line);padding:20px 16px 18px}.brand-row{padding:0 0 16px}.sidebar-status{margin:0 0 16px}.sidebar-group{padding:0}.main{padding:20px}}@media (max-width:760px){.main{padding:16px}.shell{gap:14px}.stat-value{font-size:1.9rem}.section-head{flex-direction:column;align-items:stretch}.section-head .btn{width:100%}.toolbar{display:grid;grid-template-columns:1fr;padding-left:18px;padding-right:18px}.toolbar .btn,.toolbar input,.toolbar select{width:100%;flex:none}.pagination{padding-left:18px;padding-right:18px}.pagination,.pagination-controls{width:100%}.pagination-controls{justify-content:space-between}.pagination button{flex:1 1 0}.detail-meta{display:grid;gap:8px}.trace-tabs{flex-wrap:nowrap;overflow:auto;padding-bottom:4px}.trace-tab{white-space:nowrap}.code-toolbar{flex-wrap:wrap}.copy-button{width:100%}.html-preview{min-height:220px}.table-wrap{padding:0 14px 14px;overflow:visible}.table-wrap table{min-width:0;border-spacing:0}.table-wrap thead{display:none}.table-wrap tbody{display:grid;gap:12px}.table-wrap tr{display:block;border:1px solid var(--line);border-radius:16px;background:var(--surface-soft);overflow:hidden}.table-wrap td{display:grid;grid-template-columns:minmax(84px,108px) minmax(0,1fr);gap:10px;align-items:start;padding:12px 14px;border-bottom:1px solid var(--line)}.table-wrap td::before{content:attr(data-label);font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}.table-wrap td:last-child{border-bottom:none}.table-wrap td[data-label='Summary'],.table-wrap td[data-label='Tags']{grid-template-columns:1fr}.table-wrap td[data-label='Summary']::before,.table-wrap td[data-label='Tags']::before{margin-bottom:2px}.row-button:hover td{background:transparent}.row-button:hover{box-shadow:inset 0 0 0 1px rgba(56,189,248,.18)}}@media (max-width:640px){.stats-grid{grid-template-columns:1fr}.detail-card{padding:18px}.toolbar,.section-head,.activity-list,.monitoring-wrap{padding-left:18px;padding-right:18px}.brand-row{align-items:stretch;gap:14px;padding:0 0 14px}.brand{width:100%;align-items:flex-start}.brand-copy{min-width:0}.brand-copy h1{font-size:1.18rem;line-height:1.12}.brand-copy p{font-size:.82rem;overflow-wrap:anywhere}.icon-button{align-self:flex-end}.sidebar-status{padding:12px}.nav-button{padding:11px 12px}.nav-title{font-size:.95rem}.nav-meta{font-size:.72rem}}@media (max-width:480px){.brand-row{flex-direction:column}.icon-button{align-self:flex-start}.nav-button{align-items:flex-start;flex-direction:column}.nav-meta{font-size:.7rem}}
|
|
86
86
|
</style>
|
|
87
87
|
</head>
|
|
88
88
|
<body>
|
|
@@ -845,7 +845,7 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
845
845
|
const recentRows = recent.data || [];
|
|
846
846
|
const recentTable = recentRows.length === 0
|
|
847
847
|
? '<div class="empty">No trace entries recorded.</div>'
|
|
848
|
-
: '<div class="table-wrap"><table><thead><tr><th>Type</th><th>Summary</th><th>Tags</th><th>Duration</th><th>Happened</th></tr></thead><tbody>' + recentRows.map((entry) => '<tr class="row-button" data-action="show-detail" data-uuid="' + escapeHtml(entry.uuid) + '"><td><span class="' + typeClass(entry) + '">' + escapeHtml(entryTypeLabel(entry)) + '</span></td><td>' + entrySummaryHtml(entry) + '</td><td>' + tagsHtml(entry.tags) + '</td><td>' + durationHtml(entry) + '</td><td class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</td></tr>').join('') + '</tbody></table></div>';
|
|
848
|
+
: '<div class="table-wrap"><table><thead><tr><th>Type</th><th>Summary</th><th>Tags</th><th>Duration</th><th>Happened</th></tr></thead><tbody>' + recentRows.map((entry) => '<tr class="row-button" data-action="show-detail" data-uuid="' + escapeHtml(entry.uuid) + '"><td data-label="Type"><span class="' + typeClass(entry) + '">' + escapeHtml(entryTypeLabel(entry)) + '</span></td><td data-label="Summary">' + entrySummaryHtml(entry) + '</td><td data-label="Tags">' + tagsHtml(entry.tags) + '</td><td data-label="Duration">' + durationHtml(entry) + '</td><td data-label="Happened" class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</td></tr>').join('') + '</tbody></table></div>';
|
|
849
849
|
const activityList = recentRows.length === 0
|
|
850
850
|
? '<div class="empty">No recent activity.</div>'
|
|
851
851
|
: '<ul class="activity-list">' + recentRows.slice(0, 5).map((entry) => '<li class="activity-item"><div class="activity-head"><span class="' + typeClass(entry) + '">' + escapeHtml(entryTypeLabel(entry)) + '</span>' + durationHtml(entry) + '<span class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</span></div><div class="activity-summary">' + escapeHtml(entrySummaryText(entry)) + '</div></li>').join('') + '</ul>';
|
|
@@ -892,7 +892,7 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
892
892
|
const total = Number(response.total || 0);
|
|
893
893
|
const perPage = Number(response.perPage || 50);
|
|
894
894
|
const totalPages = Math.max(1, Math.ceil(total / perPage));
|
|
895
|
-
const rows = data.map((entry) => '<tr class="row-button" data-action="show-detail" data-uuid="' + escapeHtml(entry.uuid) + '"><td><span class="' + typeClass(entry) + '">' + escapeHtml(entryTypeLabel(entry)) + '</span></td><td>' + entrySummaryHtml(entry) + '</td><td>' + tagsHtml(entry.tags) + '</td><td>' + durationHtml(entry) + '</td><td class="mono">' + batchSnippet(entry.batchId) + '</td><td class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</td></tr>').join('');
|
|
895
|
+
const rows = data.map((entry) => '<tr class="row-button" data-action="show-detail" data-uuid="' + escapeHtml(entry.uuid) + '"><td data-label="Type"><span class="' + typeClass(entry) + '">' + escapeHtml(entryTypeLabel(entry)) + '</span></td><td data-label="Summary">' + entrySummaryHtml(entry) + '</td><td data-label="Tags">' + tagsHtml(entry.tags) + '</td><td data-label="Duration">' + durationHtml(entry) + '</td><td data-label="Batch" class="mono">' + batchSnippet(entry.batchId) + '</td><td data-label="Happened" class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</td></tr>').join('');
|
|
896
896
|
|
|
897
897
|
main.innerHTML = [
|
|
898
898
|
'<section class="panel">',
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { TraceContext } from '../context';
|
|
2
2
|
|
|
3
|
+
type RequestIgnoreRules = {
|
|
4
|
+
ignoreRoutes?: string[];
|
|
5
|
+
ignorePaths?: string[];
|
|
6
|
+
};
|
|
7
|
+
|
|
3
8
|
const normalizePath = (input: string): string => {
|
|
4
9
|
const trimmed = input.trim();
|
|
5
10
|
const [pathOnly] = trimmed.split('?');
|
|
@@ -7,24 +12,65 @@ const normalizePath = (input: string): string => {
|
|
|
7
12
|
return pathOnly.startsWith('/') ? pathOnly : `/${pathOnly}`;
|
|
8
13
|
};
|
|
9
14
|
|
|
10
|
-
const
|
|
15
|
+
const normalizeContainsPattern = (input: string): string => {
|
|
16
|
+
const trimmed = input.trim();
|
|
17
|
+
const [pathOnly] = trimmed.split('?');
|
|
18
|
+
return pathOnly ?? '';
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const resolveRules = (
|
|
22
|
+
ignoreRoutesOrRules: string[] | RequestIgnoreRules,
|
|
23
|
+
ignorePaths?: string[]
|
|
24
|
+
): Required<RequestIgnoreRules> => {
|
|
25
|
+
if (Array.isArray(ignoreRoutesOrRules)) {
|
|
26
|
+
return {
|
|
27
|
+
ignoreRoutes: ignoreRoutesOrRules,
|
|
28
|
+
ignorePaths: ignorePaths ?? [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
ignoreRoutes: ignoreRoutesOrRules.ignoreRoutes ?? [],
|
|
34
|
+
ignorePaths: ignoreRoutesOrRules.ignorePaths ?? [],
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const matchesIgnoredPath = (
|
|
39
|
+
path: string,
|
|
40
|
+
ignoreRoutesOrRules: string[] | RequestIgnoreRules,
|
|
41
|
+
ignorePaths?: string[]
|
|
42
|
+
): boolean => {
|
|
11
43
|
const normalizedPath = normalizePath(path);
|
|
44
|
+
const rules = resolveRules(ignoreRoutesOrRules, ignorePaths);
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
rules.ignoreRoutes.some((route) => {
|
|
48
|
+
const normalizedRoute = normalizePath(route);
|
|
49
|
+
return (
|
|
50
|
+
normalizedPath === normalizedRoute ||
|
|
51
|
+
normalizedPath.startsWith(
|
|
52
|
+
normalizedRoute.endsWith('/') ? normalizedRoute : `${normalizedRoute}/`
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
})
|
|
56
|
+
) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
12
59
|
|
|
13
|
-
return
|
|
14
|
-
const
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
normalizedPath.startsWith(
|
|
18
|
-
normalizedRoute.endsWith('/') ? normalizedRoute : `${normalizedRoute}/`
|
|
19
|
-
)
|
|
20
|
-
);
|
|
60
|
+
return rules.ignorePaths.some((route) => {
|
|
61
|
+
const containsPattern = normalizeContainsPattern(route);
|
|
62
|
+
if (containsPattern === '') return false;
|
|
63
|
+
return normalizedPath.includes(containsPattern);
|
|
21
64
|
});
|
|
22
65
|
};
|
|
23
66
|
|
|
24
|
-
const shouldIgnoreCurrentRequest = (
|
|
67
|
+
const shouldIgnoreCurrentRequest = (
|
|
68
|
+
ignoreRoutesOrRules: string[] | RequestIgnoreRules,
|
|
69
|
+
ignorePaths?: string[]
|
|
70
|
+
): boolean => {
|
|
25
71
|
const currentPath = TraceContext.getRequestPath();
|
|
26
72
|
if (typeof currentPath !== 'string' || currentPath === '') return false;
|
|
27
|
-
return matchesIgnoredPath(currentPath,
|
|
73
|
+
return matchesIgnoredPath(currentPath, ignoreRoutesOrRules, ignorePaths);
|
|
28
74
|
};
|
|
29
75
|
|
|
30
76
|
export const RequestFilter = Object.freeze({
|
|
@@ -9,10 +9,11 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
9
9
|
|
|
10
10
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
11
11
|
let _ignoreRoutes: string[] = [];
|
|
12
|
+
let _ignorePaths: string[] = [];
|
|
12
13
|
|
|
13
14
|
const emit = (event: AuthContent['event'], userId?: string): void => {
|
|
14
15
|
if (!_storage) return;
|
|
15
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
16
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
16
17
|
const content: AuthContent = {
|
|
17
18
|
event,
|
|
18
19
|
userId,
|
|
@@ -42,9 +43,11 @@ export const AuthWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze(
|
|
|
42
43
|
if (config.watchers.auth === false) return () => undefined;
|
|
43
44
|
_storage = storage;
|
|
44
45
|
_ignoreRoutes = config.ignoreRoutes;
|
|
46
|
+
_ignorePaths = config.ignorePaths;
|
|
45
47
|
return () => {
|
|
46
48
|
_storage = null;
|
|
47
49
|
_ignoreRoutes = [];
|
|
50
|
+
_ignorePaths = [];
|
|
48
51
|
};
|
|
49
52
|
},
|
|
50
53
|
});
|
|
@@ -5,6 +5,7 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
5
5
|
|
|
6
6
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
7
7
|
let _ignoreRoutes: string[] = [];
|
|
8
|
+
let _ignorePaths: string[] = [];
|
|
8
9
|
|
|
9
10
|
const emit = (
|
|
10
11
|
name: string,
|
|
@@ -14,7 +15,7 @@ const emit = (
|
|
|
14
15
|
status: BatchContent['status']
|
|
15
16
|
): void => {
|
|
16
17
|
if (!_storage) return;
|
|
17
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
18
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
18
19
|
const tags = [name];
|
|
19
20
|
if (failed > 0) tags.push('failed');
|
|
20
21
|
const content: BatchContent = {
|
|
@@ -44,9 +45,11 @@ export const BatchWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze
|
|
|
44
45
|
if (config.watchers.batch === false) return () => undefined;
|
|
45
46
|
_storage = storage;
|
|
46
47
|
_ignoreRoutes = config.ignoreRoutes;
|
|
48
|
+
_ignorePaths = config.ignorePaths;
|
|
47
49
|
return () => {
|
|
48
50
|
_storage = null;
|
|
49
51
|
_ignoreRoutes = [];
|
|
52
|
+
_ignorePaths = [];
|
|
50
53
|
};
|
|
51
54
|
},
|
|
52
55
|
});
|
|
@@ -13,6 +13,7 @@ let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
|
13
13
|
let _config: ITraceWatcherConfig['config'] | null = null;
|
|
14
14
|
let _redactionFields: string[] = [];
|
|
15
15
|
let _ignoreRoutes: string[] = [];
|
|
16
|
+
let _ignorePaths: string[] = [];
|
|
16
17
|
|
|
17
18
|
const emit = (
|
|
18
19
|
operation: CacheContent['operation'],
|
|
@@ -24,7 +25,7 @@ const emit = (
|
|
|
24
25
|
ttl?: number
|
|
25
26
|
): void => {
|
|
26
27
|
if (!_storage) return;
|
|
27
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
28
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
28
29
|
const safeKey = redactString(key, _redactionFields);
|
|
29
30
|
const shouldLogPayload = _config?.captureCachePayloads === true;
|
|
30
31
|
const content: CacheContent = {
|
|
@@ -60,10 +61,12 @@ export const CacheWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze
|
|
|
60
61
|
_config = config;
|
|
61
62
|
_redactionFields = config.redaction.query;
|
|
62
63
|
_ignoreRoutes = config.ignoreRoutes;
|
|
64
|
+
_ignorePaths = config.ignorePaths;
|
|
63
65
|
return () => {
|
|
64
66
|
_storage = null;
|
|
65
67
|
_config = null;
|
|
66
68
|
_ignoreRoutes = [];
|
|
69
|
+
_ignorePaths = [];
|
|
67
70
|
};
|
|
68
71
|
},
|
|
69
72
|
});
|
|
@@ -7,6 +7,7 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
7
7
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
8
8
|
let _redactKeys: string[] = [];
|
|
9
9
|
let _ignoreRoutes: string[] = [];
|
|
10
|
+
let _ignorePaths: string[] = [];
|
|
10
11
|
|
|
11
12
|
const emit = (
|
|
12
13
|
name: string,
|
|
@@ -16,7 +17,7 @@ const emit = (
|
|
|
16
17
|
output?: string
|
|
17
18
|
): void => {
|
|
18
19
|
if (!_storage) return;
|
|
19
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
20
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
20
21
|
const tags = [name];
|
|
21
22
|
if (exitCode !== 0) tags.push('failed');
|
|
22
23
|
const content: CommandContent = {
|
|
@@ -47,9 +48,11 @@ export const CommandWatcher: ITraceWatcher & { emit: typeof emit } = Object.free
|
|
|
47
48
|
_storage = storage;
|
|
48
49
|
_redactKeys = [...(config.redaction?.keys ?? []), ...(config.redaction?.body ?? [])];
|
|
49
50
|
_ignoreRoutes = config.ignoreRoutes;
|
|
51
|
+
_ignorePaths = config.ignorePaths;
|
|
50
52
|
return () => {
|
|
51
53
|
_storage = null;
|
|
52
54
|
_ignoreRoutes = [];
|
|
55
|
+
_ignorePaths = [];
|
|
53
56
|
};
|
|
54
57
|
},
|
|
55
58
|
});
|
|
@@ -6,11 +6,12 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
6
6
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
7
7
|
let _enabled = false;
|
|
8
8
|
let _ignoreRoutes: string[] = [];
|
|
9
|
+
let _ignorePaths: string[] = [];
|
|
9
10
|
|
|
10
11
|
/** Explicitly opt-in (enabled only when config.watchers.dump === true, not just non-false). */
|
|
11
12
|
const emit = (value: unknown, file?: string, line?: number): void => {
|
|
12
13
|
if (!_storage || !_enabled) return;
|
|
13
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
14
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
14
15
|
const content: DumpContent = { value, file, line, hostname: TraceContext.getHostname() };
|
|
15
16
|
_storage
|
|
16
17
|
.writeEntry({
|
|
@@ -33,10 +34,12 @@ export const DumpWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze(
|
|
|
33
34
|
_storage = storage;
|
|
34
35
|
_enabled = true;
|
|
35
36
|
_ignoreRoutes = config.ignoreRoutes;
|
|
37
|
+
_ignorePaths = config.ignorePaths;
|
|
36
38
|
return () => {
|
|
37
39
|
_storage = null;
|
|
38
40
|
_enabled = false;
|
|
39
41
|
_ignoreRoutes = [];
|
|
42
|
+
_ignorePaths = [];
|
|
40
43
|
};
|
|
41
44
|
},
|
|
42
45
|
});
|
|
@@ -6,10 +6,11 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
6
6
|
|
|
7
7
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
8
8
|
let _ignoreRoutes: string[] = [];
|
|
9
|
+
let _ignorePaths: string[] = [];
|
|
9
10
|
|
|
10
11
|
const emit = (name: string, listenerCount: number, payload?: unknown): void => {
|
|
11
12
|
if (!_storage) return;
|
|
12
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
13
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
13
14
|
const content: EventContent = {
|
|
14
15
|
name,
|
|
15
16
|
payload,
|
|
@@ -35,9 +36,11 @@ export const EventWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze
|
|
|
35
36
|
if (config.watchers.event === false) return () => undefined;
|
|
36
37
|
_storage = storage;
|
|
37
38
|
_ignoreRoutes = config.ignoreRoutes;
|
|
39
|
+
_ignorePaths = config.ignorePaths;
|
|
38
40
|
return () => {
|
|
39
41
|
_storage = null;
|
|
40
42
|
_ignoreRoutes = [];
|
|
43
|
+
_ignorePaths = [];
|
|
41
44
|
};
|
|
42
45
|
},
|
|
43
46
|
});
|
|
@@ -50,6 +50,7 @@ const buildContent = (err: Error, context?: ExceptionCaptureContext): ExceptionC
|
|
|
50
50
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
51
51
|
let _listenerRefCount = 0;
|
|
52
52
|
let _ignoreRoutes: string[] = [];
|
|
53
|
+
let _ignorePaths: string[] = [];
|
|
53
54
|
|
|
54
55
|
const handleUncaughtException = (error: unknown): void => {
|
|
55
56
|
captureException(error);
|
|
@@ -76,8 +77,8 @@ const captureException = (err: unknown, context?: ExceptionCaptureContext): void
|
|
|
76
77
|
if (!storage) return;
|
|
77
78
|
if (!(err instanceof Error)) return;
|
|
78
79
|
if (context?.path !== undefined) {
|
|
79
|
-
if (RequestFilter.matchesIgnoredPath(context.path, _ignoreRoutes)) return;
|
|
80
|
-
} else if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) {
|
|
80
|
+
if (RequestFilter.matchesIgnoredPath(context.path, _ignoreRoutes, _ignorePaths)) return;
|
|
81
|
+
} else if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) {
|
|
81
82
|
return;
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -109,6 +110,7 @@ export const ExceptionWatcher: ITraceWatcher & {
|
|
|
109
110
|
if (config.watchers.exception === false) return () => undefined;
|
|
110
111
|
_storage = storage;
|
|
111
112
|
_ignoreRoutes = config.ignoreRoutes;
|
|
113
|
+
_ignorePaths = config.ignorePaths;
|
|
112
114
|
|
|
113
115
|
if (_listenerRefCount === 0) {
|
|
114
116
|
registerProcessListeners();
|
|
@@ -122,6 +124,7 @@ export const ExceptionWatcher: ITraceWatcher & {
|
|
|
122
124
|
}
|
|
123
125
|
_storage = null;
|
|
124
126
|
_ignoreRoutes = [];
|
|
127
|
+
_ignorePaths = [];
|
|
125
128
|
};
|
|
126
129
|
},
|
|
127
130
|
});
|
|
@@ -5,6 +5,7 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
5
5
|
|
|
6
6
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
7
7
|
let _ignoreRoutes: string[] = [];
|
|
8
|
+
let _ignorePaths: string[] = [];
|
|
8
9
|
|
|
9
10
|
const emit = (
|
|
10
11
|
ability: string,
|
|
@@ -13,7 +14,7 @@ const emit = (
|
|
|
13
14
|
subject?: string
|
|
14
15
|
): void => {
|
|
15
16
|
if (!_storage) return;
|
|
16
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
17
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
17
18
|
const tags: string[] = [ability, result];
|
|
18
19
|
if (userId) tags.push(`Auth:${userId}`);
|
|
19
20
|
const content: GateContent = {
|
|
@@ -42,9 +43,11 @@ export const GateWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze(
|
|
|
42
43
|
if (config.watchers.gate === false) return () => undefined;
|
|
43
44
|
_storage = storage;
|
|
44
45
|
_ignoreRoutes = config.ignoreRoutes;
|
|
46
|
+
_ignorePaths = config.ignorePaths;
|
|
45
47
|
return () => {
|
|
46
48
|
_storage = null;
|
|
47
49
|
_ignoreRoutes = [];
|
|
50
|
+
_ignorePaths = [];
|
|
48
51
|
};
|
|
49
52
|
},
|
|
50
53
|
});
|
|
@@ -16,6 +16,7 @@ let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
|
16
16
|
let _redactHeaderNames: string[] = [];
|
|
17
17
|
let _redactBodyFields: string[] = [];
|
|
18
18
|
let _ignoreRoutes: string[] = [];
|
|
19
|
+
let _ignorePaths: string[] = [];
|
|
19
20
|
let _clientRequestWatcher: TraceClientRequestWatcherConfig | undefined;
|
|
20
21
|
|
|
21
22
|
const isObjectValue = (value: unknown): value is Record<string, unknown> => {
|
|
@@ -158,7 +159,7 @@ const emit = ({
|
|
|
158
159
|
error,
|
|
159
160
|
}: ClientRequestTraceInput): void => {
|
|
160
161
|
if (!_storage) return;
|
|
161
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
162
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
162
163
|
const normalizedSource = resolveSource(source);
|
|
163
164
|
const sourceRule = resolveSourceRule(normalizedSource);
|
|
164
165
|
if (sourceRule?.enabled === false) return;
|
|
@@ -206,11 +207,13 @@ export const HttpClientWatcher: ITraceWatcher & { emit: typeof emit } = Object.f
|
|
|
206
207
|
_redactHeaderNames = [...(config.redaction?.keys ?? []), ...(config.redaction?.headers ?? [])];
|
|
207
208
|
_redactBodyFields = [...(config.redaction?.keys ?? []), ...(config.redaction?.body ?? [])];
|
|
208
209
|
_ignoreRoutes = config.ignoreRoutes;
|
|
210
|
+
_ignorePaths = config.ignorePaths;
|
|
209
211
|
return () => {
|
|
210
212
|
_storage = null;
|
|
211
213
|
_clientRequestWatcher = undefined;
|
|
212
214
|
_redactBodyFields = [];
|
|
213
215
|
_ignoreRoutes = [];
|
|
216
|
+
_ignorePaths = [];
|
|
214
217
|
};
|
|
215
218
|
},
|
|
216
219
|
});
|
|
@@ -164,7 +164,7 @@ const buildEntry = (
|
|
|
164
164
|
};
|
|
165
165
|
|
|
166
166
|
const shouldIgnore = (req: IRequest, config: ITraceConfig): boolean => {
|
|
167
|
-
return RequestFilter.matchesIgnoredPath(req.getPath(), config
|
|
167
|
+
return RequestFilter.matchesIgnoredPath(req.getPath(), config);
|
|
168
168
|
};
|
|
169
169
|
|
|
170
170
|
const isWatcherEnabled = (config: ITraceConfig): boolean => config.watchers.request !== false;
|
|
@@ -12,6 +12,7 @@ import { parseStackFrameLine } from '../utils/stackFrame';
|
|
|
12
12
|
// Module-level storage ref so emit helpers can be called from outside.
|
|
13
13
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
14
14
|
let _ignoreRoutes: string[] = [];
|
|
15
|
+
let _ignorePaths: string[] = [];
|
|
15
16
|
const MAX_TRACKED_JOBS = 1000;
|
|
16
17
|
|
|
17
18
|
type PendingJob = { uuid: string; content: JobContent };
|
|
@@ -43,7 +44,7 @@ const takePendingJob = (name: string): PendingJob | null => {
|
|
|
43
44
|
|
|
44
45
|
const emitDispatch = (name: string, queue: string, connection: string, data?: unknown): void => {
|
|
45
46
|
if (!_storage) return;
|
|
46
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
47
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
47
48
|
const uuid = crypto.randomUUID();
|
|
48
49
|
const content: JobContent = {
|
|
49
50
|
status: 'pending',
|
|
@@ -112,9 +113,11 @@ export const JobWatcher: ITraceWatcher & {
|
|
|
112
113
|
if (config.watchers.job === false) return () => undefined;
|
|
113
114
|
_storage = storage;
|
|
114
115
|
_ignoreRoutes = config.ignoreRoutes;
|
|
116
|
+
_ignorePaths = config.ignorePaths;
|
|
115
117
|
return () => {
|
|
116
118
|
_storage = null;
|
|
117
119
|
_ignoreRoutes = [];
|
|
120
|
+
_ignorePaths = [];
|
|
118
121
|
pendingJobs.clear();
|
|
119
122
|
};
|
|
120
123
|
},
|
|
@@ -82,7 +82,8 @@ export const LogWatcher: ITraceWatcher = Object.freeze({
|
|
|
82
82
|
const unsubscribe = loggerWithSink.addSink(
|
|
83
83
|
(level: string, message: string, context?: Record<string, unknown>) => {
|
|
84
84
|
if ((LEVEL_PRIORITY[level] ?? 0) < minPriority) return;
|
|
85
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes))
|
|
85
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes, config.ignorePaths))
|
|
86
|
+
return;
|
|
86
87
|
if (shouldSkipTraceInfrastructureLog(message, context)) return;
|
|
87
88
|
|
|
88
89
|
const content: LogContent = {
|
|
@@ -10,6 +10,7 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
10
10
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
11
11
|
let _redactionFields: string[] = [];
|
|
12
12
|
let _ignoreRoutes: string[] = [];
|
|
13
|
+
let _ignorePaths: string[] = [];
|
|
13
14
|
|
|
14
15
|
const emit = (
|
|
15
16
|
to: string,
|
|
@@ -19,7 +20,7 @@ const emit = (
|
|
|
19
20
|
html?: string
|
|
20
21
|
): void => {
|
|
21
22
|
if (!_storage) return;
|
|
22
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
23
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
23
24
|
const content: MailContent = {
|
|
24
25
|
to,
|
|
25
26
|
subject,
|
|
@@ -53,10 +54,12 @@ export const MailWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze(
|
|
|
53
54
|
_storage = storage;
|
|
54
55
|
_redactionFields = [...config.redaction.keys, ...config.redaction.body];
|
|
55
56
|
_ignoreRoutes = config.ignoreRoutes;
|
|
57
|
+
_ignorePaths = config.ignorePaths;
|
|
56
58
|
return () => {
|
|
57
59
|
_storage = null;
|
|
58
60
|
_redactionFields = [];
|
|
59
61
|
_ignoreRoutes = [];
|
|
62
|
+
_ignorePaths = [];
|
|
60
63
|
};
|
|
61
64
|
},
|
|
62
65
|
});
|
|
@@ -5,6 +5,7 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
5
5
|
|
|
6
6
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
7
7
|
let _ignoreRoutes: string[] = [];
|
|
8
|
+
let _ignorePaths: string[] = [];
|
|
8
9
|
|
|
9
10
|
type GlobalMiddlewareTraceState = {
|
|
10
11
|
__zintrust_trace_middleware_emit__?: typeof emit;
|
|
@@ -12,7 +13,7 @@ type GlobalMiddlewareTraceState = {
|
|
|
12
13
|
|
|
13
14
|
const emit = (name: string, event: MiddlewareContent['event'], duration?: number): void => {
|
|
14
15
|
if (!_storage) return;
|
|
15
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
16
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
16
17
|
const content: MiddlewareContent = {
|
|
17
18
|
name,
|
|
18
19
|
event,
|
|
@@ -38,6 +39,7 @@ export const MiddlewareWatcher: ITraceWatcher & { emit: typeof emit } = Object.f
|
|
|
38
39
|
if (config.watchers.middleware === false) return () => undefined;
|
|
39
40
|
_storage = storage;
|
|
40
41
|
_ignoreRoutes = config.ignoreRoutes;
|
|
42
|
+
_ignorePaths = config.ignorePaths;
|
|
41
43
|
(globalThis as unknown as GlobalMiddlewareTraceState).__zintrust_trace_middleware_emit__ = emit;
|
|
42
44
|
return () => {
|
|
43
45
|
const globalState = globalThis as unknown as GlobalMiddlewareTraceState;
|
|
@@ -46,6 +48,7 @@ export const MiddlewareWatcher: ITraceWatcher & { emit: typeof emit } = Object.f
|
|
|
46
48
|
}
|
|
47
49
|
_storage = null;
|
|
48
50
|
_ignoreRoutes = [];
|
|
51
|
+
_ignorePaths = [];
|
|
49
52
|
};
|
|
50
53
|
},
|
|
51
54
|
});
|
|
@@ -5,6 +5,7 @@ import { RequestFilter } from '../utils/requestFilter';
|
|
|
5
5
|
|
|
6
6
|
let _storage: ITraceWatcherConfig['storage'] | null = null;
|
|
7
7
|
let _ignoreRoutes: string[] = [];
|
|
8
|
+
let _ignorePaths: string[] = [];
|
|
8
9
|
|
|
9
10
|
type GlobalModelTraceState = {
|
|
10
11
|
__zintrust_trace_model_emit__?: typeof emit;
|
|
@@ -17,7 +18,7 @@ const emit = (
|
|
|
17
18
|
changes?: Record<string, unknown>
|
|
18
19
|
): void => {
|
|
19
20
|
if (!_storage) return;
|
|
20
|
-
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes)) return;
|
|
21
|
+
if (RequestFilter.shouldIgnoreCurrentRequest(_ignoreRoutes, _ignorePaths)) return;
|
|
21
22
|
const content: ModelContent = {
|
|
22
23
|
action,
|
|
23
24
|
model,
|
|
@@ -44,6 +45,7 @@ export const ModelWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze
|
|
|
44
45
|
if (config.watchers.model === false) return () => undefined;
|
|
45
46
|
_storage = storage;
|
|
46
47
|
_ignoreRoutes = config.ignoreRoutes;
|
|
48
|
+
_ignorePaths = config.ignorePaths;
|
|
47
49
|
(globalThis as unknown as GlobalModelTraceState).__zintrust_trace_model_emit__ = emit;
|
|
48
50
|
return () => {
|
|
49
51
|
const globalState = globalThis as unknown as GlobalModelTraceState;
|
|
@@ -52,6 +54,7 @@ export const ModelWatcher: ITraceWatcher & { emit: typeof emit } = Object.freeze
|
|
|
52
54
|
}
|
|
53
55
|
_storage = null;
|
|
54
56
|
_ignoreRoutes = [];
|
|
57
|
+
_ignorePaths = [];
|
|
55
58
|
};
|
|
56
59
|
},
|
|
57
60
|
});
|