un-cli 0.0.84 → 0.0.86
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/README.md +56 -34
- package/examples.txt +4 -0
- package/index.html +335 -26
- package/index.mjs +142 -16
- package/package.json +1 -1
- package/utilitynetwork.node.mjs +6 -33
package/README.md
CHANGED
|
@@ -1,17 +1,68 @@
|
|
|
1
1
|
# uncli
|
|
2
|
-
utility network javascript command line works on Windows and Linux
|
|
2
|
+
Server Log Parser and utility network javascript command line works on Windows and Linux
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Server Log web parser
|
|
7
|
+
This tool also provides a way to parse server logs and view them for each utility network and geodatabase functions. (Note you do not need to install nodejs for the web parser)
|
|
8
|
+
|
|
9
|
+
### IIS
|
|
10
|
+
To install on IIS follow these steps: This server assume your machine name where the Webadaptor lives is `utilitynetwork.esri.com`
|
|
11
|
+
|
|
12
|
+
- Login to machine where you have the webadaptor
|
|
13
|
+
- Create a folder called `log` in `c:\inetpub\wwwroot`
|
|
14
|
+
- Copy the entire content of the repro https://github.com/hussein-nasser/uncli to c:\inetpub\wwwroot\log
|
|
15
|
+
- Open IIS (Internet Information Services)
|
|
16
|
+
- Open MIME Types
|
|
17
|
+
- Under action click Add
|
|
18
|
+
- under file extension type `.mjs` and under MIME Type write `application/javascript`
|
|
19
|
+
- Restart IIS
|
|
20
|
+
- (OPTIONAL only change when your webadaptor is not /portal) In c:\inetpub\wwwroot\log edit the `index.html` and find this line of code
|
|
21
|
+
- Update the JSON object with the correct URL, for example if your webadaptor is https://utilitynetwork.esri.com/portal set the "portal" to be that. You don't have to update the referer it will be automatically calculated it.
|
|
22
|
+
- (Optional) if you have multiple federated server , you have to set the correct one you want to query admin api for in the `"server"` parameter below.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
let parameters = {
|
|
26
|
+
"user": "unadmin",
|
|
27
|
+
"password": "",
|
|
28
|
+
"portal": "",
|
|
29
|
+
"service": "",
|
|
30
|
+
"referer": "",
|
|
31
|
+
"server": undefined
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
- Save the HTML and then visit `https://utilitynetwork.esri.com/log` put in your username and password and login to use the parser
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Tomcat or any other similar Webservers
|
|
38
|
+
-Create a folder under tomcat/webapps/ call it log
|
|
39
|
+
-Then copy the content there.
|
|
40
|
+
-Then go to /home/tomcat/conf/web.xml
|
|
41
|
+
-And add this entry if doesn’t exist
|
|
42
|
+
```xml
|
|
43
|
+
<mime-mapping>
|
|
44
|
+
<extension>mjs</extension>
|
|
45
|
+
<mime-type>text/javascript</mime-type>
|
|
46
|
+
</mime-mapping>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
-Restart tomcat and visit the page/log should work
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Utility Network Command Line tool (Utility Network Only)
|
|
55
|
+
### Download Node JS 13.5 or later
|
|
5
56
|
|
|
6
57
|
https://nodejs.org/en/
|
|
7
58
|
|
|
8
|
-
|
|
59
|
+
### Open command prompt and run this command
|
|
9
60
|
|
|
10
61
|
```bash
|
|
11
62
|
npm install -g un-cli
|
|
12
63
|
```
|
|
13
64
|
|
|
14
|
-
|
|
65
|
+
### Once installed here is how you connect
|
|
15
66
|
|
|
16
67
|
```bash
|
|
17
68
|
> uncli --portal https://utilitynetwork.esri.com/portal --service NapervilleElectric_SQLServer --user tester --password tester.108 --verify true
|
|
@@ -67,7 +118,7 @@ uncli> help
|
|
|
67
118
|
|
|
68
119
|
|
|
69
120
|
|
|
70
|
-
|
|
121
|
+
### Execute bulk of commands
|
|
71
122
|
Create a commands.txt file and type in the commands in that file
|
|
72
123
|
command.txt
|
|
73
124
|
```text
|
|
@@ -77,32 +128,3 @@ export subnetworks --new
|
|
|
77
128
|
|
|
78
129
|
|
|
79
130
|
> uncli --portal https://utilitynetwork.esri.com/portal --service NapervilleElectric_SQLServer --user tester --password tester.108 --file commands.txt --verify true
|
|
80
|
-
|
|
81
|
-
## Server Log web parser
|
|
82
|
-
This tool also provides a way to parse server logs and view them for each utility network and geodatabase function
|
|
83
|
-
|
|
84
|
-
To install on IIS follow these steps: This server assume your machine name where the Webadaptor lives is `utilitynetwork.esri.com`
|
|
85
|
-
|
|
86
|
-
- Login to machine where you have the webadaptor
|
|
87
|
-
- Create a folder called `log` in `c:\inetpub\wwwroot`
|
|
88
|
-
- Copy the entire content of the repro https://github.com/hussein-nasser/uncli to c:\inetpub\wwwroot\log
|
|
89
|
-
- Open IIS (Internet Information Services)
|
|
90
|
-
- Open MIME Types
|
|
91
|
-
- Under action click Add
|
|
92
|
-
- under file extension type `.mjs` and under MIME Type write `application/javascript`
|
|
93
|
-
- Restart IIS
|
|
94
|
-
- (OPTIONAL only change when your webadaptor is not /portal) In c:\inetpub\wwwroot\log edit the `index.html` and find this line of code
|
|
95
|
-
- Update the JSON object with the correct URL, for example if your webadaptor is https://utilitynetwork.esri.com/portal set the "portal" to be that. You don't have to update the referer it will be automatically calculated it.
|
|
96
|
-
- (Optional) if you have multiple federated server , you have to set the correct one you want to query admin api for in the `"server"` parameter below.
|
|
97
|
-
|
|
98
|
-
```js
|
|
99
|
-
let parameters = {
|
|
100
|
-
"user": "unadmin",
|
|
101
|
-
"password": "",
|
|
102
|
-
"portal": "",
|
|
103
|
-
"service": "",
|
|
104
|
-
"referer": "",
|
|
105
|
-
"server": undefined
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
- Save the HTML and then visit `https://utilitynetwork.esri.com/log` put in your username and password and login to use the parser
|
package/examples.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export subnetworks --all --resulttype [{"type":"features","includeGeometry":true,"includePropagatedValues":false,"includeDomainDescriptions":true,"networkAttributeNames":["Source ID","E:Riser"],"diagramTemplateName":"","resultTypeFields":[{"networkSourceId":14,"fieldName":"GLOBALID"},{"networkSourceId":15,"fieldName":"CLUSTERKEY"},{"networkSourceId":9,"fieldName":"LIFECYCLESTATUS"},{"networkSourceId":4,"fieldName":"ASSETGROUP"},{"networkSourceId":12,"fieldName":"ASSETGROUP"}]},{"type":"connectivity","includeGeometry":true,"includePropagatedValues":false,"includeDomainDescriptions":true,"networkAttributeNames":[],"diagramTemplateName":"","resultTypeFields":[]},{"type":"associations","includeGeometry":false,"includePropagatedValues":false,"includeDomainDescriptions":true,"networkAttributeNames":[],"diagramTemplateName":"","resultTypeFields":[]}]
|
|
2
|
+
update subnewtorks --all
|
|
3
|
+
topology --validate
|
|
4
|
+
trace --subnetwork test
|
package/index.html
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
<td>Method Name</td>
|
|
55
55
|
<td><input id = 'txtMethodName' type = 'text'></td>
|
|
56
56
|
<td>RequestID</td>
|
|
57
|
-
<td colspan =3><input id = 'txtRequestId' type = 'text'></td>
|
|
57
|
+
<td colspan =3><input id = 'txtRequestId' type = 'text' style="width:250px"></td>
|
|
58
58
|
</tr>
|
|
59
59
|
</table>
|
|
60
60
|
|
|
@@ -69,13 +69,15 @@
|
|
|
69
69
|
<button id = 'btnApplyEditsLogs'>ApplyEdits Logs</button>
|
|
70
70
|
<button id = 'btnQueryLogs'>Query Logs</button>
|
|
71
71
|
<button id = 'btnReconcileLogs'>Reconcile Logs</button>
|
|
72
|
+
<button id = 'btnstartEditingLogs'>StartEditing Logs</button>
|
|
72
73
|
<button id = 'btnstopEditingLogs'>StopEditing Logs</button>
|
|
73
|
-
<button id = 'btnWaitLogs'>Wait Logs</button>
|
|
74
|
+
<button id = 'btnWaitLogs'>Startup and Wait Logs</button>
|
|
74
75
|
<button id = 'btnDownloadLogs'>Raw Logs</button>
|
|
75
76
|
</td>
|
|
76
77
|
|
|
77
78
|
</tr>
|
|
78
79
|
<tr><td colspan=9><small>Elapsed time is in minutes:seconds:milliseconds</small></td></tr>
|
|
80
|
+
<tr><td colspan=9><small>To capture the logs effectively, enable debug logging from server manager, login as admin, run the operation (e.g. edit in Pro) and click the corresponding logs to load.</small></td></tr>
|
|
79
81
|
</table>
|
|
80
82
|
|
|
81
83
|
<table id = 'tblResult' border =1 cellpadding = 4 cellspacing = 4 style="text-align:left">
|
|
@@ -170,6 +172,7 @@
|
|
|
170
172
|
document.getElementById("btnDownloadLogs").disabled = false
|
|
171
173
|
document.getElementById("btnReconcileLogs").disabled = false
|
|
172
174
|
document.getElementById("btnstopEditingLogs").disabled = false
|
|
175
|
+
document.getElementById("btnstartEditingLogs").disabled = false
|
|
173
176
|
document.getElementById("btnWaitLogs").disabled = false
|
|
174
177
|
|
|
175
178
|
|
|
@@ -239,7 +242,9 @@
|
|
|
239
242
|
|
|
240
243
|
x = /Moment:.*\r\n/.exec(m.message);
|
|
241
244
|
if (x && x.length > 0) newMessage.moment = x[0].replace("Moment:", "").replace("\r\n", "") * 1000000
|
|
242
|
-
|
|
245
|
+
|
|
246
|
+
x = /Moment:\s*([\d.]+)/.exec(m.message);
|
|
247
|
+
if (x) newMessage.moment = parseFloat(x[1]) * 1000000;
|
|
243
248
|
|
|
244
249
|
}
|
|
245
250
|
catch(ex){
|
|
@@ -261,8 +266,6 @@
|
|
|
261
266
|
cTime.textContent = "Time"
|
|
262
267
|
const cUser = document.createElement("th");
|
|
263
268
|
cUser.textContent = "User"
|
|
264
|
-
const cMethod = document.createElement("th");
|
|
265
|
-
cMethod.textContent = "Method"
|
|
266
269
|
const cVersion = document.createElement("th");
|
|
267
270
|
cVersion.textContent = "Version"
|
|
268
271
|
const cMoment = document.createElement("th");
|
|
@@ -273,6 +276,8 @@
|
|
|
273
276
|
cTraceType.textContent = "Trace Type"
|
|
274
277
|
const cTraceTime = document.createElement("th");
|
|
275
278
|
cTraceTime.textContent = "Trace Time"
|
|
279
|
+
const cReadAmp = document.createElement("th");
|
|
280
|
+
cReadAmp.textContent = "Elements / Pages"
|
|
276
281
|
const cRequestId = document.createElement("th");
|
|
277
282
|
cRequestId.textContent = "RequestId"
|
|
278
283
|
const cLog = document.createElement("th");
|
|
@@ -280,11 +285,11 @@
|
|
|
280
285
|
header.appendChild (cService)
|
|
281
286
|
header.appendChild (cTime)
|
|
282
287
|
header.appendChild (cUser)
|
|
283
|
-
header.appendChild (cMethod)
|
|
284
288
|
header.appendChild (cVersion)
|
|
285
289
|
header.appendChild (cMoment)
|
|
286
290
|
header.appendChild (cTraceType)
|
|
287
291
|
header.appendChild (cTraceTime)
|
|
292
|
+
header.appendChild (cReadAmp)
|
|
288
293
|
header.appendChild (cRequestId)
|
|
289
294
|
header.appendChild (cElapsedMS)
|
|
290
295
|
|
|
@@ -306,6 +311,8 @@
|
|
|
306
311
|
cTraceType.textContent = m.traceType
|
|
307
312
|
const cTraceTime = document.createElement("td");
|
|
308
313
|
cTraceTime.textContent = msToMinSecMs(m.traceTime)
|
|
314
|
+
const cReadAmp = document.createElement("td");
|
|
315
|
+
cReadAmp.textContent = ParseTraceReadAmplication(m.message)
|
|
309
316
|
const cRequestId = document.createElement("td");
|
|
310
317
|
cRequestId.textContent = m.requestID
|
|
311
318
|
const cVersion = document.createElement("td");
|
|
@@ -319,11 +326,11 @@
|
|
|
319
326
|
logRow.appendChild (cService)
|
|
320
327
|
logRow.appendChild (cTime)
|
|
321
328
|
logRow.appendChild (cUser)
|
|
322
|
-
logRow.appendChild (cMethod)
|
|
323
329
|
logRow.appendChild (cVersion)
|
|
324
330
|
logRow.appendChild (cMoment)
|
|
325
331
|
logRow.appendChild (cTraceType)
|
|
326
332
|
logRow.appendChild (cTraceTime)
|
|
333
|
+
logRow.appendChild (cReadAmp)
|
|
327
334
|
logRow.appendChild (cRequestId)
|
|
328
335
|
logRow.appendChild (cElapsedMS)
|
|
329
336
|
|
|
@@ -379,9 +386,16 @@
|
|
|
379
386
|
let x ;
|
|
380
387
|
x = /Extent:.*\r\n/.exec(m.message);
|
|
381
388
|
if (x && x.length > 0) m.extent = x[0].replace("Extent:", "").replace("\r\n", "")
|
|
389
|
+
|
|
390
|
+
x = /"extent":\{[^}]+\}/.exec(m.message);
|
|
391
|
+
if (x) m.extent = x[0].replace(`"extent":`,"")
|
|
392
|
+
|
|
382
393
|
x = /Version name:.*\r\n/.exec(m.message);
|
|
383
394
|
if (x && x.length > 0) m.versionName = x[0].replace("Version name:", "").replace("\r\n", "")
|
|
384
395
|
|
|
396
|
+
x = /Version name:(.*)/.exec(m.message);
|
|
397
|
+
if (x) m.versionName = x[1].trim();
|
|
398
|
+
|
|
385
399
|
let re = new RegExp(`Network built. [-+]?([0-9]*\\.[0-9]+|[0-9]+) seconds \\([-+]?([0-9]*\\.[0-9]+|[0-9]+) total\\)`)
|
|
386
400
|
let res = re.exec(m.message)
|
|
387
401
|
|
|
@@ -510,6 +524,7 @@
|
|
|
510
524
|
|
|
511
525
|
const cRequestId = document.createElement("th");
|
|
512
526
|
cRequestId.textContent = "RequestId"
|
|
527
|
+
|
|
513
528
|
const cLog = document.createElement("th");
|
|
514
529
|
cLog.textContent = "Full Log"
|
|
515
530
|
|
|
@@ -547,6 +562,12 @@
|
|
|
547
562
|
|
|
548
563
|
const cRequestId = document.createElement("td");
|
|
549
564
|
cRequestId.textContent = m.requestID;
|
|
565
|
+
cRequestId.style.color = "blue";
|
|
566
|
+
cRequestId.style.textDecoration = "underline";
|
|
567
|
+
cRequestId.style.cursor = "pointer";
|
|
568
|
+
cRequestId.style.fontOpticalSizing
|
|
569
|
+
cRequestId.addEventListener("click", e=> viewRawLogs( m.requestID ) );
|
|
570
|
+
|
|
550
571
|
const cLog = document.createElement("td");
|
|
551
572
|
cLog.textContent = "..."
|
|
552
573
|
cLog.fullLog = m.message;
|
|
@@ -678,6 +699,12 @@ async function loadUpdateSubnetworkLogs () {
|
|
|
678
699
|
cSubnetworkName.textContent = m.subnetworkName
|
|
679
700
|
const cRequestId = document.createElement("td");
|
|
680
701
|
cRequestId.textContent = m.requestID
|
|
702
|
+
cRequestId.style.color = "blue";
|
|
703
|
+
cRequestId.style.textDecoration = "underline";
|
|
704
|
+
cRequestId.style.cursor = "pointer";
|
|
705
|
+
cRequestId.style.fontOpticalSizing
|
|
706
|
+
cRequestId.addEventListener("click", e=> viewRawLogs( m.requestID ) );
|
|
707
|
+
|
|
681
708
|
const cLog = document.createElement("td");
|
|
682
709
|
cLog.textContent = "..."
|
|
683
710
|
cLog.fullLog = m.message;
|
|
@@ -719,7 +746,7 @@ async function loadAttributeRules () {
|
|
|
719
746
|
|
|
720
747
|
const arMessages = filterMessages(allMessages)
|
|
721
748
|
.filter(m => m.message.indexOf("Attribute rule executed: ") > -1)
|
|
722
|
-
.map (m =>
|
|
749
|
+
.map (m => decodeAndParseJSON(m.message.replace("Attribute rule executed: ", "")))
|
|
723
750
|
.map( m => {
|
|
724
751
|
m["Elapsed Time (ms)"] = Math.round(m["Elapsed Time"]*1000000)/1000
|
|
725
752
|
// m["Arcade Evaluation Time:"] = Math.round(m["Arcade Evaluation Time:"]*1000,6)
|
|
@@ -1016,7 +1043,8 @@ console.log(`Querying applyEdits logs for ${parameters.service} for the last ${m
|
|
|
1016
1043
|
if (m.message.indexOf("GraphicFeatureServer::HandleRESTRequest ## inputJSON ") > -1)
|
|
1017
1044
|
{
|
|
1018
1045
|
applyEditslogs[m.requestID].message = m.message.replace("GraphicFeatureServer::HandleRESTRequest ## inputJSON = ","")
|
|
1019
|
-
|
|
1046
|
+
applyEditslogs[m.requestID].message = decodeHTMLEntities(applyEditslogs[m.requestID].message)
|
|
1047
|
+
const applyEditsPayload = decodeAndParseJSON(applyEditslogs[m.requestID].message)
|
|
1020
1048
|
applyEditslogs[m.requestID].gdbVersion = applyEditsPayload.gdbVersion
|
|
1021
1049
|
applyEditslogs[m.requestID].ids = [...new Set(applyEditsPayload.edits.reduce ( (prev, cur) => {prev.push(cur.id); return prev}, []) )];
|
|
1022
1050
|
}
|
|
@@ -1066,6 +1094,13 @@ console.log(`Querying applyEdits logs for ${parameters.service} for the last ${m
|
|
|
1066
1094
|
const cRequestId = document.createElement("td");
|
|
1067
1095
|
cRequestId.textContent = m.requestID
|
|
1068
1096
|
|
|
1097
|
+
cRequestId.style.color = "blue";
|
|
1098
|
+
cRequestId.style.textDecoration = "underline";
|
|
1099
|
+
cRequestId.style.cursor = "pointer";
|
|
1100
|
+
cRequestId.style.fontOpticalSizing
|
|
1101
|
+
cRequestId.addEventListener("click", e=> viewRawLogs( m.requestID ) );
|
|
1102
|
+
|
|
1103
|
+
|
|
1069
1104
|
const cLog = document.createElement("td");
|
|
1070
1105
|
const cLogText = document.createElement("input")
|
|
1071
1106
|
cLogText.type = "text"
|
|
@@ -1097,6 +1132,7 @@ console.log(`Querying applyEdits logs for ${parameters.service} for the last ${m
|
|
|
1097
1132
|
|
|
1098
1133
|
async function stopEditingLogs () {
|
|
1099
1134
|
|
|
1135
|
+
|
|
1100
1136
|
//build table
|
|
1101
1137
|
const tblResult = document.getElementById("tblResult");
|
|
1102
1138
|
//clear
|
|
@@ -1109,7 +1145,7 @@ parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
|
1109
1145
|
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
1110
1146
|
|
|
1111
1147
|
|
|
1112
|
-
console.log(`Querying
|
|
1148
|
+
console.log(`Querying start editing logs for ${parameters.service} for the last ${mins} minutes ...`)
|
|
1113
1149
|
|
|
1114
1150
|
//startTime is the most recent
|
|
1115
1151
|
//endTime is the oldest
|
|
@@ -1158,20 +1194,22 @@ console.log(`Querying stop editing logs for ${parameters.service} for the last $
|
|
|
1158
1194
|
const queryLogs = {}
|
|
1159
1195
|
//sort by time
|
|
1160
1196
|
allMessages = allMessages.sort ( (m1, m2) => m2.time - m1.time )
|
|
1197
|
+
// allMessages = allMessages.filter( m => m.methodName.indexOf("Geodatabase.FeatureDataset.StartEditing") > -1 )
|
|
1161
1198
|
allMessages.forEach (m => {
|
|
1162
1199
|
|
|
1163
1200
|
if (!queryLogs[m.requestID])
|
|
1164
1201
|
queryLogs[m.requestID] = {"message": "Time,Method,Elapsed_ms,Message"}
|
|
1165
1202
|
|
|
1166
|
-
|
|
1203
|
+
if (m.methodName.indexOf("Geodatabase.FeatureDataset.StopEditing") > -1)
|
|
1204
|
+
queryLogs[m.requestID].message += "\r\n" + m.time + "," + m.methodName + "," + Math.round(m.elapsed*1000) + "," + m.message
|
|
1167
1205
|
|
|
1168
1206
|
//get elapsed
|
|
1169
1207
|
//check for async (method GPReconcileVersionAsync::Execute)
|
|
1170
1208
|
//sync
|
|
1171
1209
|
//VersionManagementServer::HandleREST_ReconcileOperation
|
|
1172
1210
|
//message Returned moment:
|
|
1173
|
-
if ( m.methodName.indexOf("
|
|
1174
|
-
&& m.message.indexOf("
|
|
1211
|
+
if ( m.methodName.indexOf("Geodatabase.FeatureDataset.StopEditing") > -1
|
|
1212
|
+
&& m.message.indexOf("Starting editing") > -1
|
|
1175
1213
|
)
|
|
1176
1214
|
{
|
|
1177
1215
|
queryLogs[m.requestID].elapsed = m.elapsed
|
|
@@ -1180,13 +1218,13 @@ console.log(`Querying stop editing logs for ${parameters.service} for the last $
|
|
|
1180
1218
|
queryLogs[m.requestID].time = m.time
|
|
1181
1219
|
queryLogs[m.requestID].requestID = m.requestID
|
|
1182
1220
|
queryLogs[m.requestID].methodName = m.methodName.replace("VersionManagementServer::HandleREST_","")
|
|
1183
|
-
|
|
1221
|
+
queryLogs[m.requestID].textMessage = m.message
|
|
1184
1222
|
}
|
|
1185
1223
|
|
|
1186
1224
|
if (m.message.indexOf("In WorkspaceInfo::GetVersionedWorkspaceInfo : Cache hit for versionOrBranchName=") > -1)
|
|
1187
1225
|
{
|
|
1188
|
-
let v = m.message.replace("
|
|
1189
|
-
v = v.substr(v.indexOf("
|
|
1226
|
+
let v = m.message.replace(" In WorkspaceInfo::GetVersionedWorkspaceInfo : Cache hit for versionOrBranchName=","")
|
|
1227
|
+
v = v.substr(v.indexOf(":")+1)
|
|
1190
1228
|
queryLogs[m.requestID].gdbVersion =v
|
|
1191
1229
|
|
|
1192
1230
|
}
|
|
@@ -1195,6 +1233,7 @@ console.log(`Querying stop editing logs for ${parameters.service} for the last $
|
|
|
1195
1233
|
|
|
1196
1234
|
})
|
|
1197
1235
|
|
|
1236
|
+
/*
|
|
1198
1237
|
allMessages = []
|
|
1199
1238
|
|
|
1200
1239
|
Object.keys(queryLogs).forEach(k =>
|
|
@@ -1205,14 +1244,17 @@ console.log(`Querying stop editing logs for ${parameters.service} for the last $
|
|
|
1205
1244
|
|
|
1206
1245
|
})
|
|
1207
1246
|
|
|
1208
|
-
|
|
1247
|
+
*/
|
|
1209
1248
|
|
|
1210
1249
|
console.log ("Filtering messages...")
|
|
1211
|
-
|
|
1250
|
+
allMessages = allMessages.filter( m => m.methodName.indexOf("Geodatabase.FeatureDataset.StopEditing") > -1 )
|
|
1251
|
+
|
|
1212
1252
|
allMessages = filterMessages(allMessages)
|
|
1213
1253
|
.sort( (m1,m2) => Math.round(m2.elapsed*1000) -Math.round(m1.elapsed*1000))
|
|
1214
1254
|
|
|
1215
1255
|
allMessages.forEach (m => {
|
|
1256
|
+
|
|
1257
|
+
|
|
1216
1258
|
const logRow = document.createElement("tr");
|
|
1217
1259
|
|
|
1218
1260
|
const cService = document.createElement("th");
|
|
@@ -1225,21 +1267,27 @@ console.log(`Querying stop editing logs for ${parameters.service} for the last $
|
|
|
1225
1267
|
cUser.textContent = m.user
|
|
1226
1268
|
|
|
1227
1269
|
const cVersion = document.createElement("td");
|
|
1228
|
-
cVersion.textContent =
|
|
1270
|
+
cVersion.textContent = queryLogs[m.requestID].gdbVersion
|
|
1229
1271
|
|
|
1230
1272
|
const cMethodName = document.createElement("td");
|
|
1231
1273
|
cMethodName.textContent = m.methodName
|
|
1232
1274
|
|
|
1233
1275
|
const cRequestId = document.createElement("td");
|
|
1234
|
-
cRequestId.textContent = m.requestID
|
|
1235
|
-
|
|
1276
|
+
cRequestId.textContent = m.requestID
|
|
1277
|
+
|
|
1278
|
+
cRequestId.style.color = "blue";
|
|
1279
|
+
cRequestId.style.textDecoration = "underline";
|
|
1280
|
+
cRequestId.style.cursor = "pointer";
|
|
1281
|
+
cRequestId.style.fontOpticalSizing
|
|
1282
|
+
cRequestId.addEventListener("click", e=> viewRawLogs( m.requestID ) );
|
|
1283
|
+
|
|
1236
1284
|
const cTotalTime = document.createElement("td");
|
|
1237
1285
|
cTotalTime.textContent = msToMinSecMs(m.elapsed*1000 )
|
|
1238
1286
|
const cLog = document.createElement("td");
|
|
1239
|
-
cLog.textContent =
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1287
|
+
cLog.textContent = m.message
|
|
1288
|
+
// cLog.title = "Click to copy full startediting log"
|
|
1289
|
+
// cLog.fullLog = m.message;
|
|
1290
|
+
// cLog.addEventListener("click", e=> {navigator.clipboard.writeText(e.target.fullLog); alert("Copied to clipboard")})
|
|
1243
1291
|
|
|
1244
1292
|
//cLog.fullLog = m.payLoad;
|
|
1245
1293
|
//cLog.title = m.payLoad + "\nClick to copy"
|
|
@@ -1267,6 +1315,197 @@ console.log(`Querying stop editing logs for ${parameters.service} for the last $
|
|
|
1267
1315
|
|
|
1268
1316
|
|
|
1269
1317
|
|
|
1318
|
+
async function viewRawLogs(requestId){
|
|
1319
|
+
|
|
1320
|
+
const txtRequestId = document.getElementById("txtRequestId")
|
|
1321
|
+
txtRequestId.value = requestId;
|
|
1322
|
+
document.getElementById("btnDownloadLogs").click();
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
async function startEditingLogs () {
|
|
1329
|
+
|
|
1330
|
+
//build table
|
|
1331
|
+
const tblResult = document.getElementById("tblResult");
|
|
1332
|
+
//clear
|
|
1333
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
1334
|
+
|
|
1335
|
+
|
|
1336
|
+
parameters.service = cmbService.options[cmbService.selectedIndex].text
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
let mins = document.getElementById("txtAge").value //query logs for the last 30 minutes
|
|
1340
|
+
|
|
1341
|
+
|
|
1342
|
+
console.log(`Querying start editing logs for ${parameters.service} for the last ${mins} minutes ...`)
|
|
1343
|
+
|
|
1344
|
+
//startTime is the most recent
|
|
1345
|
+
//endTime is the oldest
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
//page query the admin log , search for /stopediting logs by methodname
|
|
1349
|
+
let allMessages = await adminLogQueryWithPaging(mins, parameters.service, [102003,17003], "", "DEBUG")
|
|
1350
|
+
|
|
1351
|
+
|
|
1352
|
+
while(tblResult.firstChild) tblResult.removeChild(tblResult.firstChild)
|
|
1353
|
+
|
|
1354
|
+
let i =0;
|
|
1355
|
+
|
|
1356
|
+
const header = document.createElement("tr");
|
|
1357
|
+
const cService = document.createElement("th");
|
|
1358
|
+
cService.textContent = "Source"
|
|
1359
|
+
const cTime = document.createElement("th");
|
|
1360
|
+
cTime.textContent = "Time"
|
|
1361
|
+
const cUser = document.createElement("th");
|
|
1362
|
+
cUser.textContent = "User"
|
|
1363
|
+
const cVersion = document.createElement("th");
|
|
1364
|
+
cVersion.textContent = "Version"
|
|
1365
|
+
const cMethodName = document.createElement("th");
|
|
1366
|
+
cMethodName.textContent = "MethodName"
|
|
1367
|
+
const cRequestId = document.createElement("th");
|
|
1368
|
+
cRequestId.textContent = "RequestId"
|
|
1369
|
+
const cTotalTime = document.createElement("th");
|
|
1370
|
+
cTotalTime.title = "Total time startEditing took"
|
|
1371
|
+
cTotalTime.textContent = "Total Time"
|
|
1372
|
+
|
|
1373
|
+
|
|
1374
|
+
const cLog = document.createElement("th");
|
|
1375
|
+
cLog.textContent = "StartEditing details"
|
|
1376
|
+
header.appendChild (cService)
|
|
1377
|
+
header.appendChild (cTime)
|
|
1378
|
+
header.appendChild (cUser)
|
|
1379
|
+
header.appendChild (cVersion)
|
|
1380
|
+
header.appendChild (cMethodName)
|
|
1381
|
+
header.appendChild (cRequestId)
|
|
1382
|
+
header.appendChild (cTotalTime)
|
|
1383
|
+
|
|
1384
|
+
header.appendChild (cLog)
|
|
1385
|
+
tblResult.appendChild(header)
|
|
1386
|
+
|
|
1387
|
+
//build out the dictionary, key is request id, value is another dictionary
|
|
1388
|
+
const queryLogs = {}
|
|
1389
|
+
//sort by time
|
|
1390
|
+
allMessages = allMessages.sort ( (m1, m2) => m2.time - m1.time )
|
|
1391
|
+
// allMessages = allMessages.filter( m => m.methodName.indexOf("Geodatabase.FeatureDataset.StartEditing") > -1 )
|
|
1392
|
+
allMessages.forEach (m => {
|
|
1393
|
+
|
|
1394
|
+
if (!queryLogs[m.requestID])
|
|
1395
|
+
queryLogs[m.requestID] = {"message": "Time,Method,Elapsed_ms,Message"}
|
|
1396
|
+
|
|
1397
|
+
if (m.methodName.indexOf("Geodatabase.FeatureDataset.StartEditing") > -1)
|
|
1398
|
+
queryLogs[m.requestID].message += "\r\n" + m.time + "," + m.methodName + "," + Math.round(m.elapsed*1000) + "," + m.message
|
|
1399
|
+
|
|
1400
|
+
//get elapsed
|
|
1401
|
+
//check for async (method GPReconcileVersionAsync::Execute)
|
|
1402
|
+
//sync
|
|
1403
|
+
//VersionManagementServer::HandleREST_ReconcileOperation
|
|
1404
|
+
//message Returned moment:
|
|
1405
|
+
if ( m.methodName.indexOf("Geodatabase.FeatureDataset.StartEditing") > -1
|
|
1406
|
+
&& m.message.indexOf("Starting editing") > -1
|
|
1407
|
+
)
|
|
1408
|
+
{
|
|
1409
|
+
queryLogs[m.requestID].elapsed = m.elapsed
|
|
1410
|
+
queryLogs[m.requestID].source = m.source.replace(".MapServer", "")
|
|
1411
|
+
queryLogs[m.requestID].user = m.user
|
|
1412
|
+
queryLogs[m.requestID].time = m.time
|
|
1413
|
+
queryLogs[m.requestID].requestID = m.requestID
|
|
1414
|
+
queryLogs[m.requestID].methodName = m.methodName.replace("VersionManagementServer::HandleREST_","")
|
|
1415
|
+
queryLogs[m.requestID].textMessage = m.message
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (m.message.indexOf("In WorkspaceInfo::GetVersionedWorkspaceInfo : Cache hit for versionOrBranchName=") > -1)
|
|
1419
|
+
{
|
|
1420
|
+
let v = m.message.replace(" In WorkspaceInfo::GetVersionedWorkspaceInfo : Cache hit for versionOrBranchName=","")
|
|
1421
|
+
v = v.substr(v.indexOf(":")+1)
|
|
1422
|
+
queryLogs[m.requestID].gdbVersion =v
|
|
1423
|
+
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
})
|
|
1429
|
+
|
|
1430
|
+
/*
|
|
1431
|
+
allMessages = []
|
|
1432
|
+
|
|
1433
|
+
Object.keys(queryLogs).forEach(k =>
|
|
1434
|
+
{
|
|
1435
|
+
const m = queryLogs[k]
|
|
1436
|
+
if (m.methodName)
|
|
1437
|
+
allMessages.push(m)
|
|
1438
|
+
|
|
1439
|
+
})
|
|
1440
|
+
|
|
1441
|
+
*/
|
|
1442
|
+
|
|
1443
|
+
console.log ("Filtering messages...")
|
|
1444
|
+
allMessages = allMessages.filter( m => m.methodName.indexOf("Geodatabase.FeatureDataset.StartEditing") > -1 )
|
|
1445
|
+
|
|
1446
|
+
allMessages = filterMessages(allMessages)
|
|
1447
|
+
.sort( (m1,m2) => Math.round(m2.elapsed*1000) -Math.round(m1.elapsed*1000))
|
|
1448
|
+
|
|
1449
|
+
allMessages.forEach (m => {
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
const logRow = document.createElement("tr");
|
|
1453
|
+
|
|
1454
|
+
const cService = document.createElement("th");
|
|
1455
|
+
cService.textContent = m.source
|
|
1456
|
+
|
|
1457
|
+
const cTime = document.createElement("td");
|
|
1458
|
+
cTime.textContent = new Date(m.time).toLocaleString()
|
|
1459
|
+
|
|
1460
|
+
const cUser = document.createElement("td");
|
|
1461
|
+
cUser.textContent = m.user
|
|
1462
|
+
|
|
1463
|
+
const cVersion = document.createElement("td");
|
|
1464
|
+
cVersion.textContent = queryLogs[m.requestID].gdbVersion
|
|
1465
|
+
|
|
1466
|
+
const cMethodName = document.createElement("td");
|
|
1467
|
+
cMethodName.textContent = m.methodName
|
|
1468
|
+
|
|
1469
|
+
const cRequestId = document.createElement("td");
|
|
1470
|
+
cRequestId.textContent = m.requestID
|
|
1471
|
+
cRequestId.style.color = "blue";
|
|
1472
|
+
cRequestId.style.textDecoration = "underline";
|
|
1473
|
+
cRequestId.style.cursor = "pointer";
|
|
1474
|
+
cRequestId.style.fontOpticalSizing
|
|
1475
|
+
cRequestId.addEventListener("click", e=> viewRawLogs( m.requestID ) );
|
|
1476
|
+
|
|
1477
|
+
const cTotalTime = document.createElement("td");
|
|
1478
|
+
cTotalTime.textContent = msToMinSecMs(m.elapsed*1000 )
|
|
1479
|
+
const cLog = document.createElement("td");
|
|
1480
|
+
cLog.textContent = m.message
|
|
1481
|
+
// cLog.title = "Click to copy full startediting log"
|
|
1482
|
+
// cLog.fullLog = m.message;
|
|
1483
|
+
// cLog.addEventListener("click", e=> {navigator.clipboard.writeText(e.target.fullLog); alert("Copied to clipboard")})
|
|
1484
|
+
|
|
1485
|
+
//cLog.fullLog = m.payLoad;
|
|
1486
|
+
//cLog.title = m.payLoad + "\nClick to copy"
|
|
1487
|
+
// cLog.addEventListener("click", e=> {navigator.clipboard.writeText(e.target.fullLog); e.target.selectionStart = 0; e.target.selectionEnd = e.target.value.length;
|
|
1488
|
+
// alert("Copied to clipboard") })
|
|
1489
|
+
logRow.appendChild (cService)
|
|
1490
|
+
logRow.appendChild (cTime)
|
|
1491
|
+
logRow.appendChild (cUser)
|
|
1492
|
+
logRow.appendChild (cVersion)
|
|
1493
|
+
logRow.appendChild (cMethodName)
|
|
1494
|
+
logRow.appendChild (cRequestId)
|
|
1495
|
+
logRow.appendChild (cTotalTime)
|
|
1496
|
+
|
|
1497
|
+
logRow.appendChild (cLog)
|
|
1498
|
+
tblResult.appendChild(logRow)
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
addCSV(allMessages)
|
|
1502
|
+
|
|
1503
|
+
|
|
1504
|
+
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
|
|
1270
1509
|
|
|
1271
1510
|
|
|
1272
1511
|
async function waitLogs () {
|
|
@@ -1642,7 +1881,8 @@ console.log(`Querying query logs for ${parameters.service} for the last ${mins}
|
|
|
1642
1881
|
if (m.message.indexOf("GraphicFeatureServer::HandleRESTRequest ## inputJSON = ") > -1)
|
|
1643
1882
|
{
|
|
1644
1883
|
queryLogs[m.requestID].message = m.message.replace("GraphicFeatureServer::HandleRESTRequest ## inputJSON = ","")
|
|
1645
|
-
|
|
1884
|
+
queryLogs[m.requestID].message = decodeHTMLEntities(queryLogs[m.requestID].message)
|
|
1885
|
+
const queryPayload = decodeAndParseJSON(queryLogs[m.requestID].message)
|
|
1646
1886
|
queryLogs[m.requestID].gdbVersion = queryPayload.gdbVersion
|
|
1647
1887
|
queryLogs[m.requestID].moment = queryPayload.historicMoment
|
|
1648
1888
|
queryLogs[m.requestID].methodName = m.methodName;
|
|
@@ -1942,6 +2182,9 @@ function numberWithCommas(x) {
|
|
|
1942
2182
|
btnstopEditingLogs.disabled = true
|
|
1943
2183
|
|
|
1944
2184
|
|
|
2185
|
+
const btnstartEditingLogs = document.getElementById("btnstartEditingLogs");
|
|
2186
|
+
btnstartEditingLogs.addEventListener("click", e => startEditingLogs())
|
|
2187
|
+
btnstartEditingLogs.disabled = true
|
|
1945
2188
|
|
|
1946
2189
|
const btnWait = document.getElementById("btnWaitLogs");
|
|
1947
2190
|
btnWait.addEventListener("click", e => waitLogs())
|
|
@@ -2144,6 +2387,12 @@ function numberWithCommas(x) {
|
|
|
2144
2387
|
})
|
|
2145
2388
|
}
|
|
2146
2389
|
|
|
2390
|
+
|
|
2391
|
+
function decodeAndParseJSON (x) {
|
|
2392
|
+
const y = decodeHTMLEntities(x);
|
|
2393
|
+
return JSON.parse(y);
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2147
2396
|
function decodeHTMLEntities (x) {
|
|
2148
2397
|
const decodedString = document.createElement('div');
|
|
2149
2398
|
decodedString.innerHTML = x;
|
|
@@ -2218,6 +2467,14 @@ function numberWithCommas(x) {
|
|
|
2218
2467
|
|
|
2219
2468
|
allMessages = allMessages.concat(jsonRes.logMessages.filter(m => m.message.indexOf(messageFilter) > -1 && m.methodName.indexOf(methodFilter) > -1))
|
|
2220
2469
|
}
|
|
2470
|
+
//DECODE html for all messages.
|
|
2471
|
+
logger.info(`Decoding HTML entities ${allMessages.length}`);
|
|
2472
|
+
|
|
2473
|
+
allMessages = allMessages.map(m=> {
|
|
2474
|
+
m.message = decodeHTMLEntities(m.message)
|
|
2475
|
+
return m
|
|
2476
|
+
})
|
|
2477
|
+
|
|
2221
2478
|
logger.info(`Completed aggregation total messages ${allMessages.length}`);
|
|
2222
2479
|
|
|
2223
2480
|
return allMessages
|
|
@@ -2225,6 +2482,58 @@ function numberWithCommas(x) {
|
|
|
2225
2482
|
}
|
|
2226
2483
|
|
|
2227
2484
|
|
|
2485
|
+
|
|
2486
|
+
function ParseTraceReadAmplication (traceLog) {
|
|
2487
|
+
|
|
2488
|
+
try {
|
|
2489
|
+
|
|
2490
|
+
|
|
2491
|
+
const text = traceLog;
|
|
2492
|
+
const traversedMatch = text.match(/Total\s+#\s*Traversed\s+Elements:\s*([\d,]+)/i);
|
|
2493
|
+
|
|
2494
|
+
const traversedElements = traversedMatch
|
|
2495
|
+
? parseInt(traversedMatch[1].replace(/,/g, ''), 10)
|
|
2496
|
+
: 0;
|
|
2497
|
+
|
|
2498
|
+
let minPagesRead = traversedElements / 1024;
|
|
2499
|
+
if (minPagesRead <= 1024) minPagesRead =1;
|
|
2500
|
+
|
|
2501
|
+
|
|
2502
|
+
// -------------------------------------------------------------------
|
|
2503
|
+
// Sum all Cache misses values
|
|
2504
|
+
// -------------------------------------------------------------------
|
|
2505
|
+
let actualPagesRead = 0;
|
|
2506
|
+
|
|
2507
|
+
// Match rows that begin with a table name and then a cache miss number
|
|
2508
|
+
const cacheMissRegex =
|
|
2509
|
+
/^\s*[A-Za-z0-9:#()\-\s]+?\s+(\d+)\s+\d+\s+\d+\s+\d+\s+\d+/gm;
|
|
2510
|
+
|
|
2511
|
+
let match;
|
|
2512
|
+
|
|
2513
|
+
while ((match = cacheMissRegex.exec(text)) !== null) {
|
|
2514
|
+
actualPagesRead += parseInt(match[1], 10);
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
|
|
2518
|
+
let readAmp;
|
|
2519
|
+
if (actualPagesRead < minPagesRead)
|
|
2520
|
+
readAmp= "0%"
|
|
2521
|
+
else
|
|
2522
|
+
readAmp= Math.floor((actualPagesRead-minPagesRead)/actualPagesRead *100) + "%"
|
|
2523
|
+
|
|
2524
|
+
readAmp= numberWithCommas(traversedElements) + " / " + numberWithCommas(actualPagesRead)
|
|
2525
|
+
|
|
2526
|
+
console.log(`traversedElements = ${traversedElements}, minPagesRead = ${minPagesRead}, actualPagesRead = ${actualPagesRead} ,, readAmp=${readAmp}` );
|
|
2527
|
+
|
|
2528
|
+
return readAmp
|
|
2529
|
+
}
|
|
2530
|
+
catch(ex){
|
|
2531
|
+
console.error(ex)
|
|
2532
|
+
return "n/a";
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
|
|
2228
2537
|
|
|
2229
2538
|
|
|
2230
2539
|
</script>
|
package/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { AdminLog } from "./adminlog.mjs"
|
|
|
7
7
|
import logger from "./logger.mjs"
|
|
8
8
|
import fetch from "node-fetch"
|
|
9
9
|
//update version
|
|
10
|
-
let version = "0.0.
|
|
10
|
+
let version = "0.0.86";
|
|
11
11
|
const GENERATE_TOKEN_TIME_MIN = 30;
|
|
12
12
|
|
|
13
13
|
let rl = null;
|
|
@@ -166,17 +166,21 @@ const inputs = {
|
|
|
166
166
|
"subnetworks --deleted" : "Lists dirty and deleted subnetworks",
|
|
167
167
|
"evaluate" : "Evaluate in parallel",
|
|
168
168
|
"trace --subnetwork <subnetwork>": "Traces input subnetwork and returns the time and number of elements returned .",
|
|
169
|
+
"trace --all": "Traces all subnetworks.",
|
|
169
170
|
"topology" : "Displays the topology status",
|
|
170
171
|
"topology --disable" : "Disable topology",
|
|
171
172
|
"topology --enable" : "Enable topology",
|
|
172
173
|
"topology --validate" : "Validate topology (full extent)",
|
|
173
174
|
"update subnetworks --subnetwork": "Update the input subnetwork synchronously",
|
|
174
175
|
"update subnetworks --all": "Update all dirty subnetworks synchronously",
|
|
176
|
+
"update subnetworks --all --async": "Update all dirty subnetworks asynchronously",
|
|
175
177
|
"update subnetworks --deleted": "Update all deleted dirty subnetworks synchronously",
|
|
176
178
|
"update subnetworks --all --async": "Update all dirty subnetworks asynchronously",
|
|
177
179
|
"export subnetworks --all [--folder]": "Export all subnetworks with ACK --folder where exported files are saved",
|
|
178
180
|
"export subnetworks --new [--folder]": "Export all subnetworks with ACK that haven't been exported --folder where exported files are saved",
|
|
179
181
|
"export subnetworks --deleted": "Export all subnetworks with ACK that are deleted ",
|
|
182
|
+
"export subnetworks --all [--resulttype]": "Export all subnetworks with ACK --resulttype is a json configuration",
|
|
183
|
+
|
|
180
184
|
"updateisconnected": "Run update is connected ",
|
|
181
185
|
"versions": "List all versions available to the current logged in user.",
|
|
182
186
|
"versions --summary": "Summary of versions.",
|
|
@@ -792,8 +796,8 @@ const inputs = {
|
|
|
792
796
|
logger.info(`Result from submitting job ${JSON.stringify(subnetworkResult)}`)
|
|
793
797
|
}
|
|
794
798
|
},
|
|
795
|
-
"^export subnetworks --all --folder .*$|^export subnetworks --all
|
|
796
|
-
|
|
799
|
+
"^export subnetworks --all --folder .*$|^export subnetworks --all$|^export subnetworks --all --resulttype .*$" : async input => {
|
|
800
|
+
|
|
797
801
|
let subnetworks
|
|
798
802
|
let sort = "asc";
|
|
799
803
|
if (input.indexOf("--desc") > 0) sort = "desc"
|
|
@@ -802,6 +806,27 @@ const inputs = {
|
|
|
802
806
|
let inputDir = "Exported"
|
|
803
807
|
if (file != null && file.length > 0)
|
|
804
808
|
inputDir = file[0].replace("--folder ", "")
|
|
809
|
+
|
|
810
|
+
//default resulttype
|
|
811
|
+
let resultType = null;
|
|
812
|
+
|
|
813
|
+
const rt = input.match(/--resulttype .*/gm)
|
|
814
|
+
if (rt != null && v.length > 0)
|
|
815
|
+
resultType = rt[0].replace("--resulttype ", "")
|
|
816
|
+
|
|
817
|
+
logger.info(resultType)
|
|
818
|
+
|
|
819
|
+
try
|
|
820
|
+
{
|
|
821
|
+
resultType = JSON.parse(resultType)
|
|
822
|
+
}
|
|
823
|
+
catch(ex)
|
|
824
|
+
{
|
|
825
|
+
logger.error("Can't parse resulttype" + ex)
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
|
|
805
830
|
//create directory if doesn't exists
|
|
806
831
|
if (!fs.existsSync(inputDir)) fs.mkdirSync(inputDir)
|
|
807
832
|
let exportedSubnetworks = [];
|
|
@@ -823,7 +848,7 @@ const inputs = {
|
|
|
823
848
|
|
|
824
849
|
const fromDate = new Date();
|
|
825
850
|
|
|
826
|
-
const subnetworkResult = await un.exportSubnetworks(v(f.attributes,"domainNetworkName"), v(f.attributes,"tierName"), v(f.attributes,"subnetworkName"),false);
|
|
851
|
+
const subnetworkResult = await un.exportSubnetworks(v(f.attributes,"domainNetworkName"), v(f.attributes,"tierName"), v(f.attributes,"subnetworkName"),false, resultType);
|
|
827
852
|
|
|
828
853
|
//code
|
|
829
854
|
exportedSubnetworks.push("'" + v(f.attributes,"subnetworkName") + "'")
|
|
@@ -845,10 +870,10 @@ const inputs = {
|
|
|
845
870
|
//although the response is json, its easier to treat it as text (handle error cases) since we will only write it to disk.
|
|
846
871
|
// if we want to do something with the response then make it json
|
|
847
872
|
const jsonExport = await subContent.text();
|
|
848
|
-
fs.writeFileSync(`${inputDir}/${subnetworkName}.json`, jsonExport)
|
|
873
|
+
fs.writeFileSync(`${inputDir}/${v(f.attributes,"domainNetworkName")}_${v(f.attributes,"tierName")}_${subnetworkName}.json`, jsonExport)
|
|
849
874
|
|
|
850
875
|
|
|
851
|
-
logger.info(`Result ${JSON.stringify(subnetworkResult)} written to file ${process.cwd()}/${inputDir}/${subnetworkName}.json`)
|
|
876
|
+
logger.info(`Result ${JSON.stringify(subnetworkResult)} written to file ${process.cwd()}/${inputDir}/${v(f.attributes,"domainNetworkName")}_${v(f.attributes,"tierName")}_${subnetworkName}.json`)
|
|
852
877
|
|
|
853
878
|
}
|
|
854
879
|
}
|
|
@@ -856,7 +881,55 @@ const inputs = {
|
|
|
856
881
|
|
|
857
882
|
},
|
|
858
883
|
|
|
884
|
+
"^export subnetworks --all --async --folder .*$|^export subnetworks --all --async$|^export subnetworks --all --async --resulttype .*$" : async input => {
|
|
885
|
+
|
|
886
|
+
let subnetworks
|
|
887
|
+
let sort = "asc";
|
|
888
|
+
if (input.indexOf("--desc") > 0) sort = "desc"
|
|
889
|
+
//create folder
|
|
890
|
+
const file = input.match(/--folder .*/gm)
|
|
891
|
+
let inputDir = "Exported"
|
|
892
|
+
if (file != null && file.length > 0)
|
|
893
|
+
inputDir = file[0].replace("--folder ", "")
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
//default resulttype
|
|
897
|
+
let resultType = null;
|
|
898
|
+
|
|
899
|
+
const rt = input.match(/--resulttype .*/gm)
|
|
900
|
+
if (rt != null && v.length > 0)
|
|
901
|
+
resultType = rt[0].replace("--resulttype ", "")
|
|
902
|
+
|
|
903
|
+
logger.info(resultType)
|
|
904
|
+
|
|
905
|
+
//create directory if doesn't exists
|
|
906
|
+
if (!fs.existsSync(inputDir)) fs.mkdirSync(inputDir)
|
|
907
|
+
let exportedSubnetworks = [];
|
|
908
|
+
|
|
909
|
+
do {
|
|
910
|
+
|
|
911
|
+
let exportedSubnetworksWhereClause = ""
|
|
912
|
+
|
|
913
|
+
if (exportedSubnetworks.length > 0 )
|
|
914
|
+
exportedSubnetworksWhereClause = " AND SUBNETWORKNAME NOT IN (" + exportedSubnetworks.join(",") + ")"
|
|
915
|
+
|
|
916
|
+
logger.info("Querying all subnetworks that are clean.");
|
|
917
|
+
subnetworks = await un.queryDistinct(500002, "domainnetworkname,tiername,subnetworkname", "isdirty=0 " + exportedSubnetworksWhereClause,`domainnetworkname ${sort},tiername ${sort},subnetworkname ${sort}`);
|
|
918
|
+
logger.info(`Discovered ${subnetworks.features.length} subnetworks that can be exported.`);
|
|
919
|
+
for (let i = 0; i < subnetworks.features.length; i++) {
|
|
920
|
+
const f = subnetworks.features[i]
|
|
921
|
+
const subnetworkName = v(f.attributes,"subnetworkName")
|
|
922
|
+
logger.info("Exporting subnetworks " + subnetworkName);
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
const subnetworkResult = await un.exportSubnetworks(v(f.attributes,"domainNetworkName"), v(f.attributes,"tierName"), v(f.attributes,"subnetworkName"),true);
|
|
926
|
+
logger.info(`Result from submitting job ${JSON.stringify(subnetworkResult)}`)
|
|
859
927
|
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
while (subnetworks?.features?.length > 0)
|
|
931
|
+
|
|
932
|
+
},
|
|
860
933
|
"^export subnetworks --new --folder .*$|^export subnetworks --new$" : async input => {
|
|
861
934
|
|
|
862
935
|
//create folder
|
|
@@ -879,9 +952,11 @@ const inputs = {
|
|
|
879
952
|
//fetch the json and write it to disk
|
|
880
953
|
const subContent = await fetch(subnetworkResult.url);
|
|
881
954
|
const jsonExport = await subContent.text();
|
|
882
|
-
fs.writeFileSync(`${inputDir}/${subnetworkName}.json`,
|
|
883
|
-
|
|
884
|
-
|
|
955
|
+
fs.writeFileSync(`${inputDir}/${v(f.attributes,"domainNetworkName")}_${v(f.attributes,"tierName")}_${subnetworkName}.json`, jsonExport)
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
logger.info(`Result ${JSON.stringify(subnetworkResult)} written to file ${process.cwd()}/${inputDir}/${v(f.attributes,"domainNetworkName")}_${v(f.attributes,"tierName")}_${subnetworkName}.json`)
|
|
959
|
+
|
|
885
960
|
}
|
|
886
961
|
|
|
887
962
|
|
|
@@ -968,19 +1043,68 @@ const inputs = {
|
|
|
968
1043
|
logger.error(JSON.stringify(ex))
|
|
969
1044
|
}
|
|
970
1045
|
},
|
|
971
|
-
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
"^trace --all": async input => {
|
|
1050
|
+
//get subnetwork name
|
|
1051
|
+
try {
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
const inputDir= "Exported"
|
|
1055
|
+
let full = true;
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
const subnetworks = await un.getSubnetworks();
|
|
1059
|
+
if (subnetworks.features.length === 0) {
|
|
1060
|
+
logger.info("No dirty subnetworks found.")
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
const subs = subnetworks.features.map(a => a.attributes)
|
|
1065
|
+
const rowCount = subs.length;
|
|
1066
|
+
logger.info (`${numberWithCommas(rowCount)} subnetworks returned.`)
|
|
1067
|
+
for (let i = 0; i < subs.length ; i++)
|
|
1068
|
+
{
|
|
1069
|
+
const fromDate = new Date();
|
|
1070
|
+
const subnetworkName = v(subs[i],"subnetworkname")
|
|
1071
|
+
logger.info(`Tracing subnetwork ${subnetworkName}`);
|
|
1072
|
+
const result = await un.subnetworkTraceSimple(subnetworkName)
|
|
1073
|
+
if (result == null) {
|
|
1074
|
+
logger.info(`Subnetwork ${subnetworkName} doesn't exist`);
|
|
1075
|
+
return null;
|
|
1076
|
+
}
|
|
1077
|
+
const toDate = new Date();
|
|
1078
|
+
const timeRun = toDate.getTime() - fromDate.getTime();
|
|
1079
|
+
const newResult = {}
|
|
1080
|
+
newResult.duration = numberWithCommas(Math.round(timeRun)) + " ms"
|
|
1081
|
+
newResult.elementsCount = result.traceResults.elements.length;
|
|
1082
|
+
console.table(newResult)
|
|
1083
|
+
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
}
|
|
1089
|
+
catch(ex){
|
|
1090
|
+
logger.error(JSON.stringify(ex))
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
"^export subnetworks --deleted --folder" : async input => {
|
|
972
1096
|
|
|
973
1097
|
//create folder
|
|
974
|
-
const file = input.match(
|
|
1098
|
+
const file = input.match(/--folder .*/gm)
|
|
975
1099
|
let inputDir = "Exported"
|
|
976
1100
|
if (file != null && file.length > 0)
|
|
977
|
-
inputDir = file[0].replace("
|
|
1101
|
+
inputDir = file[0].replace("--folder ", "")
|
|
978
1102
|
//create directory if doesn't exists
|
|
979
1103
|
if (!fs.existsSync(inputDir)) fs.mkdirSync(inputDir)
|
|
980
1104
|
|
|
981
1105
|
|
|
982
1106
|
logger.info("Querying all subnetworks that are clean and deleted.");
|
|
983
|
-
let subnetworks = await un.queryDistinct(500002, "domainnetworkname,tiername,subnetworkname", "
|
|
1107
|
+
let subnetworks = await un.queryDistinct(500002, "domainnetworkname,tiername,subnetworkname", "isdeleted=1", "subnetworkname");
|
|
984
1108
|
logger.info(`Discovered ${subnetworks.features.length} subnetworks that can be exported.`);
|
|
985
1109
|
for (let i = 0; i < subnetworks.features.length; i++) {
|
|
986
1110
|
const f = subnetworks.features[i]
|
|
@@ -998,9 +1122,11 @@ const inputs = {
|
|
|
998
1122
|
//fetch the json and write it to disk
|
|
999
1123
|
const subContent = await fetch(subnetworkResult.url);
|
|
1000
1124
|
const jsonExport = await subContent.text();
|
|
1001
|
-
fs.writeFileSync(`${inputDir}/${subnetworkName}.json`,
|
|
1002
|
-
|
|
1003
|
-
|
|
1125
|
+
fs.writeFileSync(`${inputDir}/${v(f.attributes,"domainNetworkName")}_${v(f.attributes,"tierName")}_${subnetworkName}.json`, jsonExport)
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
logger.info(`Result ${JSON.stringify(subnetworkResult)} written to file ${process.cwd()}/${inputDir}/${v(f.attributes,"domainNetworkName")}_${v(f.attributes,"tierName")}_${subnetworkName}.json`)
|
|
1129
|
+
|
|
1004
1130
|
}
|
|
1005
1131
|
|
|
1006
1132
|
|
package/package.json
CHANGED
package/utilitynetwork.node.mjs
CHANGED
|
@@ -280,6 +280,7 @@ export class UtilityNetwork {
|
|
|
280
280
|
orderByFields: "DOMAINNETWORKNAME, TIERNAME, SUBNETWORKNAME",
|
|
281
281
|
gdbVersion:this.gdbVersion,
|
|
282
282
|
returnDistinctValues: true,
|
|
283
|
+
resultRecordCount: 20000,
|
|
283
284
|
f: "json"
|
|
284
285
|
}
|
|
285
286
|
|
|
@@ -1180,7 +1181,7 @@ export class UtilityNetwork {
|
|
|
1180
1181
|
}
|
|
1181
1182
|
|
|
1182
1183
|
|
|
1183
|
-
exportSubnetworks(domainNetworkName, tierName, subnetworkName, async=false) {
|
|
1184
|
+
exportSubnetworks(domainNetworkName, tierName, subnetworkName, async=false,resultTypes=null) {
|
|
1184
1185
|
|
|
1185
1186
|
let thisObj = this;
|
|
1186
1187
|
let tier = this.getTier(domainNetworkName, tierName);
|
|
@@ -1190,37 +1191,9 @@ export class UtilityNetwork {
|
|
|
1190
1191
|
let ar = thisObj.featureServiceUrl.split("/");
|
|
1191
1192
|
ar[ar.length-1]="UtilityNetworkServer";
|
|
1192
1193
|
let exportsubnetworkUrl = ar.join("/") + "/exportSubnetwork"
|
|
1193
|
-
|
|
1194
|
-
{
|
|
1195
|
-
|
|
1196
|
-
"includeGeometry": true,
|
|
1197
|
-
"includePropagatedValues": false,
|
|
1198
|
-
"includeDomainDescriptions": true,
|
|
1199
|
-
"networkAttributeNames": [
|
|
1200
|
-
"Is subnetwork controller"
|
|
1201
|
-
],
|
|
1202
|
-
"diagramTemplateName": "",
|
|
1203
|
-
"resultTypeFields": []
|
|
1204
|
-
},
|
|
1205
|
-
{
|
|
1206
|
-
"type": "connectivity",
|
|
1207
|
-
"includeGeometry": true,
|
|
1208
|
-
"includePropagatedValues": false,
|
|
1209
|
-
"includeDomainDescriptions": true,
|
|
1210
|
-
"networkAttributeNames": [],
|
|
1211
|
-
"diagramTemplateName": "",
|
|
1212
|
-
"resultTypeFields": []
|
|
1213
|
-
},
|
|
1214
|
-
{
|
|
1215
|
-
"type": "associations",
|
|
1216
|
-
"includeGeometry": false,
|
|
1217
|
-
"includePropagatedValues": false,
|
|
1218
|
-
"includeDomainDescriptions": true,
|
|
1219
|
-
"networkAttributeNames": [],
|
|
1220
|
-
"diagramTemplateName": "",
|
|
1221
|
-
"resultTypeFields": []
|
|
1222
|
-
}
|
|
1223
|
-
]
|
|
1194
|
+
if (!resultTypes)
|
|
1195
|
+
resultTypes = [{"type":"features","includeGeometry":true,"includePropagatedValues":false,"includeDomainDescriptions":true,"networkAttributeNames":["Is subnetwork controller"],"diagramTemplateName":"","resultTypeFields":[]},{"type":"connectivity","includeGeometry":true,"includePropagatedValues":false,"includeDomainDescriptions":true,"networkAttributeNames":[],"diagramTemplateName":"","resultTypeFields":[]},{"type":"associations","includeGeometry":false,"includePropagatedValues":false,"includeDomainDescriptions":true,"networkAttributeNames":[],"diagramTemplateName":"","resultTypeFields":[]}]
|
|
1196
|
+
|
|
1224
1197
|
//traceConfiguration: JSON.stringify(subnetworkDef),
|
|
1225
1198
|
let exportsubnetworkJson = {
|
|
1226
1199
|
f: "json",
|
|
@@ -1231,7 +1204,7 @@ export class UtilityNetwork {
|
|
|
1231
1204
|
exportAcknowledgement: true,
|
|
1232
1205
|
allSubnetworksInTier: false,
|
|
1233
1206
|
continueOnFailure: false,
|
|
1234
|
-
traceConfiguration: subnetworkDef,
|
|
1207
|
+
traceConfiguration: JSON.stringify(subnetworkDef),
|
|
1235
1208
|
async: async,
|
|
1236
1209
|
gdbVersion:this.gdbVersion,
|
|
1237
1210
|
resultTypes: JSON.stringify(resultTypes)
|