un-cli 0.0.67 → 0.0.70
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/adminlog.mjs +12 -3
- package/cmd.txt +1 -2
- package/index.html +677 -0
- package/index.mjs +221 -147
- package/logger.mjs +8 -1
- package/makerequest.mjs +14 -2
- package/package.json +2 -4
- package/portal.mjs +5 -4
- package/utilitynetwork.node.mjs +11 -7
package/index.html
ADDED
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>UN Logs</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
|
|
11
|
+
<table>
|
|
12
|
+
<tr><td>Service</td>
|
|
13
|
+
<td colspan =3 ><select id ='cmbService'>
|
|
14
|
+
<option>(All Services)</option>
|
|
15
|
+
</select>
|
|
16
|
+
</td>
|
|
17
|
+
</tr>
|
|
18
|
+
|
|
19
|
+
<tr>
|
|
20
|
+
<td >Age</td>
|
|
21
|
+
<td colspan =3><input type ='text' id = 'txtAge' value = '30' style="width:30px"> minutes</td>
|
|
22
|
+
</tr>
|
|
23
|
+
<tr colspan =4>
|
|
24
|
+
<td><button id = 'btnTraceLogs'>Trace Logs</button></td>
|
|
25
|
+
<td><button id = 'btnValidateLogs'>Validate Logs</button></td>
|
|
26
|
+
<td><button id = 'btnUpdateSubnetworkLogs'>Update Subnetwork Logs</button></td>
|
|
27
|
+
<td><button id = 'btnAR'>Attribute Rules Logs</button></td>
|
|
28
|
+
<td><button id = 'btnSQLLogs'>SQL Logs</button></td>
|
|
29
|
+
|
|
30
|
+
</tr>
|
|
31
|
+
|
|
32
|
+
</table>
|
|
33
|
+
|
|
34
|
+
<table id = 'tblResult' border =1 cellpadding = 4 cellspacing = 4 style="text-align:center">
|
|
35
|
+
|
|
36
|
+
</table>
|
|
37
|
+
<script type = 'module'>
|
|
38
|
+
import { Portal } from "./portal.mjs"
|
|
39
|
+
import { UtilityNetwork } from "./utilitynetwork.node.mjs"
|
|
40
|
+
import { AdminLog } from "./adminlog.mjs"
|
|
41
|
+
import logger from "./logger.mjs"
|
|
42
|
+
|
|
43
|
+
const parameters = {
|
|
44
|
+
"user": "unadmin",
|
|
45
|
+
"password": "unadmin.109",
|
|
46
|
+
"portal": "https://utilitynetwork.esri.com/portal",
|
|
47
|
+
"service": "RedTrolley_SQLServer",
|
|
48
|
+
"referer": "https://utilitynetwork.esri.com/log"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let portal;
|
|
52
|
+
let adminLog = null;
|
|
53
|
+
let cmbService
|
|
54
|
+
let token;
|
|
55
|
+
async function init() {
|
|
56
|
+
|
|
57
|
+
cmbService = document.getElementById("cmbService")
|
|
58
|
+
|
|
59
|
+
token = await getToken(parameters);
|
|
60
|
+
const services = await portal.services()
|
|
61
|
+
const featureServices = services.services.filter(s => s.type == "FeatureServer")
|
|
62
|
+
featureServices.forEach(s=> {
|
|
63
|
+
const o = document.createElement("option");
|
|
64
|
+
o.text = s.name;
|
|
65
|
+
cmbService.appendChild(o);
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async function getToken(parameters) {
|
|
71
|
+
portal = new Portal(parameters.portal, parameters.user, parameters.password,300, parameters.server, parameters.referer)
|
|
72
|
+
console.log("About to connect..")
|
|
73
|
+
const token = await portal.connect()
|
|
74
|
+
console.log(`Token generanted successfully.`)
|
|
75
|
+
return token;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async function loadTraceLogs () {
|
|
80
|
+
|
|
81
|
+
//build table
|
|
82
|
+
const tblResult = document.getElementById("tblResult");
|
|
83
|
+
//clear
|
|
84
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
85
|
+
tblResult.appendChild(document.createTextNode("Loading...."));
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
89
|
+
|
|
90
|
+
//create a new admin object (user might not be admin we won't use it until the user call log )
|
|
91
|
+
adminLog = new AdminLog(token, portal.serverUrl)
|
|
92
|
+
|
|
93
|
+
logger.info("Connected.")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
const topLogCount = 1000;
|
|
97
|
+
const pageSize = 10000
|
|
98
|
+
|
|
99
|
+
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
100
|
+
|
|
101
|
+
console.log(`Querying trace logs for ${parameters.service} for the last ${mins} minutes ...`)
|
|
102
|
+
const startTime = Date.now() - mins*60*1000
|
|
103
|
+
const endTime = Date.now();
|
|
104
|
+
let services = [parameters.service+ ".MapServer"]
|
|
105
|
+
if (parameters.service == "(All Services)")
|
|
106
|
+
services = "*"
|
|
107
|
+
let result= await adminLog.query([102002], services, topLogCount, startTime ,endTime , "VERBOSE")
|
|
108
|
+
let jsonRes = await result.json()
|
|
109
|
+
let allMessages = [].concat(jsonRes.logMessages)
|
|
110
|
+
allMessages = allMessages.filter(m => m.message.indexOf("------ Trace Parameters ----") > -1)
|
|
111
|
+
while (jsonRes.hasMore)
|
|
112
|
+
{
|
|
113
|
+
//start paging
|
|
114
|
+
logger.info(`Aggregating messages... total so far ${allMessages.length} entries but more left, pulling logs before ${new Date(jsonRes.endTime)}`)
|
|
115
|
+
result= await adminLog.query([102002], services, pageSize, jsonRes.endTime, null, "VERBOSE")
|
|
116
|
+
jsonRes = await result.json()
|
|
117
|
+
|
|
118
|
+
allMessages = allMessages.concat(jsonRes.logMessages.filter(m => m.message.indexOf("------ Trace Parameters ----") > -1))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
await populateMessages(allMessages)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
async function loadValidateLogs () {
|
|
129
|
+
//build table
|
|
130
|
+
const tblResult = document.getElementById("tblResult");
|
|
131
|
+
//clear
|
|
132
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
133
|
+
tblResult.appendChild(document.createTextNode("Loading...."));
|
|
134
|
+
|
|
135
|
+
parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
//create a new admin object (user might not be admin we won't use it until the user call log )
|
|
139
|
+
adminLog = new AdminLog(token, portal.serverUrl)
|
|
140
|
+
|
|
141
|
+
logger.info("Connected.")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
const topLogCount = 1000;
|
|
145
|
+
const pageSize = 10000
|
|
146
|
+
|
|
147
|
+
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
148
|
+
|
|
149
|
+
console.log(`Querying validate logs for ${parameters.service} for the last ${mins} minutes ...`)
|
|
150
|
+
const startTime = Date.now() - mins*60*1000
|
|
151
|
+
const endTime = Date.now();
|
|
152
|
+
let services = [parameters.service+ ".MapServer"]
|
|
153
|
+
if (parameters.service == "(All Services)")
|
|
154
|
+
services = "*"
|
|
155
|
+
let result= await adminLog.query([102003], services, topLogCount, startTime ,endTime , "VERBOSE")
|
|
156
|
+
let jsonRes = await result.json()
|
|
157
|
+
let allMessages = [].concat(jsonRes.logMessages)
|
|
158
|
+
allMessages = allMessages.filter(m => m.message.indexOf("-------- Environment ---") > -1 && m.message.indexOf("The network is built.") > -1 && m.methodName == 'BuildEngineLog')
|
|
159
|
+
while (jsonRes.hasMore)
|
|
160
|
+
{
|
|
161
|
+
//start paging
|
|
162
|
+
logger.info(`Aggregating messages... total so far ${allMessages.length} entries but more left, pulling logs before ${new Date(jsonRes.endTime)}`)
|
|
163
|
+
result= await adminLog.query([102003], services, pageSize, jsonRes.endTime, null, "VERBOSE")
|
|
164
|
+
jsonRes = await result.json()
|
|
165
|
+
|
|
166
|
+
allMessages = allMessages.concat(jsonRes.logMessages.filter(m => m.message.indexOf("-------- Environment ---") > -1 && m.message.indexOf("------ Trace Parameters ----") == -1))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
//validate logs missing elapsed populate it
|
|
173
|
+
allMessages = allMessages.map( m => {
|
|
174
|
+
try{
|
|
175
|
+
|
|
176
|
+
//The network is built. 0.093 seconds (4.982 total) - 29 MB memory
|
|
177
|
+
|
|
178
|
+
let re = /The network is built. [-+]?([0-9]*\.[0-9]+|[0-9]+) seconds \([-+]?([0-9]*\.[0-9]+|[0-9]+) total\)/;
|
|
179
|
+
let res = re.exec(m.message)
|
|
180
|
+
if (res && res.length > 1)
|
|
181
|
+
m.elapsed = res[2]
|
|
182
|
+
|
|
183
|
+
return m;
|
|
184
|
+
}
|
|
185
|
+
catch(ex){
|
|
186
|
+
return m;
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
await populateMessages(allMessages)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
async function loadUpdateSubnetworkLogs () {
|
|
198
|
+
//build table
|
|
199
|
+
const tblResult = document.getElementById("tblResult");
|
|
200
|
+
//clear
|
|
201
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
202
|
+
tblResult.appendChild(document.createTextNode("Loading...."));
|
|
203
|
+
|
|
204
|
+
parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
205
|
+
//create a new admin object (user might not be admin we won't use it until the user call log )
|
|
206
|
+
adminLog = new AdminLog(token, portal.serverUrl)
|
|
207
|
+
|
|
208
|
+
logger.info("Connected.")
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
const topLogCount = 1000;
|
|
212
|
+
const pageSize = 10000
|
|
213
|
+
|
|
214
|
+
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
console.log(`Querying subnetwork logs for ${parameters.service} for the last ${mins} minutes ...`)
|
|
218
|
+
const startTime = Date.now() - mins*60*1000
|
|
219
|
+
const endTime = Date.now();
|
|
220
|
+
let services = [parameters.service+ ".MapServer"]
|
|
221
|
+
if (parameters.service == "(All Services)")
|
|
222
|
+
services = "*"
|
|
223
|
+
let result= await adminLog.query([102003], services, topLogCount, startTime ,endTime , "VERBOSE")
|
|
224
|
+
let jsonRes = await result.json()
|
|
225
|
+
let allMessages = [].concat(jsonRes.logMessages)
|
|
226
|
+
allMessages = allMessages.filter(m => m.message.indexOf("---- Subnetwork Parameters ----") > -1)
|
|
227
|
+
while (jsonRes.hasMore)
|
|
228
|
+
{
|
|
229
|
+
//start paging
|
|
230
|
+
logger.info(`Aggregating messages... total so far ${allMessages.length} entries but more left, pulling logs before ${new Date(jsonRes.endTime)}`)
|
|
231
|
+
result= await adminLog.query([102003], services, pageSize, jsonRes.endTime, null, "VERBOSE")
|
|
232
|
+
jsonRes = await result.json()
|
|
233
|
+
|
|
234
|
+
allMessages = allMessages.concat(jsonRes.logMessages.filter(m => m.message.indexOf("---- Subnetwork Parameters ----") > -1))
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
//update subnetwork missing elapsed populate it
|
|
238
|
+
allMessages = allMessages.map( m => {
|
|
239
|
+
try{
|
|
240
|
+
|
|
241
|
+
let re = /Total \([-+]?([0-9]*\.[0-9]+|[0-9]+) seconds\)/;
|
|
242
|
+
let res = re.exec(m.message)
|
|
243
|
+
if (res && res.length > 1)
|
|
244
|
+
m.elapsed = res[1]
|
|
245
|
+
|
|
246
|
+
re = /Total update subnetwork time \([-+]?([0-9]*\.[0-9]+|[0-9]+) seconds\)/;
|
|
247
|
+
res = re.exec(m.message)
|
|
248
|
+
if (res && res.length > 1)
|
|
249
|
+
m.elapsed = res[1]
|
|
250
|
+
|
|
251
|
+
return m;
|
|
252
|
+
}
|
|
253
|
+
catch(ex){
|
|
254
|
+
return m;
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
await populateMessages(allMessages)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
async function loadAttributeRules () {
|
|
265
|
+
|
|
266
|
+
//build table
|
|
267
|
+
const tblResult = document.getElementById("tblResult");
|
|
268
|
+
tblResult.appendChild(document.createTextNode("Loading...."));
|
|
269
|
+
|
|
270
|
+
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
271
|
+
|
|
272
|
+
parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
273
|
+
//create a new admin object (user might not be admin we won't use it until the user call log )
|
|
274
|
+
adminLog = new AdminLog(token, portal.serverUrl)
|
|
275
|
+
|
|
276
|
+
let showMaxGuid = true
|
|
277
|
+
let showMinGuid = false
|
|
278
|
+
const startTime = Date.now() - mins*60*1000
|
|
279
|
+
const endTime = Date.now();
|
|
280
|
+
|
|
281
|
+
let services = [parameters.service+ ".MapServer"]
|
|
282
|
+
if (parameters.service == "(All Services)")
|
|
283
|
+
services = "*"
|
|
284
|
+
|
|
285
|
+
const pageSize = 10000 //maximum messages per page
|
|
286
|
+
logger.info(`Querying attribute rules logs for ${parameters.service} in the past ${mins} minutes...`)
|
|
287
|
+
let result= await adminLog.query([102003], services, pageSize, startTime ,endTime , "DEBUG")
|
|
288
|
+
let jsonRes = await result.json()
|
|
289
|
+
let allMessages = [].concat(jsonRes.logMessages)
|
|
290
|
+
|
|
291
|
+
while (jsonRes.hasMore && jsonRes.endTime > startTime)
|
|
292
|
+
{
|
|
293
|
+
//start paging
|
|
294
|
+
logger.info(`Aggregating messages... total so far ${allMessages.length} debug entries but more left, pulling logs before ${new Date(jsonRes.endTime)}`)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
result= await adminLog.query([102003], services, pageSize, jsonRes.endTime )
|
|
298
|
+
jsonRes = await result.json()
|
|
299
|
+
allMessages = allMessages.concat(jsonRes.logMessages)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const arMessages = allMessages
|
|
303
|
+
.filter(m => m.message.indexOf("Attribute rule execution complete:") > -1)
|
|
304
|
+
.map (m => JSON.parse(m.message.replace("Attribute rule execution complete:", "")))
|
|
305
|
+
.map( m => {
|
|
306
|
+
m["Elapsed Time (ms)"] = Math.round(m["Elapsed Time"]*1000000)/1000
|
|
307
|
+
// m["Arcade Evaluation Time:"] = Math.round(m["Arcade Evaluation Time:"]*1000,6)
|
|
308
|
+
//m.ArcadeTime = m["Arcade Evaluation Time:"]
|
|
309
|
+
|
|
310
|
+
delete m["Arcade Evaluation Time:"];
|
|
311
|
+
delete m["Elapsed Time"];
|
|
312
|
+
//delete m ['GlobalID'];
|
|
313
|
+
return m
|
|
314
|
+
})
|
|
315
|
+
.sort( (m1, m2) => m2["Elapsed Time (ms)"]- m1["Elapsed Time (ms)"])
|
|
316
|
+
.reduce( ( prev, cur ) => {
|
|
317
|
+
if (prev [cur["Rule name"]] === undefined)
|
|
318
|
+
{
|
|
319
|
+
prev [cur["Rule name"]] = {
|
|
320
|
+
"totalTime": 0,
|
|
321
|
+
"occurrence": 0,
|
|
322
|
+
"minTime": Number.MAX_SAFE_INTEGER,
|
|
323
|
+
"maxTime": -1,
|
|
324
|
+
"avgTime": 0,
|
|
325
|
+
"maxGuid": null,
|
|
326
|
+
"minGuid": null
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
prev [cur["Rule name"]].totalTime = prev [cur["Rule name"]].totalTime + cur["Elapsed Time (ms)"]
|
|
331
|
+
|
|
332
|
+
if (cur["Elapsed Time (ms)"] < prev [cur["Rule name"]].minTime ) {
|
|
333
|
+
prev [cur["Rule name"]].minTime = cur["Elapsed Time (ms)"];
|
|
334
|
+
prev [cur["Rule name"]].minGuid = cur["GlobalID"];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (cur["Elapsed Time (ms)"] > prev [cur["Rule name"]].maxTime ){
|
|
338
|
+
prev [cur["Rule name"]].maxTime = cur["Elapsed Time (ms)"];
|
|
339
|
+
prev [cur["Rule name"]].maxGuid = cur["GlobalID"];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
prev [cur["Rule name"]].occurrence++
|
|
343
|
+
|
|
344
|
+
prev [cur["Rule name"]].avgTime = prev [cur["Rule name"]].totalTime / prev [cur["Rule name"]].occurrence
|
|
345
|
+
|
|
346
|
+
return prev
|
|
347
|
+
}, {})
|
|
348
|
+
|
|
349
|
+
const rules = Object.keys(arMessages)
|
|
350
|
+
.map(a => {
|
|
351
|
+
const rule = {}
|
|
352
|
+
rule["Attribute Rule"] = a;
|
|
353
|
+
rule["Total Cost (ms)"] = parseFloat(arMessages[a].totalTime.toFixed(2))
|
|
354
|
+
if (!showMinGuid && !showMaxGuid) rule["Average Cost (ms)"] = parseFloat(arMessages[a].avgTime.toFixed(2))
|
|
355
|
+
rule["Max execution time (ms)"] = parseFloat(arMessages[a].maxTime.toFixed(2))
|
|
356
|
+
if (showMaxGuid) rule["Max GUID"] = arMessages[a].maxGuid
|
|
357
|
+
rule["Min execution time (ms)"] = parseFloat(arMessages[a].minTime.toFixed(2))
|
|
358
|
+
if (showMinGuid) rule["Min GUID"] = arMessages[a].minGuid
|
|
359
|
+
if (!showMinGuid && !showMaxGuid) rule["Occurrence"] = arMessages[a].occurrence;
|
|
360
|
+
return rule;
|
|
361
|
+
})
|
|
362
|
+
.sort( (m1, m2) => m2["Total Cost (ms)"] -m1["Total Cost (ms)"])
|
|
363
|
+
console.table(rules)
|
|
364
|
+
|
|
365
|
+
/*
|
|
366
|
+
Attribute Rule
|
|
367
|
+
│ Total Cost (ms)
|
|
368
|
+
│ Max execution time (ms)
|
|
369
|
+
│ Max GUID
|
|
370
|
+
│ Min execution time (m
|
|
371
|
+
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
const header = document.createElement("tr");
|
|
375
|
+
const cAttributeRule = document.createElement("th");
|
|
376
|
+
cAttributeRule.textContent = "Attribute Rule"
|
|
377
|
+
|
|
378
|
+
const cTotalCost = document.createElement("th");
|
|
379
|
+
cTotalCost.textContent = "Total Cost (ms)"
|
|
380
|
+
|
|
381
|
+
const cMaxExecutionTime = document.createElement("th");
|
|
382
|
+
cMaxExecutionTime.textContent = "Max execution time (ms)"
|
|
383
|
+
|
|
384
|
+
const cMaxGuid = document.createElement("th");
|
|
385
|
+
cMaxGuid.textContent = "Max GUID"
|
|
386
|
+
|
|
387
|
+
const cMinExecutionTime = document.createElement("th");
|
|
388
|
+
cMinExecutionTime.textContent = "Min execution time (ms)"
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
header.appendChild (cAttributeRule)
|
|
392
|
+
header.appendChild (cTotalCost)
|
|
393
|
+
header.appendChild (cMaxExecutionTime)
|
|
394
|
+
header.appendChild (cMaxGuid)
|
|
395
|
+
header.appendChild (cMinExecutionTime)
|
|
396
|
+
|
|
397
|
+
tblResult.appendChild(header)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
rules.forEach(rule =>
|
|
401
|
+
{
|
|
402
|
+
|
|
403
|
+
const logRow = document.createElement("tr");
|
|
404
|
+
const cAttributeRule = document.createElement("td");
|
|
405
|
+
cAttributeRule.textContent = rule["Attribute Rule"]
|
|
406
|
+
|
|
407
|
+
const cTotalCost = document.createElement("td");
|
|
408
|
+
cTotalCost.textContent = rule["Total Cost (ms)"]
|
|
409
|
+
|
|
410
|
+
const cMaxExecutionTime = document.createElement("td");
|
|
411
|
+
cMaxExecutionTime.textContent = rule["Max execution time (ms)"]
|
|
412
|
+
|
|
413
|
+
const cMaxGuid = document.createElement("td");
|
|
414
|
+
cMaxGuid.textContent = rule["Max GUID"]
|
|
415
|
+
|
|
416
|
+
const cMinExecutionTime = document.createElement("td");
|
|
417
|
+
cMinExecutionTime.textContent = rule["Min execution time (ms)"]
|
|
418
|
+
|
|
419
|
+
logRow.appendChild (cAttributeRule)
|
|
420
|
+
logRow.appendChild (cTotalCost)
|
|
421
|
+
logRow.appendChild (cMaxExecutionTime)
|
|
422
|
+
logRow.appendChild (cMaxGuid)
|
|
423
|
+
logRow.appendChild (cMinExecutionTime)
|
|
424
|
+
tblResult.appendChild(logRow)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
const totalARExecution = rules.reduce( (prev, cur) => prev + cur["Total Cost (ms)"], 0)
|
|
431
|
+
console.log(`Total time spend executing attribute rules (${Math.round(totalARExecution)} ms) (${Math.round(totalARExecution/1000)} s) (${Math.round(totalARExecution/(1000*60))} m)`)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
}
|
|
436
|
+
async function loadSQLLogs () {
|
|
437
|
+
|
|
438
|
+
//build table
|
|
439
|
+
const tblResult = document.getElementById("tblResult");
|
|
440
|
+
//clear
|
|
441
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
442
|
+
tblResult.appendChild(document.createTextNode("Loading...."));
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
446
|
+
|
|
447
|
+
//create a new admin object (user might not be admin we won't use it until the user call log )
|
|
448
|
+
adminLog = new AdminLog(token, portal.serverUrl)
|
|
449
|
+
|
|
450
|
+
logger.info("Connected.")
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
const topLogCount = 1000;
|
|
454
|
+
const pageSize = 10000
|
|
455
|
+
|
|
456
|
+
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
console.log(`Querying cursor sql logs for ${parameters.service} for the last ${mins} minutes ...`)
|
|
460
|
+
const startTime = Date.now() - mins*60*1000
|
|
461
|
+
const endTime = Date.now();
|
|
462
|
+
let services = [parameters.service+ ".MapServer"]
|
|
463
|
+
if (parameters.service == "(All Services)")
|
|
464
|
+
services = "*"
|
|
465
|
+
let result= await adminLog.query([102023], services, topLogCount, startTime ,endTime , "DEBUG")
|
|
466
|
+
let jsonRes = await result.json()
|
|
467
|
+
let allMessages = [].concat(jsonRes.logMessages)
|
|
468
|
+
allMessages = allMessages.filter(m => m.message.indexOf("EndCursor;") > -1)
|
|
469
|
+
while (jsonRes.hasMore)
|
|
470
|
+
{
|
|
471
|
+
//start paging
|
|
472
|
+
logger.info(`Aggregating messages... total so far ${allMessages.length} entries but more left, pulling logs before ${new Date(jsonRes.endTime)}`)
|
|
473
|
+
result= await adminLog.query([102023], services, pageSize, jsonRes.endTime, null, "DEBUG")
|
|
474
|
+
jsonRes = await result.json()
|
|
475
|
+
|
|
476
|
+
allMessages = allMessages.concat(jsonRes.logMessages.filter(m => m.message.indexOf("EndCursor;") > -1))
|
|
477
|
+
}
|
|
478
|
+
console.log ("Filtering messages...")
|
|
479
|
+
|
|
480
|
+
allMessages = allMessages
|
|
481
|
+
.map( m=> {
|
|
482
|
+
m.dataAccessElapsed = parseFloat(m.message.split(";")[1].split(" ")[1])
|
|
483
|
+
m.executeQueryElapsed = parseFloat(m.message.split(";")[2].split(" ")[1])
|
|
484
|
+
m.totalExecutionElapsed = m.dataAccessElapsed + m.executeQueryElapsed
|
|
485
|
+
m.elapsed = parseFloat(m.elapsed); return m;
|
|
486
|
+
|
|
487
|
+
})
|
|
488
|
+
.sort( (m1,m2) => m2.totalExecutionElapsed - m1.totalExecutionElapsed)
|
|
489
|
+
.slice(0, 100) ;//first 100
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
console.log("-----Top 10 SQL----")
|
|
493
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
494
|
+
|
|
495
|
+
let i =0;
|
|
496
|
+
|
|
497
|
+
const header = document.createElement("tr");
|
|
498
|
+
const cService = document.createElement("th");
|
|
499
|
+
cService.textContent = "Source"
|
|
500
|
+
const cTime = document.createElement("th");
|
|
501
|
+
cTime.textContent = "Time"
|
|
502
|
+
const cUser = document.createElement("th");
|
|
503
|
+
cUser.textContent = "User"
|
|
504
|
+
const cMethod = document.createElement("th");
|
|
505
|
+
cMethod.textContent = "Method"
|
|
506
|
+
const cQueryTime = document.createElement("th");
|
|
507
|
+
cQueryTime.textContent = "Query Time (ms)"
|
|
508
|
+
cQueryTime.title = "includes search + data access nextRow"
|
|
509
|
+
const cTotalTime = document.createElement("th");
|
|
510
|
+
cTotalTime.title = "Total time the cursor was opened"
|
|
511
|
+
cTotalTime.textContent = "Total Time (ms)"
|
|
512
|
+
const cLog = document.createElement("th");
|
|
513
|
+
cLog.textContent = "Full SQL"
|
|
514
|
+
header.appendChild (cService)
|
|
515
|
+
header.appendChild (cTime)
|
|
516
|
+
header.appendChild (cUser)
|
|
517
|
+
header.appendChild (cMethod)
|
|
518
|
+
header.appendChild (cQueryTime)
|
|
519
|
+
header.appendChild (cTotalTime)
|
|
520
|
+
header.appendChild (cLog)
|
|
521
|
+
tblResult.appendChild(header)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
allMessages= allMessages.forEach(m =>
|
|
525
|
+
{
|
|
526
|
+
|
|
527
|
+
const logRow = document.createElement("tr");
|
|
528
|
+
const x = m.message.split(";")
|
|
529
|
+
x.shift()
|
|
530
|
+
console.log(`id: ${i++}`)
|
|
531
|
+
console.log(`\tAt: ${new Date(m.time)} (${m.time})`)
|
|
532
|
+
console.log(`\tUser: ${m.user}`)
|
|
533
|
+
console.log(`\tTotal Time: ${numberWithCommas(Math.round(m.elapsed*1000))} ms (Total time the cursor was opened)`)
|
|
534
|
+
console.log(`\tQuery Time: ${numberWithCommas(m.totalExecutionElapsed)} ms (includes search + data access nextRow)`)
|
|
535
|
+
console.log(`\tQuery:`)
|
|
536
|
+
x.forEach(a => console.log(`\t${a}`))
|
|
537
|
+
console.log(`\n`)
|
|
538
|
+
|
|
539
|
+
const cService = document.createElement("th");
|
|
540
|
+
cService.textContent = m.source.replace(".MapServer", "")
|
|
541
|
+
|
|
542
|
+
const cTime = document.createElement("td");
|
|
543
|
+
cTime.textContent = new Date(m.time).toLocaleString()
|
|
544
|
+
|
|
545
|
+
const cUser = document.createElement("td");
|
|
546
|
+
cUser.textContent = m.user
|
|
547
|
+
const cMethod = document.createElement("td");
|
|
548
|
+
cMethod.textContent = "Cursor"
|
|
549
|
+
const cQueryTime = document.createElement("td");
|
|
550
|
+
cQueryTime.textContent = numberWithCommas(m.totalExecutionElapsed)
|
|
551
|
+
const cTotalTime = document.createElement("td");
|
|
552
|
+
cTotalTime.textContent = numberWithCommas(Math.round(m.elapsed*1000))
|
|
553
|
+
const cLog = document.createElement("td");
|
|
554
|
+
cLog.textContent = m.message.substr( m.message.indexOf("SQL: ") + 5, 50) + "..."
|
|
555
|
+
cLog.fullLog = m.message;
|
|
556
|
+
cLog.title = m.message + "\nClick to copy"
|
|
557
|
+
cLog.addEventListener("click", e=> {navigator.clipboard.writeText(e.target.fullLog); alert("Copied to clipboard")})
|
|
558
|
+
logRow.appendChild (cService)
|
|
559
|
+
logRow.appendChild (cTime)
|
|
560
|
+
logRow.appendChild (cUser)
|
|
561
|
+
logRow.appendChild (cMethod)
|
|
562
|
+
logRow.appendChild (cQueryTime)
|
|
563
|
+
logRow.appendChild (cTotalTime)
|
|
564
|
+
logRow.appendChild (cLog)
|
|
565
|
+
tblResult.appendChild(logRow)
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
})
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
//await populateMessages(allMessages)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
function numberWithCommas(x) {
|
|
583
|
+
// return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
584
|
+
return x.toLocaleString()
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
init();
|
|
588
|
+
|
|
589
|
+
const btnTraceLogs = document.getElementById("btnTraceLogs");
|
|
590
|
+
btnTraceLogs.addEventListener("click", e => loadTraceLogs())
|
|
591
|
+
|
|
592
|
+
const btnValidateLogs = document.getElementById("btnValidateLogs");
|
|
593
|
+
btnValidateLogs.addEventListener("click", e => loadValidateLogs())
|
|
594
|
+
|
|
595
|
+
const btnUpdateSubnetworkLogs = document.getElementById("btnUpdateSubnetworkLogs");
|
|
596
|
+
btnUpdateSubnetworkLogs.addEventListener("click", e => loadUpdateSubnetworkLogs())
|
|
597
|
+
|
|
598
|
+
const btnSQLLogs = document.getElementById("btnSQLLogs");
|
|
599
|
+
btnSQLLogs.addEventListener("click", e => loadSQLLogs())
|
|
600
|
+
|
|
601
|
+
const btnAR = document.getElementById("btnAR");
|
|
602
|
+
btnAR.addEventListener("click", e => loadAttributeRules())
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
async function populateMessages(allTheMessages) {
|
|
607
|
+
|
|
608
|
+
//sort messages
|
|
609
|
+
|
|
610
|
+
const allMessages = allTheMessages.map(m => {
|
|
611
|
+
const newMessage = Object.assign({}, m);
|
|
612
|
+
delete newMessage.machine;
|
|
613
|
+
delete newMessage.type;
|
|
614
|
+
delete newMessage.code;
|
|
615
|
+
delete newMessage.requestID;
|
|
616
|
+
delete newMessage.process;
|
|
617
|
+
delete newMessage.thread;
|
|
618
|
+
newMessage.elapsedms = parseInt (parseFloat(newMessage.elapsed) * 1000)
|
|
619
|
+
newMessage.time = new Date(newMessage.time).toLocaleString()
|
|
620
|
+
delete newMessage.elapsed
|
|
621
|
+
return newMessage;
|
|
622
|
+
})
|
|
623
|
+
.sort( (m1,m2) => m2.elapsedms - m1.elapsedms)
|
|
624
|
+
|
|
625
|
+
//build table
|
|
626
|
+
const tblResult = document.getElementById("tblResult");
|
|
627
|
+
//clear
|
|
628
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
629
|
+
|
|
630
|
+
const header = document.createElement("tr");
|
|
631
|
+
const cService = document.createElement("th");
|
|
632
|
+
cService.textContent = "Source"
|
|
633
|
+
const cTime = document.createElement("th");
|
|
634
|
+
cTime.textContent = "Time"
|
|
635
|
+
const cUser = document.createElement("th");
|
|
636
|
+
cUser.textContent = "User"
|
|
637
|
+
const cMethod = document.createElement("th");
|
|
638
|
+
cMethod.textContent = "Method"
|
|
639
|
+
const cElapsedMS = document.createElement("th");
|
|
640
|
+
cElapsedMS.textContent = "Elapsed (ms)"
|
|
641
|
+
const cLog = document.createElement("th");
|
|
642
|
+
cLog.textContent = "Full Log"
|
|
643
|
+
header.appendChild (cService)
|
|
644
|
+
header.appendChild (cTime)
|
|
645
|
+
header.appendChild (cUser)
|
|
646
|
+
header.appendChild (cMethod)
|
|
647
|
+
header.appendChild (cElapsedMS)
|
|
648
|
+
header.appendChild (cLog)
|
|
649
|
+
tblResult.appendChild(header)
|
|
650
|
+
allMessages.forEach(m => {
|
|
651
|
+
const logRow = document.createElement("tr");
|
|
652
|
+
const cService = document.createElement("td");
|
|
653
|
+
cService.textContent = m.source.replace(".MapServer", "")
|
|
654
|
+
const cTime = document.createElement("td");
|
|
655
|
+
cTime.textContent = m.time
|
|
656
|
+
const cUser = document.createElement("td");
|
|
657
|
+
cUser.textContent = m.user
|
|
658
|
+
const cMethod = document.createElement("td");
|
|
659
|
+
cMethod.textContent = m.methodName
|
|
660
|
+
const cElapsedMS = document.createElement("td");
|
|
661
|
+
cElapsedMS.textContent = m.elapsedms
|
|
662
|
+
const cLog = document.createElement("td");
|
|
663
|
+
cLog.textContent = "..."
|
|
664
|
+
cLog.fullLog = m.message;
|
|
665
|
+
cLog.addEventListener("click", e=> {navigator.clipboard.writeText(e.target.fullLog); alert("Copied to clipboard")})
|
|
666
|
+
logRow.appendChild (cService)
|
|
667
|
+
logRow.appendChild (cTime)
|
|
668
|
+
logRow.appendChild (cUser)
|
|
669
|
+
logRow.appendChild (cMethod)
|
|
670
|
+
logRow.appendChild (cElapsedMS)
|
|
671
|
+
logRow.appendChild (cLog)
|
|
672
|
+
tblResult.appendChild(logRow)
|
|
673
|
+
})
|
|
674
|
+
}
|
|
675
|
+
</script>
|
|
676
|
+
</body>
|
|
677
|
+
</html>
|