@beignet/devtools 0.0.2 → 0.0.4
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/CHANGELOG.md +97 -0
- package/README.md +117 -71
- package/dist/events.d.ts +16 -4
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +1 -0
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +13 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -13
- package/dist/index.js.map +1 -1
- package/dist/persistence.d.ts +1 -1
- package/dist/persistence.d.ts.map +1 -1
- package/dist/provider-instrumentation.d.ts +1 -1
- package/dist/provider-instrumentation.d.ts.map +1 -1
- package/dist/provider.d.ts +5 -5
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +10 -5
- package/dist/provider.js.map +1 -1
- package/dist/redaction.d.ts +1 -1
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +1 -0
- package/dist/redaction.js.map +1 -1
- package/dist/routes.d.ts +2 -2
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +3 -3
- package/dist/routes.js.map +1 -1
- package/dist/ui-model.d.ts +38 -0
- package/dist/ui-model.d.ts.map +1 -0
- package/dist/ui-model.js +1039 -0
- package/dist/ui-model.js.map +1 -0
- package/dist/ui.d.ts +1 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +314 -163
- package/dist/ui.js.map +1 -1
- package/dist/watchers.d.ts +2 -2
- package/dist/watchers.d.ts.map +1 -1
- package/dist/watchers.js +18 -2
- package/dist/watchers.js.map +1 -1
- package/package.json +22 -2
- package/src/events.ts +32 -2
- package/src/index.ts +13 -15
- package/src/persistence.ts +1 -1
- package/src/provider-instrumentation.ts +1 -1
- package/src/provider.ts +12 -7
- package/src/redaction.ts +2 -1
- package/src/routes.ts +4 -4
- package/src/ui-model.ts +1233 -0
- package/src/ui.ts +314 -163
- package/src/watchers.ts +20 -3
- package/dist/audit.d.ts +0 -31
- package/dist/audit.d.ts.map +0 -1
- package/dist/audit.js +0 -55
- package/dist/audit.js.map +0 -1
- package/dist/instrumentation.d.ts +0 -114
- package/dist/instrumentation.d.ts.map +0 -1
- package/dist/instrumentation.js +0 -303
- package/dist/instrumentation.js.map +0 -1
- package/dist/trace-context.d.ts +0 -80
- package/dist/trace-context.d.ts.map +0 -1
- package/dist/trace-context.js +0 -92
- package/dist/trace-context.js.map +0 -1
- package/src/audit.ts +0 -92
- package/src/instrumentation.ts +0 -491
- package/src/trace-context.ts +0 -166
package/src/ui.ts
CHANGED
|
@@ -2,7 +2,8 @@ import {
|
|
|
2
2
|
type DevtoolsRouteAccessOptions,
|
|
3
3
|
devtoolsNotFoundResponse,
|
|
4
4
|
isDevtoolsRouteEnabled,
|
|
5
|
-
} from "./access";
|
|
5
|
+
} from "./access.js";
|
|
6
|
+
import { devtoolsPanelModelBrowserSource } from "./ui-model.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Devtools UI handler
|
|
@@ -98,6 +99,22 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
98
99
|
.detail-title{color:var(--text);font-family:var(--font-sans);font-size:12px;font-weight:650;margin-bottom:6px}
|
|
99
100
|
.correlated{display:flex;flex-direction:column;gap:6px}
|
|
100
101
|
.correlated-row{display:flex;gap:7px;align-items:flex-start;color:var(--text-muted)}
|
|
102
|
+
.request-map{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-bottom:12px}
|
|
103
|
+
.request-fact{border:1px solid var(--border);border-radius:7px;background:var(--surface);padding:9px 10px;min-width:0}
|
|
104
|
+
.request-fact-label{font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.1em}
|
|
105
|
+
.request-fact-value{font-family:var(--font-mono);font-size:12px;color:var(--text);margin-top:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
106
|
+
.detail-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-bottom:10px}
|
|
107
|
+
.lifecycle{display:flex;flex-direction:column;gap:7px}
|
|
108
|
+
.phase-row{display:grid;grid-template-columns:108px minmax(130px,.8fr) minmax(180px,1.2fr) 92px;gap:8px;align-items:start;border:1px solid var(--border);border-radius:7px;background:var(--bg);padding:8px}
|
|
109
|
+
.phase-name{font-family:var(--font-mono);font-size:11px;color:var(--text)}
|
|
110
|
+
.phase-summary{color:var(--text-muted);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
111
|
+
.phase-meta{font-family:var(--font-mono);font-size:10px;color:var(--text-dim)}
|
|
112
|
+
.owner-pill{display:inline-block;border:1px solid var(--border);border-radius:999px;background:var(--surface-2);color:var(--text-muted);font-family:var(--font-mono);font-size:10px;padding:2px 6px;line-height:1.4}
|
|
113
|
+
.owner-framework,.owner-provider,.owner-devtools{color:var(--red);background:#fff1f2;border-color:#ffe4e6}
|
|
114
|
+
.owner-route{color:var(--green);background:#ecfdf5;border-color:#d1fae5}
|
|
115
|
+
.owner-transport,.owner-client{color:var(--blue);background:#eff6ff;border-color:#dbeafe}
|
|
116
|
+
.owner-job,.owner-schedule,.owner-outbox{color:var(--orange);background:#fff7ed;border-color:#fed7aa}
|
|
117
|
+
.redaction-note{border:1px solid var(--border);border-radius:7px;background:var(--surface);padding:8px 10px;color:var(--text-muted);font-size:12px;margin-top:8px}
|
|
101
118
|
.focus-panel{display:flex;flex-direction:column}
|
|
102
119
|
.focus-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:14px;border-bottom:1px solid var(--border);background:var(--bg)}
|
|
103
120
|
.focus-title{font-size:15px;line-height:1.2;font-weight:720;color:var(--text)}
|
|
@@ -107,7 +124,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
107
124
|
.focus-metric-label{font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.1em}
|
|
108
125
|
.focus-metric-value{font-family:var(--font-mono);font-size:15px;color:var(--text);margin-top:3px}
|
|
109
126
|
.event-table{display:flex;flex-direction:column}
|
|
110
|
-
.table-row{display:grid;grid-template-columns:86px minmax(140px,.
|
|
127
|
+
.table-row{display:grid;grid-template-columns:86px minmax(140px,.8fr) minmax(210px,1.2fr) minmax(130px,.8fr) 78px 104px;gap:10px;align-items:start;padding:11px 14px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .1s}
|
|
111
128
|
.table-row:last-child{border-bottom:0}
|
|
112
129
|
.table-row:hover{background:var(--surface)}
|
|
113
130
|
.table-row.open{background:#f8fafc}
|
|
@@ -115,8 +132,31 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
115
132
|
.table-cell strong{display:block;color:var(--text);font-size:13px;font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
116
133
|
.table-cell code{font-family:var(--font-mono);font-size:11px;color:var(--text-muted);background:var(--surface-2);border:1px solid var(--border);border-radius:4px;padding:1px 4px}
|
|
117
134
|
.table-summary{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
135
|
+
.table-correlation{display:flex;flex-wrap:wrap;gap:4px}
|
|
136
|
+
.table-empty{font-family:var(--font-mono);font-size:10px;color:var(--text-dim)}
|
|
118
137
|
.table-detail{display:none;grid-column:1/-1;margin-top:2px;padding-top:10px;border-top:1px solid var(--border);font-family:var(--font-mono);font-size:11px;color:var(--text-muted);line-height:1.7;white-space:pre-wrap;word-break:break-word}
|
|
119
138
|
.table-row.open .table-detail{display:block}
|
|
139
|
+
.table-detail-note{font-family:var(--font-sans);font-size:12px;color:var(--text-muted);margin-bottom:8px;white-space:normal}
|
|
140
|
+
.result-chip{display:inline-block;border:1px solid var(--border);border-radius:5px;background:var(--surface);font-family:var(--font-mono);font-size:10px;color:var(--text-muted);padding:2px 5px}
|
|
141
|
+
.result-failed,.result-blocked,.result-deadLettered{color:var(--red);background:#fff1f2;border-color:#ffe4e6}
|
|
142
|
+
.result-retryScheduled{color:var(--orange);background:#fff7ed;border-color:#fed7aa}
|
|
143
|
+
.result-delivered,.result-completed,.result-allowed,.result-hit,.result-signed_in{color:var(--green);background:#ecfdf5;border-color:#d1fae5}
|
|
144
|
+
.error-board{display:flex;flex-direction:column}
|
|
145
|
+
.error-owner-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;padding:14px;border-bottom:1px solid var(--border);background:var(--bg)}
|
|
146
|
+
.error-owner-card{border:1px solid var(--border);border-radius:7px;background:var(--surface);padding:9px 10px;min-width:0}
|
|
147
|
+
.error-owner-card strong{display:block;font-family:var(--font-mono);font-size:15px;color:var(--text)}
|
|
148
|
+
.error-owner-card span{display:block;color:var(--text-muted);font-size:10px;text-transform:uppercase;letter-spacing:.1em;margin-top:2px}
|
|
149
|
+
.error-group{border-bottom:1px solid var(--border)}
|
|
150
|
+
.error-group:last-child{border-bottom:0}
|
|
151
|
+
.error-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;background:var(--surface)}
|
|
152
|
+
.error-group-title{display:flex;align-items:center;gap:7px;font-size:13px;font-weight:700;color:var(--text)}
|
|
153
|
+
.error-group-count{font-family:var(--font-mono);font-size:11px;color:var(--text-muted)}
|
|
154
|
+
.error-row{display:grid;grid-template-columns:86px minmax(170px,1fr) 90px minmax(150px,.9fr) minmax(140px,.8fr);gap:10px;align-items:start;padding:11px 14px;border-top:1px solid var(--border);cursor:pointer;transition:background .1s}
|
|
155
|
+
.error-row:hover{background:var(--surface)}
|
|
156
|
+
.error-row.open{background:#f8fafc}
|
|
157
|
+
.error-message{min-width:0;color:var(--text);font-size:13px;font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
158
|
+
.error-context{font-family:var(--font-mono);font-size:11px;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
159
|
+
.error-related{display:flex;flex-direction:column;gap:5px;margin-top:8px}
|
|
120
160
|
.empty{text-align:center;padding:58px 16px;color:var(--text-dim);font-size:13px;background:var(--bg)}
|
|
121
161
|
.badge{display:inline-block;font-size:10px;font-weight:650;padding:2px 6px;border-radius:4px;text-transform:uppercase;letter-spacing:.06em;line-height:1.4;border:1px solid transparent}
|
|
122
162
|
.badge-request{background:#eff6ff;color:var(--blue);border-color:#dbeafe}
|
|
@@ -124,6 +164,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
124
164
|
.badge-usecase{background:#f5f3ff;color:var(--purple);border-color:#ede9fe}
|
|
125
165
|
.badge-eventBus{background:#ecfdf5;color:var(--green);border-color:#d1fae5}
|
|
126
166
|
.badge-job{background:#fff7ed;color:var(--orange);border-color:#fed7aa}
|
|
167
|
+
.badge-outbox{background:#fefce8;color:#a16207;border-color:#fef08a}
|
|
127
168
|
.badge-schedule{background:#f0f9ff;color:#0369a1;border-color:#bae6fd}
|
|
128
169
|
.badge-provider{background:#f8fafc;color:var(--gray);border-color:var(--border)}
|
|
129
170
|
.badge-custom{background:#f0fdfa;color:#0f766e;border-color:#ccfbf1}
|
|
@@ -135,6 +176,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
135
176
|
.badge-notifications{background:#f5f3ff;color:#6d28d9;border-color:#ddd6fe}
|
|
136
177
|
.badge-rateLimit{background:#fffbeb;color:#b45309;border-color:#fde68a}
|
|
137
178
|
.badge-storage{background:#f0fdf4;color:#15803d;border-color:#bbf7d0}
|
|
179
|
+
.badge-uploads{background:#f0f9ff;color:#0369a1;border-color:#bae6fd}
|
|
138
180
|
.request-id{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);padding:2px 5px;background:var(--surface-2);border:1px solid var(--border);border-radius:4px}
|
|
139
181
|
.trace-id{font-family:var(--font-mono);font-size:10px;color:var(--accent-strong);padding:2px 5px;background:#eef2ff;border:1px solid rgba(79,70,229,.16);border-radius:4px}
|
|
140
182
|
@media(max-width:760px){
|
|
@@ -149,9 +191,14 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
149
191
|
.event-time{min-width:0}
|
|
150
192
|
.event-summary{white-space:normal}
|
|
151
193
|
.request-detail{grid-template-columns:1fr}
|
|
194
|
+
.request-map{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
195
|
+
.detail-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
196
|
+
.phase-row{grid-template-columns:1fr;gap:5px}
|
|
152
197
|
.focus-head{flex-direction:column}
|
|
153
198
|
.focus-metrics{grid-template-columns:repeat(2,minmax(0,1fr));min-width:0;width:100%}
|
|
154
199
|
.table-row{grid-template-columns:1fr;gap:6px}
|
|
200
|
+
.error-owner-strip{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
201
|
+
.error-row{grid-template-columns:1fr;gap:6px}
|
|
155
202
|
.table-detail{grid-column:auto}
|
|
156
203
|
}
|
|
157
204
|
</style>
|
|
@@ -162,7 +209,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
162
209
|
<div>
|
|
163
210
|
<div class="brand"><span class="mark">B</span><span>Beignet</span></div>
|
|
164
211
|
<h1>Beignet <span>Devtools</span></h1>
|
|
165
|
-
<div class="subtitle">A local timeline for requests, use cases, errors, jobs, schedules, and provider activity.</div>
|
|
212
|
+
<div class="subtitle">A local timeline for requests, use cases, errors, jobs, outbox delivery, schedules, and provider activity.</div>
|
|
166
213
|
</div>
|
|
167
214
|
<div class="controls">
|
|
168
215
|
<span class="status"><span class="dot" id="statusDot"></span><span id="statusText">Connecting</span></span>
|
|
@@ -217,11 +264,13 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
217
264
|
{id:"errors",label:"Errors",type:"error",watcher:"errors"},
|
|
218
265
|
{id:"events",label:"Events",type:"eventBus",watcher:"eventBus"},
|
|
219
266
|
{id:"jobs",label:"Jobs",type:"job",watcher:"jobs"},
|
|
267
|
+
{id:"outbox",label:"Outbox",watcher:"outbox",watcherName:"outbox"},
|
|
220
268
|
{id:"schedules",label:"Schedules",type:"schedule",watcher:"schedules"},
|
|
221
269
|
{id:"providers",label:"Providers",type:"provider",watcher:"providers"},
|
|
222
270
|
{id:"db",label:"Database",type:"custom",watcher:"db",watcherName:"db"},
|
|
223
271
|
{id:"cache",label:"Cache",type:"custom",watcher:"cache",watcherName:"cache"},
|
|
224
272
|
{id:"storage",label:"Storage",type:"custom",watcher:"storage",watcherName:"storage"},
|
|
273
|
+
{id:"uploads",label:"Uploads",type:"custom",watcher:"uploads",watcherName:"uploads"},
|
|
225
274
|
{id:"mail",label:"Mail",type:"custom",watcher:"mail",watcherName:"mail"},
|
|
226
275
|
{id:"notifications",label:"Notifications",type:"custom",watcher:"notifications",watcherName:"notifications"},
|
|
227
276
|
{id:"auth",label:"Auth",type:"custom",watcher:"auth",watcherName:"auth"},
|
|
@@ -229,8 +278,9 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
229
278
|
{id:"rateLimit",label:"Rate limits",type:"custom",watcher:"rateLimit",watcherName:"rateLimit"},
|
|
230
279
|
{id:"custom",label:"Custom",type:"custom",watcher:"custom"}
|
|
231
280
|
];
|
|
232
|
-
const FOCUS_PANEL_TABS={events:true,jobs:true,schedules:true,db:true,cache:true,storage:true,mail:true,notifications:true,auth:true,audit:true,rateLimit:true};
|
|
233
|
-
const BUILT_IN_WATCHERS={requests:true,errors:true,useCases:true,eventBus:true,jobs:true,schedules:true,providers:true,db:true,cache:true,storage:true,mail:true,notifications:true,auth:true,audit:true,rateLimit:true,custom:true};
|
|
281
|
+
const FOCUS_PANEL_TABS={events:true,jobs:true,outbox:true,schedules:true,db:true,cache:true,storage:true,uploads:true,mail:true,notifications:true,auth:true,audit:true,rateLimit:true};
|
|
282
|
+
const BUILT_IN_WATCHERS={requests:true,errors:true,useCases:true,eventBus:true,jobs:true,outbox:true,schedules:true,providers:true,db:true,cache:true,storage:true,uploads:true,mail:true,notifications:true,auth:true,audit:true,rateLimit:true,custom:true};
|
|
283
|
+
const ERROR_OWNERS=["route","framework","provider","job","schedule","outbox","client","devtools","unknown"];
|
|
234
284
|
let events=[];
|
|
235
285
|
let watchers=[];
|
|
236
286
|
let activeTab=localStorage.getItem("beignet-devtools-tab")||"timeline";
|
|
@@ -297,6 +347,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
297
347
|
case "usecase": return e.name+" ("+e.phase+")"+(e.durationMs!==undefined?" "+e.durationMs+"ms":"");
|
|
298
348
|
case "eventBus": return e.eventName||"Domain event";
|
|
299
349
|
case "job": return e.jobName+" -> "+e.status;
|
|
350
|
+
case "outbox": return e.messageName+" ("+e.messageKind+") -> "+e.status;
|
|
300
351
|
case "schedule": return e.scheduleName+" -> "+e.status;
|
|
301
352
|
case "provider": return e.providerName+" -> "+e.action;
|
|
302
353
|
case "custom": return (e.label||e.name||"Custom event")+(e.summary?" - "+e.summary:"");
|
|
@@ -305,6 +356,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
305
356
|
}
|
|
306
357
|
|
|
307
358
|
function tabMatchesEvent(tab,event){
|
|
359
|
+
if(tab.id==="errors")return event.type==="error"||failureFor(event);
|
|
308
360
|
if(tab.type&&event.type!==tab.type)return false;
|
|
309
361
|
if(tab.watcherName&&event.watcher!==tab.watcherName)return false;
|
|
310
362
|
return true;
|
|
@@ -318,6 +370,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
318
370
|
case "usecase": return "useCases";
|
|
319
371
|
case "eventBus": return "eventBus";
|
|
320
372
|
case "job": return "jobs";
|
|
373
|
+
case "outbox": return "outbox";
|
|
321
374
|
case "schedule": return "schedules";
|
|
322
375
|
case "provider": return "providers";
|
|
323
376
|
case "custom": return "custom";
|
|
@@ -336,6 +389,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
336
389
|
case "notifications": return "notifications";
|
|
337
390
|
case "rateLimit": return "rate limit";
|
|
338
391
|
case "storage": return "storage";
|
|
392
|
+
case "uploads": return "uploads";
|
|
339
393
|
default: return "custom";
|
|
340
394
|
}
|
|
341
395
|
}
|
|
@@ -353,6 +407,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
353
407
|
case "notifications": return "notifications";
|
|
354
408
|
case "rateLimit": return "rateLimit";
|
|
355
409
|
case "storage": return "storage";
|
|
410
|
+
case "uploads": return "uploads";
|
|
356
411
|
default: return "custom";
|
|
357
412
|
}
|
|
358
413
|
}
|
|
@@ -393,6 +448,9 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
393
448
|
event.summary,
|
|
394
449
|
event.eventName,
|
|
395
450
|
event.jobName,
|
|
451
|
+
event.messageId,
|
|
452
|
+
event.messageKind,
|
|
453
|
+
event.messageName,
|
|
396
454
|
event.providerName,
|
|
397
455
|
event.action,
|
|
398
456
|
jsonSearch(event.details)
|
|
@@ -428,6 +486,164 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
428
486
|
});
|
|
429
487
|
}
|
|
430
488
|
|
|
489
|
+
function eventTimeValue(event){
|
|
490
|
+
const time=Date.parse(event.timestamp||"");
|
|
491
|
+
return Number.isFinite(time)?time:0;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function responseOwnerFor(event){
|
|
495
|
+
const details=detailsObject(event);
|
|
496
|
+
const response=details.response&&typeof details.response==="object"?details.response:{};
|
|
497
|
+
return event.responseOwner||event.owner||response.owner||"unknown";
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function ownerClass(owner){
|
|
501
|
+
return "owner-"+String(owner||"unknown").replace(/[^a-zA-Z0-9_-]/g,"");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function ownerPill(owner){
|
|
505
|
+
const value=owner||"unknown";
|
|
506
|
+
return '<span class="owner-pill '+esc(ownerClass(value))+'">'+esc(value)+'</span>';
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function categoryFor(event){
|
|
510
|
+
const watcher=inferredWatcher(event);
|
|
511
|
+
if(event.type==="request")return"HTTP";
|
|
512
|
+
if(event.type==="usecase")return"Use case";
|
|
513
|
+
if(event.type==="error")return"Error";
|
|
514
|
+
if(event.type==="provider")return"Provider";
|
|
515
|
+
if(event.type==="eventBus")return"Domain event";
|
|
516
|
+
if(event.type==="outbox")return"Outbox";
|
|
517
|
+
if(event.type==="job")return"Job";
|
|
518
|
+
if(event.type==="schedule")return"Schedule";
|
|
519
|
+
if(["db","cache","storage","uploads","mail","notifications","auth","audit","rateLimit"].indexOf(watcher)>=0)return"Provider work";
|
|
520
|
+
return watcher==="custom"?"Custom":"Provider work";
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function ownerForEvent(event){
|
|
524
|
+
if(event.owner)return event.owner;
|
|
525
|
+
const watcher=inferredWatcher(event);
|
|
526
|
+
if(event.type==="error")return responseOwnerFor(event);
|
|
527
|
+
if(event.type==="provider")return"provider";
|
|
528
|
+
if(event.type==="job")return"job";
|
|
529
|
+
if(event.type==="schedule")return"schedule";
|
|
530
|
+
if(event.type==="outbox")return"outbox";
|
|
531
|
+
if(["db","cache","storage","uploads","mail","notifications","auth","audit","rateLimit"].indexOf(watcher)>=0)return"provider";
|
|
532
|
+
if(event.type==="request")return responseOwnerFor(event);
|
|
533
|
+
return"route";
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function relatedEventsFor(event){
|
|
537
|
+
return events.filter(function(candidate){
|
|
538
|
+
if(candidate.id===event.id)return false;
|
|
539
|
+
if(event.traceId&&candidate.traceId===event.traceId)return true;
|
|
540
|
+
return Boolean(event.requestId)&&candidate.requestId===event.requestId;
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function requestForEvent(event){
|
|
545
|
+
return relatedEventsFor(event).filter(function(candidate){return candidate.type==="request"}).sort(function(a,b){return eventTimeValue(b)-eventTimeValue(a)})[0];
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function statusForEvent(event){
|
|
549
|
+
if(event.status!==undefined)return event.status;
|
|
550
|
+
const request=requestForEvent(event);
|
|
551
|
+
if(request&&request.status!==undefined)return request.status;
|
|
552
|
+
const details=detailsObject(event);
|
|
553
|
+
const response=details.response&&typeof details.response==="object"?details.response:{};
|
|
554
|
+
return response.status||"";
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function contractForEvent(event){
|
|
558
|
+
const request=requestForEvent(event);
|
|
559
|
+
return event.contractName||event.useCaseName||(request&&request.contractName)||"";
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function pathForEvent(event){
|
|
563
|
+
const request=requestForEvent(event);
|
|
564
|
+
return event.path||(request&&request.path)||"";
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function correlationFor(event){
|
|
568
|
+
const rid=event.requestId?'<span class="request-id">'+esc(event.requestId)+'</span>':"";
|
|
569
|
+
const trace=event.traceId?'<span class="trace-id">trace '+esc(event.traceId.slice(0,8))+'</span>':"";
|
|
570
|
+
return rid+trace||'<span class="table-empty">n/a</span>';
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function unsafeMetadataPaths(value,path){
|
|
574
|
+
if(!value||typeof value!=="object")return[];
|
|
575
|
+
return Object.entries(value).flatMap(function(entry){
|
|
576
|
+
const key=entry[0];
|
|
577
|
+
const nested=entry[1];
|
|
578
|
+
const next=path.concat(key);
|
|
579
|
+
const lower=key.toLowerCase();
|
|
580
|
+
const sensitive=lower==="authorization"||lower==="cookie"||lower==="set-cookie"||lower.indexOf("token")>=0||lower.indexOf("password")>=0||lower.indexOf("secret")>=0||lower.indexOf("credential")>=0;
|
|
581
|
+
if(sensitive&&nested!=="[redacted]")return[next.join(".")];
|
|
582
|
+
return unsafeMetadataPaths(nested,next);
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function requestFact(label,value){
|
|
587
|
+
const display=value===undefined||value===null||value===""?"n/a":value;
|
|
588
|
+
return '<div class="request-fact"><div class="request-fact-label">'+esc(label)+'</div><div class="request-fact-value" title="'+esc(display)+'">'+esc(display)+'</div></div>';
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function detailGrid(items){
|
|
592
|
+
return '<div class="detail-grid">'+items.map(function(item){return requestFact(item[0],item[1])}).join("")+'</div>';
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function requestOverview(request,related){
|
|
596
|
+
return '<div class="request-map">'+
|
|
597
|
+
requestFact("Route",request.contractName||"unmatched")+
|
|
598
|
+
requestFact("Method",request.method||"")+
|
|
599
|
+
requestFact("Path",request.path||"")+
|
|
600
|
+
requestFact("Status",request.status||"")+
|
|
601
|
+
requestFact("Duration",request.durationMs!==undefined?request.durationMs+"ms":"")+
|
|
602
|
+
requestFact("Owner",responseOwnerFor(request))+
|
|
603
|
+
requestFact("Trace",request.traceId||"")+
|
|
604
|
+
requestFact("Related",related.length)+
|
|
605
|
+
'</div>';
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function requestLifecycleRows(request,related){
|
|
609
|
+
const rows=[request].concat(related).sort(function(a,b){return eventTimeValue(a)-eventTimeValue(b)});
|
|
610
|
+
return rows.map(function(event){
|
|
611
|
+
const duration=durationFor(event);
|
|
612
|
+
const durationLabel=duration===undefined?"":duration+"ms";
|
|
613
|
+
return '<div class="phase-row">'+
|
|
614
|
+
'<div>'+eventBadge(event)+'</div>'+
|
|
615
|
+
'<div><strong class="phase-name">'+esc(categoryFor(event))+'</strong><div class="phase-meta">'+esc(durationLabel||inferredWatcher(event))+'</div></div>'+
|
|
616
|
+
'<div class="phase-summary" title="'+esc(summarize(event))+'">'+esc(summarize(event))+'</div>'+
|
|
617
|
+
'<div>'+ownerPill(ownerForEvent(event))+'</div>'+
|
|
618
|
+
'</div>';
|
|
619
|
+
}).join("");
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function groupedRelatedRows(related){
|
|
623
|
+
const groups=["Use case","Provider work","Domain event","Outbox","Job","Schedule","Error","Provider","Custom"];
|
|
624
|
+
return groups.map(function(group){
|
|
625
|
+
const groupEvents=related.filter(function(event){return categoryFor(event)===group});
|
|
626
|
+
if(!groupEvents.length)return"";
|
|
627
|
+
const rows=groupEvents.slice().sort(function(a,b){return eventTimeValue(a)-eventTimeValue(b)}).map(function(event){
|
|
628
|
+
return '<div class="correlated-row">'+eventBadge(event)+'<span>'+esc(summarize(event))+'</span>'+ownerPill(ownerForEvent(event))+'</div>';
|
|
629
|
+
}).join("");
|
|
630
|
+
return '<section class="detail-section"><div class="detail-title">'+esc(group)+'</div><div class="correlated">'+rows+'</div></section>';
|
|
631
|
+
}).join("");
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function redactionNote(request,related){
|
|
635
|
+
const all=[request].concat(related);
|
|
636
|
+
const redacted=all.some(function(event){return hasRedactedValue(event)});
|
|
637
|
+
const unsafe=Array.from(new Set(all.flatMap(function(event){return unsafeMetadataPaths(event,[])}))).slice(0,4);
|
|
638
|
+
if(unsafe.length){
|
|
639
|
+
return '<div class="redaction-note">Unsafe-looking metadata keys remain visible: '+esc(unsafe.join(", "))+'</div>';
|
|
640
|
+
}
|
|
641
|
+
if(redacted){
|
|
642
|
+
return '<div class="redaction-note">Sensitive metadata was redacted before storage.</div>';
|
|
643
|
+
}
|
|
644
|
+
return '<div class="redaction-note">No redacted fields detected in the stored events for this request.</div>';
|
|
645
|
+
}
|
|
646
|
+
|
|
431
647
|
function updateStats(){
|
|
432
648
|
$statTotal.textContent=String(events.length);
|
|
433
649
|
$statRequests.textContent=String(events.filter(function(event){return event.type==="request"}).length);
|
|
@@ -500,178 +716,49 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
500
716
|
function renderRequests(list){
|
|
501
717
|
return list.slice().reverse().map(function(request){
|
|
502
718
|
const related=correlatedEvents(request);
|
|
503
|
-
const relatedHtml=related.length
|
|
504
|
-
? related.slice().reverse().map(function(event){
|
|
505
|
-
return '<div class="correlated-row">'+eventBadge(event)+'<span>'+esc(summarize(event))+'</span></div>';
|
|
506
|
-
}).join("")
|
|
507
|
-
: '<div class="empty">No correlated events for this request.</div>';
|
|
508
719
|
const detail='<div class="request-detail">'+
|
|
509
|
-
'<section class="detail-section"><div class="detail-title">Request</div
|
|
510
|
-
'<section class="detail-section"><div class="detail-title">Correlated
|
|
720
|
+
'<section class="detail-section"><div class="detail-title">Request lifecycle</div>'+requestOverview(request,related)+'<div class="lifecycle">'+requestLifecycleRows(request,related)+'</div>'+redactionNote(request,related)+'</section>'+
|
|
721
|
+
'<section class="detail-section"><div class="detail-title">Correlated activity</div>'+(related.length?groupedRelatedRows(related):'<div class="empty">No correlated events for this request.</div>')+'<pre>'+json(request)+'</pre></section>'+
|
|
511
722
|
'</div>';
|
|
512
723
|
return eventRow(request,detail);
|
|
513
724
|
}).join("");
|
|
514
725
|
}
|
|
515
726
|
|
|
516
|
-
function detailsObject(event){
|
|
517
|
-
return event.details&&typeof event.details==="object"&&!Array.isArray(event.details)?event.details:{};
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
function detailValue(event,key){
|
|
521
|
-
return detailsObject(event)[key];
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function durationFor(event){
|
|
525
|
-
const detailDuration=detailValue(event,"durationMs");
|
|
526
|
-
const duration=event.durationMs!==undefined?event.durationMs:detailDuration;
|
|
527
|
-
return typeof duration==="number"&&Number.isFinite(duration)?duration:undefined;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function providerFor(event){
|
|
531
|
-
const details=detailsObject(event);
|
|
532
|
-
return details.providerName||details.provider||details.portName||"";
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
function failureFor(event){
|
|
536
|
-
const details=detailsObject(event);
|
|
537
|
-
if(event.type==="error")return true;
|
|
538
|
-
if(typeof event.status==="string")return event.status==="failed";
|
|
539
|
-
if(typeof event.name==="string"&&event.name.indexOf("failed")>=0)return true;
|
|
540
|
-
return Boolean(details.error)||details.allowed===false;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
function averageDuration(list){
|
|
544
|
-
const durations=list.map(durationFor).filter(function(value){return value!==undefined});
|
|
545
|
-
if(!durations.length)return "n/a";
|
|
546
|
-
const total=durations.reduce(function(sum,value){return sum+value},0);
|
|
547
|
-
return Math.round(total/durations.length)+"ms";
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
function distinctCount(list,selector){
|
|
551
|
-
const values=new Set();
|
|
552
|
-
list.forEach(function(event){
|
|
553
|
-
const value=selector(event);
|
|
554
|
-
if(value!==undefined&&value!==null&&String(value)!=="")values.add(String(value));
|
|
555
|
-
});
|
|
556
|
-
return values.size;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
727
|
function metric(label,value){
|
|
560
728
|
return '<div class="focus-metric"><div class="focus-metric-label">'+esc(label)+'</div><div class="focus-metric-value">'+esc(value)+'</div></div>';
|
|
561
729
|
}
|
|
562
730
|
|
|
563
|
-
|
|
564
|
-
switch(tab.id){
|
|
565
|
-
case "events": return {title:"Domain events",subtitle:"Published facts and event bus activity"};
|
|
566
|
-
case "jobs": return {title:"Jobs",subtitle:"Background job lifecycle"};
|
|
567
|
-
case "schedules": return {title:"Schedules",subtitle:"Cron and scheduled task runs"};
|
|
568
|
-
case "db": return {title:"Database",subtitle:"Queries and database provider diagnostics"};
|
|
569
|
-
case "cache": return {title:"Cache",subtitle:"Reads, writes, deletes, and hit rates"};
|
|
570
|
-
case "storage": return {title:"Storage",subtitle:"Object storage operations"};
|
|
571
|
-
case "mail": return {title:"Mail",subtitle:"Delivery attempts and provider results"};
|
|
572
|
-
case "notifications": return {title:"Notifications",subtitle:"Notification intent and channel delivery"};
|
|
573
|
-
case "auth": return {title:"Auth",subtitle:"Session and authentication activity"};
|
|
574
|
-
case "audit": return {title:"Audit",subtitle:"Durable activity records emitted by application code"};
|
|
575
|
-
case "rateLimit": return {title:"Rate limits",subtitle:"Allowed, blocked, and failed checks"};
|
|
576
|
-
default: return {title:tab.label,subtitle:"Subsystem activity"};
|
|
577
|
-
}
|
|
578
|
-
}
|
|
731
|
+
${devtoolsPanelModelBrowserSource()}
|
|
579
732
|
|
|
733
|
+
function summarize(e){return summarizeDevtoolsEvent(e);}
|
|
734
|
+
function inferredWatcher(event){return inferDevtoolsWatcher(event);}
|
|
735
|
+
function eventBadgeLabel(event){return devtoolsEventBadgeLabel(event);}
|
|
736
|
+
function eventBadgeClass(event){return devtoolsEventBadgeClass(event);}
|
|
737
|
+
function durationFor(event){return devtoolsEventDuration(event);}
|
|
738
|
+
function providerFor(event){return devtoolsEventProvider(event);}
|
|
739
|
+
function failureFor(event){return devtoolsEventFailure(event);}
|
|
740
|
+
function hasRedactedValue(value){return hasDevtoolsRedactedValue(value);}
|
|
741
|
+
function panelMeta(tab){return devtoolsPanelMeta(tab.id,tab.label);}
|
|
580
742
|
function panelMetrics(tab,list){
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
metric("Events",list.length),
|
|
585
|
-
metric("Names",distinctCount(list,function(event){return event.eventName})),
|
|
586
|
-
metric("Traces",distinctCount(list,function(event){return event.traceId})),
|
|
587
|
-
metric("Requests",distinctCount(list,function(event){return event.requestId}))
|
|
588
|
-
].join("");
|
|
589
|
-
case "jobs":
|
|
590
|
-
return [
|
|
591
|
-
metric("Jobs",list.length),
|
|
592
|
-
metric("Failed",list.filter(failureFor).length),
|
|
593
|
-
metric("Names",distinctCount(list,function(event){return event.jobName})),
|
|
594
|
-
metric("Providers",distinctCount(list,providerFor))
|
|
595
|
-
].join("");
|
|
596
|
-
case "schedules":
|
|
597
|
-
return [
|
|
598
|
-
metric("Runs",list.length),
|
|
599
|
-
metric("Failed",list.filter(failureFor).length),
|
|
600
|
-
metric("Names",distinctCount(list,function(event){return event.scheduleName})),
|
|
601
|
-
metric("Cron",distinctCount(list,function(event){return event.cron}))
|
|
602
|
-
].join("");
|
|
603
|
-
case "cache":
|
|
604
|
-
return [
|
|
605
|
-
metric("Operations",list.length),
|
|
606
|
-
metric("Hits",list.filter(function(event){return detailValue(event,"hit")===true}).length),
|
|
607
|
-
metric("Failures",list.filter(failureFor).length),
|
|
608
|
-
metric("Avg",averageDuration(list))
|
|
609
|
-
].join("");
|
|
610
|
-
case "auth":
|
|
611
|
-
return [
|
|
612
|
-
metric("Events",list.length),
|
|
613
|
-
metric("Authenticated",list.filter(function(event){return detailValue(event,"authenticated")===true}).length),
|
|
614
|
-
metric("Failures",list.filter(failureFor).length),
|
|
615
|
-
metric("Avg",averageDuration(list))
|
|
616
|
-
].join("");
|
|
617
|
-
case "audit":
|
|
618
|
-
return [
|
|
619
|
-
metric("Entries",list.length),
|
|
620
|
-
metric("Failures",list.filter(function(event){return detailValue(event,"outcome")==="failure"}).length),
|
|
621
|
-
metric("Actors",distinctCount(list,function(event){const actor=detailValue(event,"actor");return actor&&actor.id})),
|
|
622
|
-
metric("Resources",distinctCount(list,function(event){const resource=detailValue(event,"resource");return resource&&resource.id}))
|
|
623
|
-
].join("");
|
|
624
|
-
case "rateLimit":
|
|
625
|
-
return [
|
|
626
|
-
metric("Checks",list.length),
|
|
627
|
-
metric("Allowed",list.filter(function(event){return detailValue(event,"allowed")===true}).length),
|
|
628
|
-
metric("Blocked",list.filter(function(event){return detailValue(event,"allowed")===false}).length),
|
|
629
|
-
metric("Avg",averageDuration(list))
|
|
630
|
-
].join("");
|
|
631
|
-
default:
|
|
632
|
-
return [
|
|
633
|
-
metric("Events",list.length),
|
|
634
|
-
metric("Failures",list.filter(failureFor).length),
|
|
635
|
-
metric("Providers",distinctCount(list,providerFor)),
|
|
636
|
-
metric("Avg",averageDuration(list))
|
|
637
|
-
].join("");
|
|
638
|
-
}
|
|
743
|
+
return devtoolsPanelMetrics(tab.id,list).map(function(item){
|
|
744
|
+
return metric(item.label,item.value);
|
|
745
|
+
}).join("");
|
|
639
746
|
}
|
|
640
|
-
|
|
641
|
-
function
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
default: return summarize(event);
|
|
648
|
-
}
|
|
747
|
+
function primaryFor(event){return devtoolsPanelPrimary(tabFor(activeTab).id,event);}
|
|
748
|
+
function secondaryFor(event){return devtoolsPanelSecondary(tabFor(activeTab).id,event);}
|
|
749
|
+
function resultFor(event){return devtoolsPanelResult(event);}
|
|
750
|
+
function tableDetailFor(tab,event){
|
|
751
|
+
const detail=devtoolsPanelDetail(tab.id,event);
|
|
752
|
+
return detailGrid(detail.fields.map(function(item){return [item.label,item.value]}))+
|
|
753
|
+
'<div class="table-detail-note">'+esc(detail.note)+'</div><pre>'+json(event)+'</pre>';
|
|
649
754
|
}
|
|
650
755
|
|
|
651
|
-
function
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
if(event.type==="job")return event.status;
|
|
655
|
-
if(event.type==="schedule")return event.status;
|
|
656
|
-
if(event.type==="eventBus")return event.requestId||event.traceId||"";
|
|
657
|
-
if(event.name)return event.name;
|
|
658
|
-
return inferredWatcher(event);
|
|
756
|
+
function resultChip(value){
|
|
757
|
+
const normalized=String(value||"").replace(/[^a-zA-Z0-9_-]/g,"_");
|
|
758
|
+
return '<span class="result-chip result-'+esc(normalized)+'">'+esc(value||"n/a")+'</span>';
|
|
659
759
|
}
|
|
660
760
|
|
|
661
|
-
function
|
|
662
|
-
const details=detailsObject(event);
|
|
663
|
-
if(details.allowed===true)return "allowed";
|
|
664
|
-
if(details.allowed===false)return "blocked";
|
|
665
|
-
if(details.hit===true)return "hit";
|
|
666
|
-
if(details.hit===false)return "miss";
|
|
667
|
-
if(details.authenticated===true)return "signed in";
|
|
668
|
-
if(details.authenticated===false)return "guest";
|
|
669
|
-
if(event.status)return event.status;
|
|
670
|
-
if(details.error)return "failed";
|
|
671
|
-
return providerFor(event)||inferredWatcher(event);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
function tableRow(event){
|
|
761
|
+
function tableRow(tab,event){
|
|
675
762
|
const time=event.timestamp?new Date(event.timestamp).toLocaleTimeString():"";
|
|
676
763
|
const duration=durationFor(event);
|
|
677
764
|
const durationLabel=duration===undefined?"":duration+"ms";
|
|
@@ -680,15 +767,16 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
680
767
|
'<div class="table-cell">'+esc(time)+'</div>'+
|
|
681
768
|
'<div class="table-cell"><strong>'+esc(primaryFor(event))+'</strong><code>'+esc(secondaryFor(event))+'</code></div>'+
|
|
682
769
|
'<div class="table-cell table-summary">'+esc(summarize(event))+'</div>'+
|
|
770
|
+
'<div class="table-cell table-correlation">'+correlationFor(event)+'</div>'+
|
|
683
771
|
'<div class="table-cell">'+esc(durationLabel)+'</div>'+
|
|
684
|
-
'<div class="table-cell">'+
|
|
685
|
-
'<
|
|
772
|
+
'<div class="table-cell">'+resultChip(resultFor(event)||provider)+'</div>'+
|
|
773
|
+
'<div class="table-detail">'+tableDetailFor(tab,event)+'</div>'+
|
|
686
774
|
'</article>';
|
|
687
775
|
}
|
|
688
776
|
|
|
689
777
|
function renderFocusPanel(tab,list){
|
|
690
778
|
const meta=panelMeta(tab);
|
|
691
|
-
const rows=list.slice().reverse().map(tableRow).join("");
|
|
779
|
+
const rows=list.slice().reverse().map(function(event){return tableRow(tab,event)}).join("");
|
|
692
780
|
return '<section class="focus-panel">'+
|
|
693
781
|
'<div class="focus-head">'+
|
|
694
782
|
'<div><h2 class="focus-title">'+esc(meta.title)+'</h2><div class="focus-subtitle">'+esc(meta.subtitle)+'</div></div>'+
|
|
@@ -698,6 +786,65 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
698
786
|
'</section>';
|
|
699
787
|
}
|
|
700
788
|
|
|
789
|
+
function renderErrorOwners(list){
|
|
790
|
+
const owners=ERROR_OWNERS.map(function(owner){
|
|
791
|
+
return {owner:owner,count:list.filter(function(event){return ownerForEvent(event)===owner}).length};
|
|
792
|
+
}).filter(function(item){return item.count>0});
|
|
793
|
+
const cards=(owners.length?owners:[{owner:"none",count:0}]).map(function(item){
|
|
794
|
+
return '<div class="error-owner-card"><strong>'+esc(item.count)+'</strong><span>'+esc(item.owner)+'</span></div>';
|
|
795
|
+
}).join("");
|
|
796
|
+
return '<div class="error-owner-strip">'+cards+'</div>';
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
function renderErrorRelated(event){
|
|
800
|
+
const related=relatedEventsFor(event).filter(function(candidate){return candidate.type!=="error"}).slice().sort(function(a,b){return eventTimeValue(a)-eventTimeValue(b)}).slice(0,8);
|
|
801
|
+
if(!related.length)return '<div class="empty">No related request, provider, or side-effect events.</div>';
|
|
802
|
+
return '<div class="error-related">'+related.map(function(candidate){
|
|
803
|
+
return '<div class="correlated-row">'+eventBadge(candidate)+'<span>'+esc(summarize(candidate))+'</span>'+ownerPill(ownerForEvent(candidate))+'</div>';
|
|
804
|
+
}).join("")+'</div>';
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function failureMessageFor(event){
|
|
808
|
+
if(event.message)return event.message;
|
|
809
|
+
const details=detailsObject(event);
|
|
810
|
+
const detailError=details.error;
|
|
811
|
+
if(typeof detailError==="string"&&detailError)return detailError;
|
|
812
|
+
if(detailError&&typeof detailError==="object"){
|
|
813
|
+
if(typeof detailError.message==="string")return detailError.message;
|
|
814
|
+
return jsonSearch(detailError);
|
|
815
|
+
}
|
|
816
|
+
return summarize(event)||"Unknown failure";
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function renderErrorRow(event){
|
|
820
|
+
const time=event.timestamp?new Date(event.timestamp).toLocaleTimeString():"";
|
|
821
|
+
const status=statusForEvent(event);
|
|
822
|
+
const route=[contractForEvent(event),pathForEvent(event)].filter(Boolean).join(" ");
|
|
823
|
+
const relatedCount=relatedEventsFor(event).length;
|
|
824
|
+
const message=failureMessageFor(event);
|
|
825
|
+
return '<article class="error-row" onclick="this.classList.toggle(\\'open\\')">'+
|
|
826
|
+
'<div class="table-cell">'+esc(time)+'</div>'+
|
|
827
|
+
'<div><div class="error-message" title="'+esc(message)+'">'+esc(message)+'</div><div class="error-context">'+esc(route||event.useCaseName||primaryFor(event)||"unmatched")+'</div></div>'+
|
|
828
|
+
'<div>'+ownerPill(ownerForEvent(event))+'</div>'+
|
|
829
|
+
'<div class="table-cell table-correlation">'+correlationFor(event)+'</div>'+
|
|
830
|
+
'<div class="table-cell">'+resultChip(status||relatedCount+" related")+'</div>'+
|
|
831
|
+
'<div class="table-detail">'+renderErrorRelated(event)+'<pre>'+json(event)+'</pre></div>'+
|
|
832
|
+
'</article>';
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function renderErrorsPanel(list){
|
|
836
|
+
const rowsByOwner=ERROR_OWNERS.map(function(owner){
|
|
837
|
+
const ownerEvents=list.filter(function(event){return ownerForEvent(event)===owner});
|
|
838
|
+
if(!ownerEvents.length)return"";
|
|
839
|
+
const rows=ownerEvents.slice().reverse().map(renderErrorRow).join("");
|
|
840
|
+
return '<section class="error-group">'+
|
|
841
|
+
'<div class="error-group-head"><div class="error-group-title">'+ownerPill(owner)+'<span>'+esc(owner)+' failures</span></div><div class="error-group-count">'+esc(ownerEvents.length)+' errors</div></div>'+
|
|
842
|
+
rows+
|
|
843
|
+
'</section>';
|
|
844
|
+
}).join("");
|
|
845
|
+
return '<section class="error-board">'+renderErrorOwners(list)+rowsByOwner+'</section>';
|
|
846
|
+
}
|
|
847
|
+
|
|
701
848
|
function render(){
|
|
702
849
|
updateStats();
|
|
703
850
|
renderTabs();
|
|
@@ -714,6 +861,10 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
714
861
|
$content.innerHTML=renderRequests(list);
|
|
715
862
|
return;
|
|
716
863
|
}
|
|
864
|
+
if(activeTab==="errors"){
|
|
865
|
+
$content.innerHTML=renderErrorsPanel(list);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
717
868
|
if(FOCUS_PANEL_TABS[tab.id]){
|
|
718
869
|
$content.innerHTML=renderFocusPanel(tab,list);
|
|
719
870
|
return;
|