@zintrust/trace 0.4.84 → 0.4.92
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/build-manifest.json +16 -28
- package/dist/dashboard/ui.js +51 -12
- package/dist/register.js +101 -56
- package/dist/watchers/LogWatcher.js +32 -3
- package/dist/watchers/QueryWatcher.js +3 -1
- package/package.json +2 -2
- package/src/dashboard/ui.ts +51 -12
- package/src/register.ts +171 -90
- package/src/watchers/LogWatcher.ts +45 -3
- package/src/watchers/QueryWatcher.ts +5 -1
- package/dist/storage/DebuggerStorage.d.ts +0 -13
- package/dist/storage/DebuggerStorage.js +0 -195
package/src/dashboard/ui.ts
CHANGED
|
@@ -76,11 +76,11 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
76
76
|
.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}
|
|
77
77
|
.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)}
|
|
78
78
|
.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
|
-
.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}.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}.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}
|
|
79
|
+
.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}
|
|
80
80
|
.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}
|
|
81
81
|
.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}
|
|
82
82
|
.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}
|
|
83
|
-
.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 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}.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}
|
|
83
|
+
.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}
|
|
84
84
|
@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,.pagination,.activity-list,.monitoring-wrap{padding-left:18px;padding-right:18px}.table-wrap{padding:0 8px 10px}.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}}
|
|
85
85
|
</style>
|
|
86
86
|
</head>
|
|
@@ -328,8 +328,9 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
328
328
|
return id;
|
|
329
329
|
};
|
|
330
330
|
|
|
331
|
-
const renderCodeCard = (label, rawText, highlightedHtml, languageClass) => {
|
|
331
|
+
const renderCodeCard = (label, rawText, highlightedHtml, languageClass, options = {}) => {
|
|
332
332
|
const copyId = registerCopyPayload(rawText);
|
|
333
|
+
const wrapClass = options.wrap === true ? ' wrap' : '';
|
|
333
334
|
return [
|
|
334
335
|
'<section class="code-card">',
|
|
335
336
|
'<div class="code-toolbar">',
|
|
@@ -338,19 +339,23 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
338
339
|
COPY_ICON,
|
|
339
340
|
'</button>',
|
|
340
341
|
'</div>',
|
|
341
|
-
'<pre class="code-block ' + escapeHtml(languageClass) + '"><code>' + highlightedHtml + '</code></pre>',
|
|
342
|
+
'<pre class="code-block ' + escapeHtml(languageClass) + wrapClass + '"><code>' + highlightedHtml + '</code></pre>',
|
|
342
343
|
'</section>'
|
|
343
344
|
].join('');
|
|
344
345
|
};
|
|
345
346
|
|
|
346
347
|
const renderTextCard = (label, value) => {
|
|
347
348
|
const source = String(value ?? '');
|
|
348
|
-
return renderCodeCard(label, source, escapeHtml(source), 'language-text');
|
|
349
|
+
return renderCodeCard(label, source, escapeHtml(source), 'language-text', { wrap: true });
|
|
349
350
|
};
|
|
350
351
|
|
|
351
|
-
const renderHtmlPreview = (label, html) => {
|
|
352
|
+
const renderHtmlPreview = (label, html, options = {}) => {
|
|
352
353
|
const source = String(html ?? '');
|
|
353
354
|
const copyId = registerCopyPayload(source);
|
|
355
|
+
const rawHtmlBlock = '<pre class="code-block language-html wrap"><code>' + escapeHtml(source) + '</code></pre>';
|
|
356
|
+
const rawHtmlSection = options.collapseSource === true
|
|
357
|
+
? '<details class="inline-collapse"><summary>View raw HTML source</summary>' + rawHtmlBlock + '</details>'
|
|
358
|
+
: rawHtmlBlock;
|
|
354
359
|
return [
|
|
355
360
|
'<section class="code-card">',
|
|
356
361
|
'<div class="code-toolbar">',
|
|
@@ -359,8 +364,8 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
359
364
|
COPY_ICON,
|
|
360
365
|
'</button>',
|
|
361
366
|
'</div>',
|
|
362
|
-
'<pre class="code-block language-html"><code>' + escapeHtml(source) + '</code></pre>',
|
|
363
367
|
'<div class="html-preview-wrap"><iframe class="html-preview" sandbox="allow-same-origin" srcdoc="' + escapeHtml(source) + '"></iframe></div>',
|
|
368
|
+
rawHtmlSection,
|
|
364
369
|
'</section>'
|
|
365
370
|
].join('');
|
|
366
371
|
};
|
|
@@ -384,7 +389,7 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
384
389
|
}
|
|
385
390
|
|
|
386
391
|
output += escapeHtml(source.slice(lastIndex));
|
|
387
|
-
return renderCodeCard(label, source, output, 'language-json');
|
|
392
|
+
return renderCodeCard(label, source, output, 'language-json', { wrap: true });
|
|
388
393
|
};
|
|
389
394
|
|
|
390
395
|
const highlightSql = (sql) => {
|
|
@@ -419,7 +424,9 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
419
424
|
const renderPayload = (label, value) => {
|
|
420
425
|
if (value === undefined) return '<p class="trace-note">No ' + escapeHtml(label.toLowerCase()) + ' was captured.</p>';
|
|
421
426
|
if (typeof value === 'string') {
|
|
422
|
-
return looksLikeHtml(value)
|
|
427
|
+
return looksLikeHtml(value)
|
|
428
|
+
? renderHtmlPreview(label, value, { collapseSource: true })
|
|
429
|
+
: renderTextCard(label, value);
|
|
423
430
|
}
|
|
424
431
|
return detailJson(value, label);
|
|
425
432
|
};
|
|
@@ -459,6 +466,17 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
459
466
|
return '<div class="summary">' + summary + '</div><div class="summary-sub">' + escapeHtml(secondary) + '</div>';
|
|
460
467
|
};
|
|
461
468
|
|
|
469
|
+
const entrySummaryInlineHtml = (entry) => {
|
|
470
|
+
const summary = escapeHtml(entrySummaryText(entry) || 'No summary available');
|
|
471
|
+
const secondary = [
|
|
472
|
+
entry.type === 'request' ? 'Incoming request' : '',
|
|
473
|
+
entry.type === 'query' ? 'Database query' : '',
|
|
474
|
+
entry.type === 'exception' ? 'Unhandled error' : '',
|
|
475
|
+
entry.type === 'client_request' ? 'Outbound HTTP call' : ''
|
|
476
|
+
].find(Boolean) || 'Trace record';
|
|
477
|
+
return '<span class="summary">' + summary + '</span><span class="summary-sub">' + escapeHtml(secondary) + '</span>';
|
|
478
|
+
};
|
|
479
|
+
|
|
462
480
|
const renderMetricBox = (title, items) => {
|
|
463
481
|
return [
|
|
464
482
|
'<section class="detail-box">',
|
|
@@ -583,8 +601,8 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
583
601
|
]),
|
|
584
602
|
'</div>',
|
|
585
603
|
'<div class="detail-stack">',
|
|
586
|
-
renderPayload('Mail Text', content.text),
|
|
587
604
|
renderPayload('Mail Html', content.html),
|
|
605
|
+
renderPayload('Mail Text', content.text),
|
|
588
606
|
'</div>'
|
|
589
607
|
].join('');
|
|
590
608
|
}
|
|
@@ -609,10 +627,31 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
609
627
|
return detailJson(content);
|
|
610
628
|
};
|
|
611
629
|
|
|
612
|
-
const renderTraceItems = (entries) => {
|
|
630
|
+
const renderTraceItems = (entries, options = {}) => {
|
|
613
631
|
if (entries.length === 0) return '<p class="trace-note">No related entries captured.</p>';
|
|
614
632
|
|
|
633
|
+
const collapsible = options.collapsible === true;
|
|
634
|
+
const isInitiallyOpen = options.collapsed !== true;
|
|
635
|
+
|
|
615
636
|
return '<div class="trace-panel">' + entries.map((entry) => {
|
|
637
|
+
if (collapsible) {
|
|
638
|
+
return [
|
|
639
|
+
'<details class="trace-item trace-disclosure"' + (isInitiallyOpen ? ' open' : '') + '>',
|
|
640
|
+
'<summary class="trace-item-head trace-summary">',
|
|
641
|
+
'<span class="trace-summary-main">',
|
|
642
|
+
'<span><span class="' + typeClass(entry) + '">' + escapeHtml(entry.type) + '</span></span>',
|
|
643
|
+
'<span class="trace-summary-copy">' + entrySummaryInlineHtml(entry) + '</span>',
|
|
644
|
+
'</span>',
|
|
645
|
+
'<span class="activity-head">' + durationHtml(entry) + '<span class="activity-time">' + escapeHtml(timeSince(entry.createdAt)) + '</span></span>',
|
|
646
|
+
'</summary>',
|
|
647
|
+
'<div class="trace-disclosure-body">',
|
|
648
|
+
'<div>' + tagsHtml(entry.tags) + '</div>',
|
|
649
|
+
renderEntryBody(entry),
|
|
650
|
+
'</div>',
|
|
651
|
+
'</details>'
|
|
652
|
+
].join('');
|
|
653
|
+
}
|
|
654
|
+
|
|
616
655
|
return [
|
|
617
656
|
'<section class="trace-item">',
|
|
618
657
|
'<div class="trace-item-head">',
|
|
@@ -671,7 +710,7 @@ const DASHBOARD_DOCUMENT = String.raw`<!DOCTYPE html>
|
|
|
671
710
|
payload: detailJson(content.payload || {}, 'Payload Json'),
|
|
672
711
|
headers: '<div class="detail-stack">' + detailJson(content.headers || {}, 'Request Header Json') + detailJson(content.responseHeaders || {}, 'Response Header Json') + '</div>',
|
|
673
712
|
response: '<div class="detail-stack"><div class="detail-grid">' + renderMetricBox('Status', [{ label: 'Response status', value: escapeHtml(content.responseStatus || '') }, { label: 'Duration', value: escapeHtml(formatDuration(getEntryDuration(entry))) }]) + '</div>' + (content.responseBody === undefined ? '<p class="trace-note">No response body was captured for this request.</p>' : detailJson(content.responseBody, 'Response Body Json')) + detailJson(content.responseHeaders || {}, 'Response Header Json') + '</div>',
|
|
674
|
-
queries: renderTraceItems(batchEntriesByType('query')),
|
|
713
|
+
queries: renderTraceItems(batchEntriesByType('query'), { collapsible: true, collapsed: true }),
|
|
675
714
|
logs: renderTraceItems(batchEntriesByType('log')),
|
|
676
715
|
exceptions: renderTraceItems(batchEntriesByType('exception')),
|
|
677
716
|
http: renderTraceItems(batchEntriesByType('client_request')),
|
package/src/register.ts
CHANGED
|
@@ -64,6 +64,9 @@ type CoreApi = {
|
|
|
64
64
|
Logger?: {
|
|
65
65
|
warn(message: string, context?: Record<string, unknown>): void;
|
|
66
66
|
};
|
|
67
|
+
ErrorFactory?: {
|
|
68
|
+
createConfigError(message: string, details?: unknown): Error;
|
|
69
|
+
};
|
|
67
70
|
StartupConfigFile?: {
|
|
68
71
|
Trace?: string;
|
|
69
72
|
};
|
|
@@ -72,6 +75,14 @@ type CoreApi = {
|
|
|
72
75
|
};
|
|
73
76
|
};
|
|
74
77
|
|
|
78
|
+
type CoreDatabase = import('@zintrust/core').IDatabase;
|
|
79
|
+
|
|
80
|
+
const TRACE_REQUIRED_TABLES = [
|
|
81
|
+
'zin_trace_entries',
|
|
82
|
+
'zin_trace_entries_tags',
|
|
83
|
+
'zin_trace_monitoring',
|
|
84
|
+
] as const;
|
|
85
|
+
|
|
75
86
|
type GlobalMiddlewareRegistrarState = {
|
|
76
87
|
__zintrust_register_global_middleware__?: ITraceWatcherConfig['registerMiddleware'];
|
|
77
88
|
__zintrust_pending_global_middlewares__?: Array<
|
|
@@ -125,7 +136,7 @@ const resolveObservedConnectionName = (
|
|
|
125
136
|
return resolveTraceConnectionName(env, configuredObservedConnection);
|
|
126
137
|
}
|
|
127
138
|
|
|
128
|
-
const defaultConnectionName = resolveTraceConnectionName(env
|
|
139
|
+
const defaultConnectionName = resolveTraceConnectionName(env);
|
|
129
140
|
if (storageConnectionName !== defaultConnectionName) {
|
|
130
141
|
return defaultConnectionName;
|
|
131
142
|
}
|
|
@@ -217,6 +228,71 @@ const buildTraceRedactionOverrides = (input: {
|
|
|
217
228
|
: undefined;
|
|
218
229
|
};
|
|
219
230
|
|
|
231
|
+
const createTraceConfigError = (coreApi: CoreApi, message: string, details?: unknown): Error => {
|
|
232
|
+
if (coreApi.ErrorFactory?.createConfigError !== undefined) {
|
|
233
|
+
return coreApi.ErrorFactory.createConfigError(message, details);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const error = new globalThis.Error(message) as Error & {
|
|
237
|
+
code?: string;
|
|
238
|
+
details?: unknown;
|
|
239
|
+
name?: string;
|
|
240
|
+
statusCode?: number;
|
|
241
|
+
};
|
|
242
|
+
error.name = 'ConfigError';
|
|
243
|
+
error.code = 'CONFIG_ERROR';
|
|
244
|
+
error.statusCode = 500;
|
|
245
|
+
error.details = details;
|
|
246
|
+
return error;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
function assertTraceConnectionResolved(
|
|
250
|
+
coreApi: CoreApi,
|
|
251
|
+
db: CoreDatabase | undefined,
|
|
252
|
+
params: { connectionName: string; envKey: 'TRACE_DB_CONNECTION' | 'TRACE_QUERY_CONNECTION' }
|
|
253
|
+
): asserts db is CoreDatabase {
|
|
254
|
+
if (db !== undefined) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
throw createTraceConfigError(
|
|
259
|
+
coreApi,
|
|
260
|
+
`Trace connection "${params.connectionName}" could not be resolved.`,
|
|
261
|
+
{
|
|
262
|
+
connectionName: params.connectionName,
|
|
263
|
+
envKey: params.envKey,
|
|
264
|
+
hint:
|
|
265
|
+
params.envKey === 'TRACE_DB_CONNECTION'
|
|
266
|
+
? 'Configure TRACE_DB_CONNECTION to an existing database connection before enabling TRACE_ENABLED.'
|
|
267
|
+
: 'Configure TRACE_QUERY_CONNECTION, or ensure DB_CONNECTION resolves to an existing database connection.',
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const assertTraceStorageReady = async (
|
|
273
|
+
coreApi: CoreApi,
|
|
274
|
+
db: CoreDatabase,
|
|
275
|
+
connectionName: string
|
|
276
|
+
): Promise<void> => {
|
|
277
|
+
try {
|
|
278
|
+
await Promise.all(
|
|
279
|
+
TRACE_REQUIRED_TABLES.map(async (table) => {
|
|
280
|
+
await db.queryOne(`SELECT 1 AS ok FROM ${table} LIMIT 1`, []);
|
|
281
|
+
})
|
|
282
|
+
);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
throw createTraceConfigError(
|
|
285
|
+
coreApi,
|
|
286
|
+
`Trace storage connection "${connectionName}" is not ready. Create the database if needed and run \`zin migrate:trace\` before enabling TRACE_ENABLED.`,
|
|
287
|
+
{
|
|
288
|
+
connectionName,
|
|
289
|
+
error,
|
|
290
|
+
requiredTables: [...TRACE_REQUIRED_TABLES],
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
220
296
|
const core = (await importCore()) as CoreApi;
|
|
221
297
|
const Env = core.Env;
|
|
222
298
|
const startupOverrides = resolveTraceStartupOverrides(core);
|
|
@@ -292,98 +368,103 @@ if (!traceAlreadyInitialized && Env) {
|
|
|
292
368
|
const storageDb = core.useDatabase?.(undefined, resolvedConnectionName);
|
|
293
369
|
const observedDb = core.useDatabase?.(undefined, resolvedObservedConnectionName);
|
|
294
370
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
);
|
|
371
|
+
assertTraceConnectionResolved(core, storageDb, {
|
|
372
|
+
connectionName: resolvedConnectionName,
|
|
373
|
+
envKey: 'TRACE_DB_CONNECTION',
|
|
374
|
+
});
|
|
375
|
+
assertTraceConnectionResolved(core, observedDb, {
|
|
376
|
+
connectionName: resolvedObservedConnectionName,
|
|
377
|
+
envKey: 'TRACE_QUERY_CONNECTION',
|
|
378
|
+
});
|
|
379
|
+
await assertTraceStorageReady(core, storageDb, resolvedConnectionName);
|
|
380
|
+
|
|
381
|
+
const storage = TraceWriteDiagnostics.wrapStorage(
|
|
382
|
+
TraceContentRedaction.wrapStorage(
|
|
383
|
+
TraceEntryFiltering.wrapStorage(TraceStorage.resolveStorage(storageDb), config),
|
|
384
|
+
config.redaction
|
|
385
|
+
),
|
|
386
|
+
{
|
|
387
|
+
connectionName: resolvedConnectionName,
|
|
388
|
+
logger: core.Logger,
|
|
314
389
|
}
|
|
390
|
+
);
|
|
315
391
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
{ ScheduleWatcher },
|
|
324
|
-
{ MailWatcher },
|
|
325
|
-
{ AuthWatcher },
|
|
326
|
-
{ EventWatcher },
|
|
327
|
-
{ ModelWatcher },
|
|
328
|
-
{ NotificationWatcher },
|
|
329
|
-
{ RedisWatcher },
|
|
330
|
-
{ GateWatcher },
|
|
331
|
-
{ MiddlewareWatcher },
|
|
332
|
-
{ CommandWatcher },
|
|
333
|
-
{ BatchWatcher },
|
|
334
|
-
{ DumpWatcher },
|
|
335
|
-
{ ViewWatcher },
|
|
336
|
-
{ HttpClientWatcher },
|
|
337
|
-
] = await Promise.all([
|
|
338
|
-
import('./watchers/HttpWatcher'),
|
|
339
|
-
import('./watchers/QueryWatcher'),
|
|
340
|
-
import('./watchers/LogWatcher'),
|
|
341
|
-
import('./watchers/ExceptionWatcher'),
|
|
342
|
-
import('./watchers/JobWatcher'),
|
|
343
|
-
import('./watchers/CacheWatcher'),
|
|
344
|
-
import('./watchers/ScheduleWatcher'),
|
|
345
|
-
import('./watchers/MailWatcher'),
|
|
346
|
-
import('./watchers/AuthWatcher'),
|
|
347
|
-
import('./watchers/EventWatcher'),
|
|
348
|
-
import('./watchers/ModelWatcher'),
|
|
349
|
-
import('./watchers/NotificationWatcher'),
|
|
350
|
-
import('./watchers/RedisWatcher'),
|
|
351
|
-
import('./watchers/GateWatcher'),
|
|
352
|
-
import('./watchers/MiddlewareWatcher'),
|
|
353
|
-
import('./watchers/CommandWatcher'),
|
|
354
|
-
import('./watchers/BatchWatcher'),
|
|
355
|
-
import('./watchers/DumpWatcher'),
|
|
356
|
-
import('./watchers/ViewWatcher'),
|
|
357
|
-
import('./watchers/HttpClientWatcher'),
|
|
358
|
-
]);
|
|
359
|
-
|
|
360
|
-
const watcherArgs = { storage, config, db: observedDb };
|
|
361
|
-
|
|
362
|
-
HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
|
|
363
|
-
|
|
364
|
-
QueryWatcher.register(watcherArgs);
|
|
365
|
-
LogWatcher.register(watcherArgs);
|
|
366
|
-
ExceptionWatcher.register(watcherArgs);
|
|
367
|
-
JobWatcher.register(watcherArgs);
|
|
368
|
-
CacheWatcher.register(watcherArgs);
|
|
369
|
-
ScheduleWatcher.register(watcherArgs);
|
|
370
|
-
MailWatcher.register(watcherArgs);
|
|
371
|
-
AuthWatcher.register(watcherArgs);
|
|
372
|
-
EventWatcher.register(watcherArgs);
|
|
373
|
-
ModelWatcher.register(watcherArgs);
|
|
374
|
-
NotificationWatcher.register(watcherArgs);
|
|
375
|
-
RedisWatcher.register(watcherArgs);
|
|
376
|
-
GateWatcher.register(watcherArgs);
|
|
377
|
-
MiddlewareWatcher.register(watcherArgs);
|
|
378
|
-
CommandWatcher.register(watcherArgs);
|
|
379
|
-
BatchWatcher.register(watcherArgs);
|
|
380
|
-
DumpWatcher.register(watcherArgs);
|
|
381
|
-
ViewWatcher.register(watcherArgs);
|
|
382
|
-
HttpClientWatcher.register(watcherArgs);
|
|
383
|
-
} else {
|
|
384
|
-
// eslint-disable-next-line no-console
|
|
385
|
-
console.warn('[trace] Could not resolve database connection - skipping init.');
|
|
392
|
+
if (core.RequestContext) {
|
|
393
|
+
TraceContext.setRequestContextImpl(
|
|
394
|
+
core.RequestContext as {
|
|
395
|
+
current?: () => unknown;
|
|
396
|
+
peek?: () => unknown;
|
|
397
|
+
}
|
|
398
|
+
);
|
|
386
399
|
}
|
|
400
|
+
|
|
401
|
+
const [
|
|
402
|
+
{ HttpWatcher },
|
|
403
|
+
{ QueryWatcher },
|
|
404
|
+
{ LogWatcher },
|
|
405
|
+
{ ExceptionWatcher },
|
|
406
|
+
{ JobWatcher },
|
|
407
|
+
{ CacheWatcher },
|
|
408
|
+
{ ScheduleWatcher },
|
|
409
|
+
{ MailWatcher },
|
|
410
|
+
{ AuthWatcher },
|
|
411
|
+
{ EventWatcher },
|
|
412
|
+
{ ModelWatcher },
|
|
413
|
+
{ NotificationWatcher },
|
|
414
|
+
{ RedisWatcher },
|
|
415
|
+
{ GateWatcher },
|
|
416
|
+
{ MiddlewareWatcher },
|
|
417
|
+
{ CommandWatcher },
|
|
418
|
+
{ BatchWatcher },
|
|
419
|
+
{ DumpWatcher },
|
|
420
|
+
{ ViewWatcher },
|
|
421
|
+
{ HttpClientWatcher },
|
|
422
|
+
] = await Promise.all([
|
|
423
|
+
import('./watchers/HttpWatcher'),
|
|
424
|
+
import('./watchers/QueryWatcher'),
|
|
425
|
+
import('./watchers/LogWatcher'),
|
|
426
|
+
import('./watchers/ExceptionWatcher'),
|
|
427
|
+
import('./watchers/JobWatcher'),
|
|
428
|
+
import('./watchers/CacheWatcher'),
|
|
429
|
+
import('./watchers/ScheduleWatcher'),
|
|
430
|
+
import('./watchers/MailWatcher'),
|
|
431
|
+
import('./watchers/AuthWatcher'),
|
|
432
|
+
import('./watchers/EventWatcher'),
|
|
433
|
+
import('./watchers/ModelWatcher'),
|
|
434
|
+
import('./watchers/NotificationWatcher'),
|
|
435
|
+
import('./watchers/RedisWatcher'),
|
|
436
|
+
import('./watchers/GateWatcher'),
|
|
437
|
+
import('./watchers/MiddlewareWatcher'),
|
|
438
|
+
import('./watchers/CommandWatcher'),
|
|
439
|
+
import('./watchers/BatchWatcher'),
|
|
440
|
+
import('./watchers/DumpWatcher'),
|
|
441
|
+
import('./watchers/ViewWatcher'),
|
|
442
|
+
import('./watchers/HttpClientWatcher'),
|
|
443
|
+
]);
|
|
444
|
+
|
|
445
|
+
const watcherArgs = { storage, config, db: observedDb };
|
|
446
|
+
|
|
447
|
+
HttpWatcher.register({ ...watcherArgs, registerMiddleware: resolveRegisterMiddleware() });
|
|
448
|
+
|
|
449
|
+
QueryWatcher.register(watcherArgs);
|
|
450
|
+
LogWatcher.register(watcherArgs);
|
|
451
|
+
ExceptionWatcher.register(watcherArgs);
|
|
452
|
+
JobWatcher.register(watcherArgs);
|
|
453
|
+
CacheWatcher.register(watcherArgs);
|
|
454
|
+
ScheduleWatcher.register(watcherArgs);
|
|
455
|
+
MailWatcher.register(watcherArgs);
|
|
456
|
+
AuthWatcher.register(watcherArgs);
|
|
457
|
+
EventWatcher.register(watcherArgs);
|
|
458
|
+
ModelWatcher.register(watcherArgs);
|
|
459
|
+
NotificationWatcher.register(watcherArgs);
|
|
460
|
+
RedisWatcher.register(watcherArgs);
|
|
461
|
+
GateWatcher.register(watcherArgs);
|
|
462
|
+
MiddlewareWatcher.register(watcherArgs);
|
|
463
|
+
CommandWatcher.register(watcherArgs);
|
|
464
|
+
BatchWatcher.register(watcherArgs);
|
|
465
|
+
DumpWatcher.register(watcherArgs);
|
|
466
|
+
ViewWatcher.register(watcherArgs);
|
|
467
|
+
HttpClientWatcher.register(watcherArgs);
|
|
387
468
|
}
|
|
388
469
|
} else if (!traceAlreadyInitialized) {
|
|
389
470
|
// Running outside a ZinTrust project - skip init silently.
|
|
@@ -21,8 +21,50 @@ const TRACE_INFRASTRUCTURE_LOG_MESSAGES = new Set<string>([
|
|
|
21
21
|
'[trace] Trace storage write degraded',
|
|
22
22
|
]);
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
|
|
24
|
+
const TRACE_STORAGE_TABLE_NAMES = [
|
|
25
|
+
'zin_trace_entries',
|
|
26
|
+
'zin_trace_entries_tags',
|
|
27
|
+
'zin_trace_monitoring',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const isTraceStorageQuery = (sql: string): boolean => {
|
|
31
|
+
const normalized = sql.toLowerCase();
|
|
32
|
+
return TRACE_STORAGE_TABLE_NAMES.some((tableName) => normalized.includes(tableName));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const extractSqlFromLog = (
|
|
36
|
+
message: string,
|
|
37
|
+
context?: Record<string, unknown>
|
|
38
|
+
): string | undefined => {
|
|
39
|
+
const contextSql = context?.['sql'];
|
|
40
|
+
if (typeof contextSql === 'string') return contextSql;
|
|
41
|
+
|
|
42
|
+
const trimmed = message.trim();
|
|
43
|
+
const rawPrefix = 'Raw SQL Query executed:';
|
|
44
|
+
if (trimmed.startsWith(rawPrefix)) {
|
|
45
|
+
const sql = trimmed.slice(rawPrefix.length).trim();
|
|
46
|
+
return sql === '' ? undefined : sql;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return undefined;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const isTraceStorageQueryLog = (message: string, context?: Record<string, unknown>): boolean => {
|
|
53
|
+
const normalizedMessage = message.trim().toLowerCase();
|
|
54
|
+
if (!normalizedMessage.includes('query executed')) return false;
|
|
55
|
+
|
|
56
|
+
const sql = extractSqlFromLog(message, context);
|
|
57
|
+
return typeof sql === 'string' && isTraceStorageQuery(sql);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const shouldSkipTraceInfrastructureLog = (
|
|
61
|
+
message: string,
|
|
62
|
+
context?: Record<string, unknown>
|
|
63
|
+
): boolean => {
|
|
64
|
+
return (
|
|
65
|
+
TRACE_INFRASTRUCTURE_LOG_MESSAGES.has(message.trim()) ||
|
|
66
|
+
isTraceStorageQueryLog(message, context)
|
|
67
|
+
);
|
|
26
68
|
};
|
|
27
69
|
|
|
28
70
|
export const LogWatcher: ITraceWatcher = Object.freeze({
|
|
@@ -41,7 +83,7 @@ export const LogWatcher: ITraceWatcher = Object.freeze({
|
|
|
41
83
|
(level: string, message: string, context?: Record<string, unknown>) => {
|
|
42
84
|
if ((LEVEL_PRIORITY[level] ?? 0) < minPriority) return;
|
|
43
85
|
if (RequestFilter.shouldIgnoreCurrentRequest(config.ignoreRoutes)) return;
|
|
44
|
-
if (shouldSkipTraceInfrastructureLog(message)) return;
|
|
86
|
+
if (shouldSkipTraceInfrastructureLog(message, context)) return;
|
|
45
87
|
|
|
46
88
|
const content: LogContent = {
|
|
47
89
|
level,
|
|
@@ -24,7 +24,11 @@ const bindingsInterpolated = (sql: string, params: unknown[]): string => {
|
|
|
24
24
|
|
|
25
25
|
const isTraceStorageQuery = (sql: string): boolean => {
|
|
26
26
|
const normalized = sql.toLowerCase();
|
|
27
|
-
return
|
|
27
|
+
return (
|
|
28
|
+
normalized.includes('zin_trace_entries') ||
|
|
29
|
+
normalized.includes('zin_trace_entries_tags') ||
|
|
30
|
+
normalized.includes('zin_trace_monitoring')
|
|
31
|
+
);
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
const emit = (query: string, params: unknown[], duration: number, connection = 'default'): void => {
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TraceStorage — sealed namespace wrapping the D1/SQLite driver.
|
|
3
|
-
* Resolves the correct IDatabase from the app config, then delegates all
|
|
4
|
-
* read/write operations to the trace storage facade.
|
|
5
|
-
*/
|
|
6
|
-
import type { IDatabase } from '@zintrust/core';
|
|
7
|
-
import type { ITraceStorage } from '../types';
|
|
8
|
-
export declare const TraceStorage: Readonly<{
|
|
9
|
-
resolveStorage: (db: IDatabase) => ITraceStorage;
|
|
10
|
-
reset: () => void;
|
|
11
|
-
familyHash: (input: string) => string;
|
|
12
|
-
}>;
|
|
13
|
-
export { type ITraceStorage } from '../types';
|