@oas-tools/oas-telemetry 0.2.1 → 0.3.0
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/LICENSE +200 -200
- package/README.md +133 -133
- package/dist/exporters/InMemoryDbExporter.cjs +51 -31
- package/dist/index.cjs +96 -17
- package/dist/telemetry.cjs +0 -0
- package/dist/ui.cjs +419 -111
- package/package.json +71 -63
- package/src/exporters/InMemoryDbExporter.js +175 -154
- package/src/index.js +307 -197
- package/src/telemetry.js +25 -25
- package/src/ui.js +1193 -887
package/dist/ui.cjs
CHANGED
|
@@ -6,8 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = ui;
|
|
7
7
|
function ui() {
|
|
8
8
|
return {
|
|
9
|
-
main:
|
|
10
|
-
<!DOCTYPE html>
|
|
9
|
+
main: `<!DOCTYPE html>
|
|
11
10
|
<html lang="en">
|
|
12
11
|
|
|
13
12
|
<head>
|
|
@@ -17,12 +16,98 @@ function ui() {
|
|
|
17
16
|
<style>
|
|
18
17
|
body {
|
|
19
18
|
font-family: Arial, sans-serif;
|
|
20
|
-
margin:
|
|
19
|
+
margin: 0;
|
|
20
|
+
padding: 0;
|
|
21
|
+
background-color: #f5f5f5;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.header {
|
|
25
|
+
background-color: #333;
|
|
26
|
+
color: #fff;
|
|
27
|
+
padding: 20px;
|
|
28
|
+
text-align: left;
|
|
29
|
+
display: flex;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.header h1 {
|
|
34
|
+
display: inline-block;
|
|
35
|
+
margin: 0;
|
|
36
|
+
font-size: 24px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.header .links {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
}
|
|
43
|
+
.links a {
|
|
44
|
+
color: #fff;
|
|
45
|
+
text-decoration: none;
|
|
46
|
+
margin-left: 30px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.page {
|
|
50
|
+
margin: 0;
|
|
51
|
+
padding: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.panel-conainer {
|
|
55
|
+
min-width: 60%;
|
|
56
|
+
width: fit-content;
|
|
57
|
+
margin: 20px auto;
|
|
58
|
+
}
|
|
59
|
+
.panel {
|
|
60
|
+
background-color: #fff;
|
|
61
|
+
border: 1px solid #ddd;
|
|
62
|
+
margin: 10px;
|
|
63
|
+
border-radius: 4px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.panel-header {
|
|
67
|
+
background-color: #f1f1f1;
|
|
68
|
+
padding: 10px;
|
|
69
|
+
font-weight: bold;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.panel-content {
|
|
74
|
+
display: none;
|
|
75
|
+
padding: 15px;
|
|
76
|
+
|
|
77
|
+
/* items margin */
|
|
78
|
+
>* {
|
|
79
|
+
margin: 5px 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.panel.open .panel-content {
|
|
85
|
+
display: flex;
|
|
86
|
+
flex-direction: column;
|
|
87
|
+
padding: 15px;
|
|
88
|
+
justify-content: center;
|
|
89
|
+
align-items: center;
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
button {
|
|
95
|
+
background-color: #007bff;
|
|
96
|
+
color: white;
|
|
97
|
+
border: none;
|
|
98
|
+
padding: 10px 15px;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
button:hover {
|
|
104
|
+
background-color: #0056b3;
|
|
21
105
|
}
|
|
22
106
|
|
|
23
107
|
table {
|
|
24
|
-
width:
|
|
108
|
+
width: fit-content;
|
|
25
109
|
border-collapse: collapse;
|
|
110
|
+
margin: 100%;
|
|
26
111
|
}
|
|
27
112
|
|
|
28
113
|
th,
|
|
@@ -36,40 +121,221 @@ function ui() {
|
|
|
36
121
|
background-color: #f2f2f2;
|
|
37
122
|
}
|
|
38
123
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
.spaced-row {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
justify-content: space-between;
|
|
130
|
+
width: 100%;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.row {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
}
|
|
137
|
+
</style>
|
|
138
|
+
<style>
|
|
139
|
+
.toggle-container {
|
|
140
|
+
display: flex;
|
|
141
|
+
flex: none;
|
|
142
|
+
width: max-content;
|
|
143
|
+
align-items: center;
|
|
144
|
+
margin: 10px 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.toggle {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
min-width: 40px;
|
|
151
|
+
min-height: 20px;
|
|
152
|
+
border-radius: 12px;
|
|
153
|
+
background-color: gray;
|
|
154
|
+
position: relative;
|
|
155
|
+
cursor: pointer;
|
|
156
|
+
transition: background-color 0.3s;
|
|
157
|
+
margin: 0 10px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.toggle.circle {
|
|
161
|
+
border-radius: 50%;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.toggle.active {
|
|
165
|
+
background-color: green;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.circle-indicator {
|
|
169
|
+
width: 16px;
|
|
170
|
+
height: 16px;
|
|
171
|
+
margin: 0px 2px;
|
|
172
|
+
background-color: white;
|
|
173
|
+
border-radius: 50%;
|
|
174
|
+
transition: transform 0.3s;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.toggle.active .circle-indicator {
|
|
178
|
+
transform: translateX(20px);
|
|
179
|
+
/* Move the circle to the right when active */
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.option-text {
|
|
183
|
+
transition: color 0.3s;
|
|
184
|
+
margin: 0 5px;
|
|
42
185
|
}
|
|
43
186
|
</style>
|
|
44
187
|
</head>
|
|
45
188
|
|
|
46
189
|
<body>
|
|
47
|
-
<h1>Telemetry <span id="telemetryStatusSpan"></span></h1>
|
|
48
|
-
|
|
49
|
-
<label><input type="checkbox" id="toggleTelemetry"> Allow Server Telemetry</label>
|
|
50
|
-
<br><br>
|
|
51
|
-
<button onclick="fetch('/telemetry/reset');showTelemetryStatus();">Reset Telemetry Data</button>
|
|
52
|
-
<br><br>
|
|
53
|
-
<label><input type="checkbox" id="autoUpdate"> Allow Client Auto Update</label>
|
|
54
|
-
<br><br>
|
|
55
|
-
<table id="apiTable">
|
|
56
|
-
<thead>
|
|
57
|
-
<tr>
|
|
58
|
-
<th onclick="sortTable(0)">Path</th>
|
|
59
|
-
<th onclick="sortTable(1)">Method</th>
|
|
60
|
-
<th onclick="sortTable(2)">Status</th>
|
|
61
|
-
<th onclick="sortTable(3)">Description</th>
|
|
62
|
-
<th onclick="sortTable(4)" style="text-align: center;">Request <br> Count</th>
|
|
63
|
-
<th onclick="sortTable(5)" style="text-align: center;">Average response time<br> (sec)</th>
|
|
64
|
-
<th style="text-align: center;">Auto<br>Update</th>
|
|
65
|
-
</tr>
|
|
66
|
-
</thead>
|
|
67
|
-
<tbody>
|
|
68
|
-
</tbody>
|
|
69
|
-
</table>
|
|
70
190
|
|
|
191
|
+
<div class="header">
|
|
192
|
+
<h1>OAS-Telemetry</h1>
|
|
193
|
+
<div class="links">
|
|
194
|
+
<a target="_blank" href="https://github.com/oas-tools/oas-telemetry">Documentation</a>
|
|
195
|
+
<a target="_blank" href="https://www.npmjs.com/package/@oas-tools/oas-telemetry">NPM</a>
|
|
196
|
+
<a target="_blank" href="https://github.com/oas-tools/oas-telemetry">GitHub</a>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
<div class="page">
|
|
200
|
+
<div class="panel-conainer">
|
|
201
|
+
<!-- Panel 1 -->
|
|
202
|
+
<div class="panel open" id="panel1">
|
|
203
|
+
<div class="panel-header" onclick="togglePanel('panel1')">Telemetry Management</div>
|
|
204
|
+
<div class="panel-content">
|
|
205
|
+
<div class="spaced-row">
|
|
206
|
+
<div id="toggleTelemetry"></div>
|
|
207
|
+
<button onclick="fetch('/telemetry/reset');fetchTelemetryStatus();">Reset Telemetry
|
|
208
|
+
Data</button>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<!-- Panel 2 -->
|
|
214
|
+
<div class="panel open" id="panel2">
|
|
215
|
+
<div class="panel-header" onclick="togglePanel('panel2')">Heap Stats</div>
|
|
216
|
+
<div class="panel-content">
|
|
217
|
+
<div class="spaced-row">
|
|
218
|
+
<div id="heapAutoUpdate"></div>
|
|
219
|
+
<button onclick="populateHeapStats()">Update</button>
|
|
220
|
+
</div>
|
|
221
|
+
<table id="heapStatsTable">
|
|
222
|
+
<thead>
|
|
223
|
+
<tr>
|
|
224
|
+
<th>Stat Name</th>
|
|
225
|
+
<th>Value</th>
|
|
226
|
+
</tr>
|
|
227
|
+
</thead>
|
|
228
|
+
<tbody>
|
|
229
|
+
</tbody>
|
|
230
|
+
</table>
|
|
231
|
+
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<!-- Panel 3 -->
|
|
236
|
+
<div class="panel no-user-select open" id="panel3">
|
|
237
|
+
<div class="panel-header" onclick="togglePanel('panel3')">Telemetry Endpoints</div>
|
|
238
|
+
<div class="panel-content">
|
|
239
|
+
<div class="spaced-row">
|
|
240
|
+
<div id="autoUpdateApiTable"></div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<table id="apiTable">
|
|
244
|
+
<thead>
|
|
245
|
+
<tr>
|
|
246
|
+
<th onclick="sortTable(0)">Path</th>
|
|
247
|
+
<th onclick="sortTable(1)">Method</th>
|
|
248
|
+
<th onclick="sortTable(2)">Status</th>
|
|
249
|
+
<th onclick="sortTable(3)">Description</th>
|
|
250
|
+
<th onclick="sortTable(4)" style="text-align: center;">Request Count</th>
|
|
251
|
+
<th onclick="sortTable(5)" style="text-align: center;">Average response time (sec)
|
|
252
|
+
</th>
|
|
253
|
+
<th style="text-align: center;">Options</th>
|
|
254
|
+
</tr>
|
|
255
|
+
</thead>
|
|
256
|
+
<tbody>
|
|
257
|
+
</tbody>
|
|
258
|
+
</table>
|
|
259
|
+
</table>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
<!-- Scripts -->
|
|
71
265
|
<script>
|
|
72
|
-
|
|
266
|
+
// Open Close Panel
|
|
267
|
+
function togglePanel(panelId) {
|
|
268
|
+
const panel = document.getElementById(panelId);
|
|
269
|
+
panel.classList.toggle('open');
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Create a toggle component
|
|
273
|
+
* @param {string} title - Title of the toggle
|
|
274
|
+
* @param {string} falseText - Text to display when false
|
|
275
|
+
* @param {string} falseColor - Color of the text when false
|
|
276
|
+
* @param {string} trueText - Text to display when true
|
|
277
|
+
* @param {string} trueColor - Color of the text when true
|
|
278
|
+
* @param {function} handler - Function to call when the toggle is clicked
|
|
279
|
+
* @param {boolean} defaultValue - Default value of the toggle
|
|
280
|
+
* @returns {HTMLDivElement} - The toggle component
|
|
281
|
+
*/
|
|
282
|
+
function createToggle(title, falseText, falseColor, trueText, trueColor, handler, defaultValue = false) {
|
|
283
|
+
const container = document.createElement('div');
|
|
284
|
+
container.className = 'toggle-container';
|
|
285
|
+
|
|
286
|
+
const label = document.createElement('span');
|
|
287
|
+
label.textContent = title + ':';
|
|
288
|
+
label.style.marginRight = '10px';
|
|
289
|
+
|
|
290
|
+
const falseTextSpan = document.createElement('span');
|
|
291
|
+
falseTextSpan.className = 'option-text';
|
|
292
|
+
falseTextSpan.textContent = falseText;
|
|
293
|
+
falseTextSpan.style.color = defaultValue ? 'gray' : falseColor;
|
|
294
|
+
|
|
295
|
+
const toggle = document.createElement('div');
|
|
296
|
+
toggle.className = 'toggle';
|
|
297
|
+
const circleIndicator = document.createElement('div');
|
|
298
|
+
circleIndicator.className = 'circle-indicator';
|
|
299
|
+
toggle.appendChild(circleIndicator);
|
|
300
|
+
|
|
301
|
+
toggle.addEventListener('click', () => {
|
|
302
|
+
toggle.classList.toggle('active');
|
|
303
|
+
const isActive = toggle.classList.contains('active');
|
|
304
|
+
|
|
305
|
+
// Update colors. Not selected option to default color, selected option to active color
|
|
306
|
+
falseTextSpan.style.color = isActive ? 'gray' : falseColor;
|
|
307
|
+
trueTextSpan.style.color = isActive ? trueColor : 'gray';
|
|
308
|
+
|
|
309
|
+
handler(isActive);
|
|
310
|
+
});
|
|
311
|
+
toggle.classList.toggle('active', defaultValue);
|
|
312
|
+
|
|
313
|
+
const trueTextSpan = document.createElement('span');
|
|
314
|
+
trueTextSpan.className = 'option-text';
|
|
315
|
+
trueTextSpan.textContent = trueText; // Always display trueText
|
|
316
|
+
trueTextSpan.style.color = defaultValue ? trueColor : 'gray';
|
|
317
|
+
|
|
318
|
+
container.appendChild(label);
|
|
319
|
+
container.appendChild(falseTextSpan);
|
|
320
|
+
container.appendChild(toggle);
|
|
321
|
+
container.appendChild(trueTextSpan);
|
|
322
|
+
|
|
323
|
+
return container;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const localStorageManager = {
|
|
327
|
+
get: (key) => {
|
|
328
|
+
const value = localStorage.getItem(key);
|
|
329
|
+
return value ? JSON.parse(value) : null;
|
|
330
|
+
},
|
|
331
|
+
set: (key, value) => {
|
|
332
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
</script>
|
|
337
|
+
<script>
|
|
338
|
+
let LOG = true;
|
|
73
339
|
|
|
74
340
|
|
|
75
341
|
let intervalTimer = {
|
|
@@ -77,7 +343,14 @@ function ui() {
|
|
|
77
343
|
period: 2000,
|
|
78
344
|
subscribers: [],
|
|
79
345
|
start: function () {
|
|
346
|
+
this.disabled = false;
|
|
80
347
|
this.interval = setInterval(() => this.tick(), this.period);
|
|
348
|
+
log("interval started with period: " + this.period);
|
|
349
|
+
},
|
|
350
|
+
stop: function () {
|
|
351
|
+
this.disabled = true;
|
|
352
|
+
clearInterval(this.interval);
|
|
353
|
+
log("interval stopped");
|
|
81
354
|
},
|
|
82
355
|
tick: function () {
|
|
83
356
|
if (this.disabled) return;
|
|
@@ -92,10 +365,6 @@ function ui() {
|
|
|
92
365
|
}
|
|
93
366
|
}
|
|
94
367
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
368
|
function log(s) {
|
|
100
369
|
if (LOG) console.log(s);
|
|
101
370
|
}
|
|
@@ -115,6 +384,17 @@ function ui() {
|
|
|
115
384
|
}
|
|
116
385
|
}
|
|
117
386
|
|
|
387
|
+
async function fetchTelemetryStatus() {
|
|
388
|
+
const response = await fetch("/telemetry/status");
|
|
389
|
+
if (!response.ok) {
|
|
390
|
+
throw new Error("ERROR getting the Status");
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
tStatus = await response.json();
|
|
394
|
+
|
|
395
|
+
log("tStatus: " + JSON.stringify(tStatus, null, 2));
|
|
396
|
+
return tStatus.active;
|
|
397
|
+
}
|
|
118
398
|
|
|
119
399
|
function getPathRegEx(path) {
|
|
120
400
|
let pathComponents = path.split("/");
|
|
@@ -124,14 +404,16 @@ function ui() {
|
|
|
124
404
|
if (c != "") {
|
|
125
405
|
pathRegExpStr += "/";
|
|
126
406
|
if (c.charAt(0) == "{" && c.charAt(c.length - 1) == "}") {
|
|
127
|
-
|
|
407
|
+
// Ensure it matches at least one character (.+)
|
|
408
|
+
pathRegExpStr += "(.+)";
|
|
128
409
|
} else {
|
|
129
410
|
pathRegExpStr += c;
|
|
130
411
|
}
|
|
131
412
|
}
|
|
132
413
|
});
|
|
133
414
|
|
|
134
|
-
|
|
415
|
+
// Allow an optional trailing slash
|
|
416
|
+
pathRegExpStr += "/?\$";
|
|
135
417
|
|
|
136
418
|
return pathRegExpStr;
|
|
137
419
|
}
|
|
@@ -243,11 +525,12 @@ function ui() {
|
|
|
243
525
|
cellRequestCount.textContent = requestCount;
|
|
244
526
|
cellAverageResponseTime.textContent = requestCount ? averageResponseTime.toFixed(3) : "--";
|
|
245
527
|
|
|
246
|
-
// setTimeout(() => loadStats(path, method, status, cellRequestCount, cellAverageResponseTime), 2000);
|
|
247
528
|
}
|
|
248
529
|
|
|
249
|
-
function
|
|
530
|
+
async function populateApiTable() {
|
|
531
|
+
const apiSpec = await fetchSpec()
|
|
250
532
|
const tableBody = document.getElementById('apiTable').getElementsByTagName('tbody')[0];
|
|
533
|
+
tableBody.innerHTML = "";
|
|
251
534
|
Object.keys(apiSpec.paths).forEach(path => {
|
|
252
535
|
Object.keys(apiSpec.paths[path]).forEach(method => {
|
|
253
536
|
Object.keys(apiSpec.paths[path][method].responses).forEach(responseType => {
|
|
@@ -278,28 +561,17 @@ function ui() {
|
|
|
278
561
|
+ apiSpec.paths[path][method].responses[responseType].description;
|
|
279
562
|
|
|
280
563
|
row.detailPath = \`/telemetry/detail/\${responseType}/\${method.toLowerCase()}\${fullPath}\`;
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
// Add event listener to handle checkbox auto-update
|
|
293
|
-
checkbox.addEventListener('change', function () {
|
|
294
|
-
if (this.checked)
|
|
295
|
-
intervalTimer.subscribe(() =>
|
|
296
|
-
loadStats(fullPath, method.toLowerCase(), responseType, cellRequestCount, cellAverageResponseTime)
|
|
297
|
-
);
|
|
298
|
-
else
|
|
299
|
-
intervalTimer.unsubscribe(() =>
|
|
300
|
-
loadStats(fullPath, method.toLowerCase(), responseType, cellRequestCount, cellAverageResponseTime)
|
|
301
|
-
);
|
|
302
|
-
});
|
|
564
|
+
const cellOptions = row.insertCell(6);
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
// Create a button for updating the endpoint spaced row but centered
|
|
568
|
+
const updateButton = document.createElement('button');
|
|
569
|
+
updateButton.textContent = "Update";
|
|
570
|
+
updateButton.onclick = () => loadStats(path, method, responseType, cellRequestCount, cellAverageResponseTime);
|
|
571
|
+
cellOptions.appendChild(updateButton);
|
|
572
|
+
cellOptions.style.display = "flex";
|
|
573
|
+
cellOptions.style.justifyContent = "center";
|
|
574
|
+
loadStats(path, method, responseType, cellRequestCount, cellAverageResponseTime);
|
|
303
575
|
|
|
304
576
|
}
|
|
305
577
|
});
|
|
@@ -307,6 +579,24 @@ function ui() {
|
|
|
307
579
|
});
|
|
308
580
|
}
|
|
309
581
|
|
|
582
|
+
function populateHeapStats() {
|
|
583
|
+
// heapstats at /telemetry/heapstats
|
|
584
|
+
const tableBody = document.getElementById('heapStatsTable').getElementsByTagName('tbody')[0];
|
|
585
|
+
fetch('/telemetry/heapstats').then(response => response.json()).then(heapStats => {
|
|
586
|
+
tableBody.innerHTML = "";
|
|
587
|
+
Object.keys(heapStats).forEach(statName => {
|
|
588
|
+
const row = tableBody.insertRow();
|
|
589
|
+
const cellStatName = row.insertCell(0);
|
|
590
|
+
const cellValue = row.insertCell(1);
|
|
591
|
+
cellStatName.textContent = statName;
|
|
592
|
+
//format always to 3 decimals (if number)
|
|
593
|
+
const formattedValue = typeof heapStats[statName] === 'number' ? heapStats[statName].toFixed(3) : heapStats[statName];
|
|
594
|
+
cellValue.textContent = heapStats[statName];
|
|
595
|
+
cellValue.style.textAlign = "right";
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
|
|
310
600
|
function sortTable(column) {
|
|
311
601
|
const table = document.getElementById('apiTable');
|
|
312
602
|
let rows, switching, i, x, y, shouldSwitch;
|
|
@@ -330,58 +620,58 @@ function ui() {
|
|
|
330
620
|
}
|
|
331
621
|
}
|
|
332
622
|
|
|
333
|
-
document.getElementById('
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
async function showTelemetryStatus() {
|
|
344
|
-
const tss = document.getElementById("telemetryStatusSpan");
|
|
345
|
-
const response = await fetch("/telemetry/status");
|
|
346
|
-
if (!response.ok) {
|
|
347
|
-
throw new Error("ERROR getting the Status");
|
|
348
|
-
return false;
|
|
623
|
+
document.getElementById('toggleTelemetry').appendChild(createToggle(
|
|
624
|
+
'Telemetry status',
|
|
625
|
+
'Stopped', 'red', // false state
|
|
626
|
+
'Active', 'green', // true state
|
|
627
|
+
async (status) => {
|
|
628
|
+
const response = await fetch('/telemetry/' + (status ? 'start' : 'stop'));
|
|
629
|
+
if (!response.ok) {
|
|
630
|
+
throw new Error("ERROR setting the Telemetry status");
|
|
631
|
+
}
|
|
349
632
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
633
|
+
));
|
|
634
|
+
|
|
635
|
+
document.getElementById('autoUpdateApiTable').appendChild(createToggle(
|
|
636
|
+
'Auto Update',
|
|
637
|
+
'Manual', 'orange', // false state
|
|
638
|
+
'Auto', 'green', // true state
|
|
639
|
+
(status) => {
|
|
640
|
+
const callback = () => { populateApiTable(); };
|
|
641
|
+
if (status) {
|
|
642
|
+
intervalTimer.subscribe(callback);
|
|
643
|
+
} else {
|
|
644
|
+
intervalTimer.unsubscribe(callback);
|
|
645
|
+
}
|
|
359
646
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
647
|
+
));
|
|
648
|
+
|
|
649
|
+
document.getElementById('heapAutoUpdate').appendChild(createToggle(
|
|
650
|
+
'Auto Update',
|
|
651
|
+
'Manual', 'orange', // false state
|
|
652
|
+
'Auto', 'green', // true state
|
|
653
|
+
(status) => {
|
|
654
|
+
if (status) {
|
|
655
|
+
intervalTimer.subscribe(populateHeapStats);
|
|
656
|
+
} else {
|
|
657
|
+
intervalTimer.unsubscribe(populateHeapStats);
|
|
658
|
+
}
|
|
368
659
|
}
|
|
369
|
-
|
|
660
|
+
));
|
|
370
661
|
|
|
371
662
|
window.onload = async function () {
|
|
372
|
-
document.getElementById('
|
|
373
|
-
const activeTelemetry = await
|
|
374
|
-
document.getElementById('toggleTelemetry').
|
|
375
|
-
|
|
376
|
-
|
|
663
|
+
document.getElementById('autoUpdateApiTable').querySelector('.toggle').classList.toggle('active', localStorageManager.get('autoUpdateApiTable'));
|
|
664
|
+
const activeTelemetry = await fetchTelemetryStatus();
|
|
665
|
+
document.getElementById('toggleTelemetry').querySelector('.toggle').classList.toggle('active', activeTelemetry);
|
|
666
|
+
populateApiTable();
|
|
667
|
+
populateHeapStats();
|
|
377
668
|
intervalTimer.start();
|
|
378
669
|
};
|
|
379
670
|
</script>
|
|
380
671
|
</body>
|
|
381
672
|
|
|
382
673
|
</html>`,
|
|
383
|
-
detail:
|
|
384
|
-
<!DOCTYPE html>
|
|
674
|
+
detail: `<!DOCTYPE html>
|
|
385
675
|
<html lang="en">
|
|
386
676
|
|
|
387
677
|
<head>
|
|
@@ -584,14 +874,16 @@ function ui() {
|
|
|
584
874
|
if (c != "") {
|
|
585
875
|
pathRegExpStr += "/";
|
|
586
876
|
if (c.charAt(0) == "{" && c.charAt(c.length - 1) == "}") {
|
|
587
|
-
|
|
877
|
+
// Ensure it matches at least one character (.+)
|
|
878
|
+
pathRegExpStr += "(.+)";
|
|
588
879
|
} else {
|
|
589
880
|
pathRegExpStr += c;
|
|
590
881
|
}
|
|
591
882
|
}
|
|
592
883
|
});
|
|
593
884
|
|
|
594
|
-
|
|
885
|
+
// Allow an optional trailing slash
|
|
886
|
+
pathRegExpStr += "/?\$";
|
|
595
887
|
|
|
596
888
|
return pathRegExpStr;
|
|
597
889
|
}
|
|
@@ -600,7 +892,24 @@ function ui() {
|
|
|
600
892
|
try {
|
|
601
893
|
log(\`Fetchig traces for <\${path}> - \${method} - \${status},.. \`);
|
|
602
894
|
|
|
603
|
-
const
|
|
895
|
+
const body = {
|
|
896
|
+
"flags": { "containsRegex": true },
|
|
897
|
+
"config": { "regexIds": ["attributes.http.target"] },
|
|
898
|
+
"search": {
|
|
899
|
+
"attributes.http.target": getPathRegEx(path),
|
|
900
|
+
"attributes.http.method": method.toUpperCase(),
|
|
901
|
+
"attributes.http.status_code": parseInt(status)
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
log("body: " + JSON.stringify(body, null, 2));
|
|
905
|
+
//response is to the post at /telemetry/find
|
|
906
|
+
const response = await fetch("/telemetry/find", {
|
|
907
|
+
method: "POST",
|
|
908
|
+
headers: {
|
|
909
|
+
"Content-Type": "application/json"
|
|
910
|
+
},
|
|
911
|
+
body: JSON.stringify(body)
|
|
912
|
+
});
|
|
604
913
|
|
|
605
914
|
if (!response.ok) {
|
|
606
915
|
throw new Error("ERROR getting the Traces.");
|
|
@@ -608,13 +917,12 @@ function ui() {
|
|
|
608
917
|
|
|
609
918
|
const responseJSON = await response.json();
|
|
610
919
|
const traces = responseJSON.spans;
|
|
611
|
-
const filteredTraces = traces; //filter made in server side
|
|
612
|
-
log(\`Feched \${traces.length} traces.\`);
|
|
613
|
-
//log(\`First trace: \${JSON.stringify(traces[0],null,2)}\`);
|
|
614
920
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
921
|
+
log(\`Fetched \${traces.length} traces.\`);
|
|
922
|
+
|
|
923
|
+
if (traces.length != traceCount) {
|
|
924
|
+
loadTraces(traces);
|
|
925
|
+
traceCount = traces.length;
|
|
618
926
|
}
|
|
619
927
|
|
|
620
928
|
setTimeout(fetchTracesByParsing, 1000, path, method, status);
|