Updates to test env and A1function test
[nonrtric.git] / test / simulator-group / sim-monitor.js
1 /*
2 #  ============LICENSE_START===============================================
3 #  Copyright (C) 2020 Nordix Foundation. All rights reserved.
4 #  ========================================================================
5 #  Licensed under the Apache License, Version 2.0 (the "License");
6 #  you may not use this file except in compliance with the License.
7 #  You may obtain a copy of the License at
8 #
9 #       http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #  Unless required by applicable law or agreed to in writing, software
12 #  distributed under the License is distributed on an "AS IS" BASIS,
13 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 #  See the License for the specific language governing permissions and
15 #  limitations under the License.
16 #  ============LICENSE_END=================================================
17 #
18 */
19
20 // Sim mon server - query the agent and the simulators for counters and other data
21 // Presents a web page on localhost:9999/mon
22
23 var LOCALHOST="http://127.0.0.1:"
24 var MRSTUB_PORT="3905"
25 var AGENT_PORT="8081"
26 var CR_PORT="8090"
27 var ECS_PORT="8083"
28 var PRODSTUB_PORT="8092"
29
30 var http = require('http');
31
32 var express = require('express');
33 var app = express();
34 var fieldSize=32;
35
36 var flagstore={}
37
38 //I am alive
39 app.get("/",function(req, res){
40         res.send("ok");
41 })
42
43 //Get parameter value from other server
44 function getSimCtr(url, index, cb) {
45     var data = '';
46
47     try {
48         http.get(url, (resp) => {
49             // A chunk of data has been recieved.
50             resp.on('data', (chunk) => {
51                 data += chunk;
52             });
53
54             // The whole response has been received.
55             resp.on('end', () => {
56                 var code=resp.statusCode
57                 if (code > 199 && code < 300) {
58                     cb(data, index);
59                 } else {
60                     cb("not found", index);
61                 }
62             });
63
64         }).on("error", (err) => {
65             console.log("Error: " + err.message);
66             cb("no response", index);
67         });
68     } catch(err) {
69         cb("no response", index);
70     }
71 };
72
73
74 //Format a comma separated list of data to a html-safe string with fixed fieldsizes
75 function formatDataRow(commaList) {
76         var str = "";
77         var tmp=commaList.split(',');
78     for(var i=0;i<tmp.length;i++) {
79         var data=tmp[i];
80         var len = fieldSize-data.length;
81         while(len>0) {
82             data = data+"&nbsp;";
83             len--;
84         }
85         str=str+data+"&nbsp;&nbsp;&nbsp;";
86      }
87         return str;
88 }
89
90 //Format a comma separated list of ids to a html-safe string with fixed fieldsizes
91 function formatIdRow(commaList) {
92         var str = "";
93         var tmp=commaList.split(',');
94     for(var i=0;i<tmp.length;i++) {
95         tmp[i] = tmp[i].trim();
96         var data="&lt"+tmp[i]+"&gt";
97         var len = fieldSize+4-data.length;
98         while(len>0) {
99             data = data+"&nbsp;";
100             len--;
101         }
102         str=str+data+"&nbsp;&nbsp;&nbsp;";
103     }
104         return str;
105 }
106
107 //Format a list of ids to a html-safe string in compact format
108 function formatIdRowCompact(commaList) {
109     if (commaList == undefined) {
110         commaList= "";
111     }
112         var str = "";
113         var tmp=commaList.split(',');
114     for(var i=0;i<tmp.length;i++) {
115         tmp[i] = tmp[i].trim();
116         var data="&lt"+tmp[i]+"&gt";
117         str=str+data+"&nbsp;";
118     }
119         return str;
120 }
121
122 //Pad a string upto a certain size using a pad string
123 function padding(val, fieldSize, pad) {
124         var s=""+val;
125         for(var i=s.length;i<fieldSize;i++) {
126                 s=s+pad
127         }
128         return s;
129 }
130
131 //Function to check if the previous call has returned, if so return true, if not return false
132 //For preventing multiple calls to slow containers.
133 function checkFunctionFlag(flag) {
134     if (flagstore.hasOwnProperty(flag)) {
135         if (flagstore[flag] == 0) {
136             flagstore[flag]=1
137             return true
138         } else if (flagstore[flag] > 10) {
139             //Reset flag after ten attempts
140             console.log("Force release flag "+flag)
141             flagstore[flag]=1
142             return true
143         } else {
144             //Previous call not returned
145             console.log("Flag not available "+flag)
146             flagstore[flag]=flagstore[flag]+1
147             return false
148         }
149     } else {
150         flagstore[flag]=1
151         return true
152     }
153 }
154 //Clear flag for parameter
155 function clearFlag(flag) {
156     flagstore[flag]=0
157 }
158
159 //Status variables, for parameters values fetched from other simulators
160 var mr1="", mr2="", mr3="", mr4="", mr5="", mr6="";
161
162 //Status variables for agent
163 var ag1=""
164 var ag2=""
165 var ag3=""
166 var ag4=""
167 var ag5=""
168
169 //Status variables for callback receiver
170 var cr1=""
171 var cr2=""
172 var cr3=""
173
174
175 //Container names and ports of the ric simulator
176 var simnames=[]
177 var simports=[]
178
179 //Status variables for each ric simulator
180 var simvar1=[]
181 var simvar2=[]
182 var simvar3=[]
183 var simvar4=[]
184 var simvar5=[]
185 var simvar6=[]
186
187 //Status variables, for parameters values fetched from ecs
188 var ecs1="", ecs2="", ecs3="", ecs4="", ecs_types="-", ecs_producers="-";
189 var ecs_producer_arr=new Array(0)
190 var ecs_producer_type_arr=new Array(0)
191 var ecs_producer_jobs_arr=new Array(0)
192 var ecs_producer_status_arr=new Array(0)
193
194 //Status variables, for parameters values fetched from prodstub
195 var ps2="", ps3="", ps4="", ps_types="-", ps_producers="-";
196 var ps_producer_type_arr=new Array(0)
197 var ps_producer_jobs_arr=new Array(0)
198 var ps_producer_delivery_arr=new Array(0)
199
200 //Counts the number of get request for the html page
201 var getCtr=0
202
203 var refreshCount_pol=-1
204
205 var refreshCount_ecs=-1
206
207 var ricbasename="ricsim"
208
209 function fetchAllMetrics_pol() {
210
211     console.log("Fetching policy metrics " + refreshCount_pol)
212
213     if (refreshCount_pol < 0) {
214         refreshCount_pol = -1
215         return
216     } else {
217         refreshCount_pol = refreshCount_pol - 1
218     }
219     setTimeout(() => {
220
221         if (getCtr%3 == 0) {
222             //Extract the port numbers from the running simulators, for every 3 calls
223             const { exec } = require('child_process');
224             exec('docker ps --filter "name='+ricbasename+'" --format "{{.Names}} {{.Ports}}" | sed s/0.0.0.0:// | cut -d \'>\' -f1 | sed \'s/[[-]]*$//\'', (err, stdout, stderr) => {
225
226                 var simulators = ""
227                 simulators=`${stdout}`.replace(/(\r\n|\n|\r)/gm," ");
228                 simulators=simulators.trim();
229                 var sims=simulators.split(" ")
230                 simnames=[]
231                 simports=[]
232                 for(i=0;i<sims.length;i=i+2) {
233                     simnames[i/2]=sims[i]
234                     simports[i/2]=sims[i+1]
235                 }
236             });
237         }
238         getCtr=getCtr+1
239
240         //Get metric values from the simulators
241         for(var index=0;index<simnames.length;index++) {
242
243             if (checkFunctionFlag("simvar1_"+index)) {
244                 getSimCtr(LOCALHOST+simports[index]+"/counter/num_instances", index, function(data, index) {
245                     simvar1[index] = data;
246                     clearFlag("simvar1_"+index)
247                 });
248             }
249             if (checkFunctionFlag("simvar2_"+index)) {
250                 getSimCtr(LOCALHOST+simports[index]+"/counter/num_types", index, function(data,index) {
251                     simvar2[index] = data;
252                     clearFlag("simvar2_"+index)
253                 });
254             }
255             if (checkFunctionFlag("simvar3_"+index)) {
256                 getSimCtr(LOCALHOST+simports[index]+"/policytypes", index, function(data,index) {
257                     data=data.replace(/\[/g,'');
258                     data=data.replace(/\]/g,'');
259                     data=data.replace(/ /g,'');
260                     data=data.replace(/\"/g,'');
261                     simvar3[index] = data;
262                     clearFlag("simvar3_"+index)
263                 });
264             }
265             if (checkFunctionFlag("simvar4_"+index)) {
266                 getSimCtr(LOCALHOST+simports[index]+"/counter/interface", index, function(data,index) {
267                     simvar4[index] = data;
268                     clearFlag("simvar4_"+index)
269                 });
270             }
271             if (checkFunctionFlag("simvar5_"+index)) {
272                 getSimCtr(LOCALHOST+simports[index]+"/counter/remote_hosts", index, function(data,index) {
273                     simvar5[index] = data;
274                     clearFlag("simvar5_"+index)
275                 });
276             }
277             if (checkFunctionFlag("simvar6_"+index)) {
278                 getSimCtr(LOCALHOST+simports[index]+"/counter/datadelivery", index, function(data,index) {
279                     simvar6[index] = data;
280                     clearFlag("simvar6_"+index)
281                 });
282             }
283         }
284
285         //MR - get metrics values from the MR stub
286         if (checkFunctionFlag("mr1")) {
287             getSimCtr(LOCALHOST+MRSTUB_PORT+"/counter/requests_submitted", 0, function(data, index) {
288                 mr1 = data;
289                 clearFlag("mr1")
290             });
291         }
292         if (checkFunctionFlag("mr2")) {
293             getSimCtr(LOCALHOST+MRSTUB_PORT+"/counter/requests_fetched", 0, function(data, index) {
294                 mr2 = data;
295                 clearFlag("mr2")
296             });
297         }
298         if (checkFunctionFlag("mr3")) {
299             getSimCtr(LOCALHOST+MRSTUB_PORT+"/counter/current_requests", 0, function(data, index) {
300                 mr3 = data;
301                 clearFlag("mr3")
302             });
303         }
304         if (checkFunctionFlag("mr4")) {
305             getSimCtr(LOCALHOST+MRSTUB_PORT+"/counter/responses_submitted", 0, function(data, index) {
306                 mr4 = data;
307                 clearFlag("mr4")
308             });
309         }
310         if (checkFunctionFlag("mr5")) {
311             getSimCtr(LOCALHOST+MRSTUB_PORT+"/counter/responses_fetched", 0, function(data, index) {
312                 mr5 = data;
313                 clearFlag("mr5")
314             });
315         }
316         if (checkFunctionFlag("mr6")) {
317             getSimCtr(LOCALHOST+MRSTUB_PORT+"/counter/current_responses", 0, function(data, index) {
318                 mr6 = data;
319                 clearFlag("mr6")
320             });
321         }
322
323         //CR - get metrics values from the callbackreceiver
324         if (checkFunctionFlag("cr1")) {
325             getSimCtr(LOCALHOST+CR_PORT+"/counter/received_callbacks", 0, function(data, index) {
326                 cr1 = data;
327                 clearFlag("cr1")
328             });
329         }
330         if (checkFunctionFlag("cr2")) {
331             getSimCtr(LOCALHOST+CR_PORT+"/counter/fetched_callbacks", 0, function(data, index) {
332                 cr2 = data;
333                 clearFlag("cr2")
334             });
335         }
336         if (checkFunctionFlag("cr3")) {
337             getSimCtr(LOCALHOST+CR_PORT+"/counter/current_messages", 0, function(data, index) {
338                 cr3 = data;
339                 clearFlag("cr3")
340             });
341         }
342         //Agent - more get metrics from the agent
343         if (checkFunctionFlag("ag1")) {
344             getSimCtr(LOCALHOST+AGENT_PORT+"/status", 0, function(data, index) {
345                 ag1 = data;
346                 clearFlag("ag1")
347             });
348         }
349         if (checkFunctionFlag("ag2")) {
350             getSimCtr(LOCALHOST+AGENT_PORT+"/services", 0, function(data, index) {
351                 ag2="";
352                 try {
353                     var jd=JSON.parse(data);
354                     for(var key in jd) {
355                         if (ag2.length > 1) {
356                             ag2=ag2+", "
357                         }
358                         ag2=ag2+(jd[key]["serviceName"]).trim()
359                     }
360                 }
361                 catch (err) {
362                     ag2=data
363                 }
364                 clearFlag("ag2")
365             });
366         }
367         if (checkFunctionFlag("ag3")) {
368             getSimCtr(LOCALHOST+AGENT_PORT+"/policy_types", 0, function(data, index) {
369                 ag3="";
370                 try {
371                     var jd=JSON.parse(data);
372                     for(var key in jd) {
373                         if (ag3.length > 0) {
374                             ag3=ag3+", "
375                         }
376                         ag3=ag3+jd[key].trim()
377                     }
378                 }
379                 catch (err) {
380                     ag3=""
381                 }
382                 clearFlag("ag3")
383             });
384         }
385
386         if (checkFunctionFlag("ag4")) {
387             getSimCtr(LOCALHOST+AGENT_PORT+"/policy_ids", 0, function(data, index) {
388                 try {
389                     var jd=JSON.parse(data);
390                     ag4=""+jd.length
391                 }
392                 catch (err) {
393                     ag4=""
394                 }
395                 clearFlag("ag4")
396             });
397         }
398
399         if (checkFunctionFlag("ag5")) {
400             getSimCtr(LOCALHOST+AGENT_PORT+"/rics", 0, function(data, index) {
401                 try {
402                     var jd=JSON.parse(data);
403                     ag5=""+jd.length
404                 }
405                 catch (err) {
406                     ag5=""
407                 }
408                 clearFlag("ag5")
409             });
410         }
411
412         fetchAllMetrics_pol();
413
414     }, 500)
415 }
416
417 function fetchAllMetrics_ecs() {
418
419     console.log("Fetching enrichment metrics - timer:" + refreshCount_ecs)
420
421     if (refreshCount_ecs < 0) {
422         refreshCount_ecs = -1
423         return
424     } else {
425         refreshCount_ecs = refreshCount_ecs - 1
426     }
427     setTimeout(() => {
428
429         if (checkFunctionFlag("ecs_stat")) {
430             getSimCtr(LOCALHOST+ECS_PORT+"/status", 0, function(data, index) {
431                 ecs1=""
432                 ecs2=""
433                 ecs3=""
434                 ecs4=""
435                 try {
436                     var jd=JSON.parse(data);
437                     ecs1=jd["status"]
438                     ecs2=""+jd["no_of_producers"]
439                     ecs3=""+jd["no_of_types"]
440                     ecs4=""+jd["no_of_jobs"]
441                 }
442                 catch (err) {
443                     ecs1="error response"
444                     ecs2="error response"
445                     ecs3="error response"
446                     ecs4="error response"
447                 }
448             });
449
450             getSimCtr(LOCALHOST+ECS_PORT+"/ei-producer/v1/eitypes", 0, function(data, index) {
451                 ecs_types="-"
452                 try {
453                     var jd=JSON.parse(data);
454                     for(var i=0;i<jd.length;i++) {
455                         if (ecs_types.length == 1) {
456                             ecs_types=""
457                         }
458                         ecs_types=""+ecs_types+jd[i]+" "
459                     }
460                 }
461                 catch (err) {
462                     ecs_types="error response"
463                 }
464             });
465
466             getSimCtr(LOCALHOST+ECS_PORT+"/ei-producer/v1/eiproducers", 0, function(data, index) {
467                 ecs_producers="-"
468                 try {
469                     var jd=JSON.parse(data);
470                     var tmp_ecs_producer_arr=new Array(jd.length)
471                     for(var i=0;i<jd.length;i++) {
472                         if (ecs_producers.length == 1) {
473                             ecs_producers=""
474                         }
475                         ecs_producers=""+ecs_producers+jd[i]+" "
476                         tmp_ecs_producer_arr[i]=jd[i]
477                     }
478                     ecs_producer_arr = tmp_ecs_producer_arr
479                 }
480                 catch (err) {
481                     ecs_producers="error response"
482                     ecs_producer_arr=new Array(0)
483                 }
484             });
485
486             ecs_producer_type_arr = JSON.parse(JSON.stringify(ecs_producer_arr))
487             for(var x=0;x<ecs_producer_type_arr.length;x++) {
488                 getSimCtr(LOCALHOST+ECS_PORT+"/ei-producer/v1/eiproducers/"+ecs_producer_type_arr[x], x, function(data, x) {
489                     var row=""+ecs_producer_type_arr[x]+" : "
490                     try {
491                         var jd=JSON.parse(data);
492                         var jda=jd["supported_ei_types"]
493                         for(var j=0;j<jda.length;j++) {
494                             row=""+row+jda[j]["ei_type_identity"]+" "
495                         }
496                         ecs_producer_type_arr[x]=row
497                     }
498                     catch (err) {
499                         ecs_producer_type_arr=new Array(0)
500                     }
501                 });
502             }
503
504             ecs_producer_jobs_arr = JSON.parse(JSON.stringify(ecs_producer_arr))
505             for(var x=0;x<ecs_producer_jobs_arr.length;x++) {
506                 getSimCtr(LOCALHOST+ECS_PORT+"/ei-producer/v1/eiproducers/"+ecs_producer_jobs_arr[x]+"/eijobs", x, function(data, x) {
507                     var row=""+ecs_producer_jobs_arr[x]+" : "
508                     try {
509                         var jd=JSON.parse(data);
510                         for(var j=0;j<jd.length;j++) {
511                             var jda=jd[j]
512                             row=""+row+jda["ei_job_identity"]+"("+jda["ei_type_identity"]+") "
513                         }
514                         ecs_producer_jobs_arr[x]=row
515                     }
516                     catch (err) {
517                         ecs_producer_jobs_arr=new Array(0)
518                     }
519                 });
520             }
521
522             ecs_producer_status_arr = JSON.parse(JSON.stringify(ecs_producer_arr))
523             for(var x=0;x<ecs_producer_status_arr.length;x++) {
524                 getSimCtr(LOCALHOST+ECS_PORT+"/ei-producer/v1/eiproducers/"+ecs_producer_status_arr[x]+"/status", x, function(data, x) {
525                     var row=""+ecs_producer_status_arr[x]+" : "
526                     try {
527                         var jd=JSON.parse(data);
528                         row=""+row+jd["operational_state"]
529                         ecs_producer_status_arr[x]=row
530                     }
531                     catch (err) {
532                         ecs_producer_status_arr=new Array(0)
533                     }
534                 });
535             }
536             clearFlag("ecs_stat")
537         }
538         if (checkFunctionFlag("prodstub_stat")) {
539             getSimCtr(LOCALHOST+PRODSTUB_PORT+"/status", x, function(data, x) {
540                 var ctr2_map=new Map()
541                 var ctr3_map=new Map()
542                 var ctr2=0
543                 var ctr4=0
544                 ps_producers=""
545                 ps_types=""
546                 ps_producer_type_arr=new Array()
547                 ps_producer_jobs_arr=new Array()
548                 ps_producer_delivery_arr=new Array()
549                 ps2=""
550                 ps3=""
551                 ps4=""
552                 try {
553                     var jp=JSON.parse(data);
554                     for(var prod_name in jp) {
555                         ctr2_map.set(prod_name, prod_name)
556                         ctr2 += 1
557                         var jj=jp[prod_name]
558                         var row=""+prod_name+" : "
559                         var rowj=""+prod_name+" : "
560                         var rowd=""+prod_name+" : "
561                         ps_producers += prod_name + " "
562                         for(var ji in jj) {
563                             if (ji == "types") {
564                                 var ta=jj[ji]
565                                 for(var i=0;i<ta.length;i++) {
566                                     ctr3_map.set(ta[i], ta[i])
567                                     row += " "+ta[i]
568                                 }
569                             } else if (ji == "supervision_response") {
570                             } else if (ji == "supervision_counter") {
571                             } else if (ji == "types") {
572                             } else {
573                                 ctr4 += 1
574                                 rowj += " "+ji
575                                 rowd += " "+ji
576                                 var job_data=jj[ji]["json"]
577                                 if (job_data != undefined) {
578                                     rowj += "("+job_data["ei_type_identity"]+")"
579                                 }
580                                 rowd += "("+jj[ji]["delivery_attempts"]+")"
581                             }
582                         }
583                         ps_producer_type_arr[(ctr2-1)]=row
584                         ps_producer_jobs_arr[(ctr2-1)]=rowj
585                         ps_producer_delivery_arr[(ctr2-1)]=rowd
586                     }
587                     ps2=""+ctr2_map.size
588                     ps3=""+ctr3_map.size
589                     for(const [key, value] of ctr3_map.entries()) {
590                         ps_types += key + " "
591                     }
592                     ps4=""+ctr4
593                 }
594                 catch (err) {
595                     console.error(err);
596                     ps_producers="error response"
597                     ps_types="error response"
598                     ps_producer_type_arr=new Array()
599                     ps_producer_jobs_arr=new Array()
600                     ps_producer_delivery_arr=new Array()
601                     ps2="error response"
602                     ps3="error response"
603                     ps4="error response"
604                 }
605             });
606             clearFlag("prodstub_stat")
607         }
608
609         fetchAllMetrics_ecs();
610
611     }, 500)
612 }
613
614 // Monitor for ECS
615 app.get("/mon2",function(req, res){
616
617     console.log("Creating enrichment metrics - timer: " + refreshCount_ecs)
618
619     if (refreshCount_ecs < 0) {
620         refreshCount_ecs=5
621         fetchAllMetrics_ecs()
622     }
623     refreshCount_ecs=5
624
625     var summary=req.query.summary
626
627     if (summary == undefined) {
628         return res.redirect('/mon2?summary=false');
629     }
630
631   //Build web page
632         var htmlStr = "<!DOCTYPE html>" +
633           "<html>" +
634           "<head>" +
635             "<meta http-equiv=\"refresh\" content=\"2\">"+  //2 sec auto refresh
636             "<title>Enrichment coordinator service and producer stub</title>"+
637             "</head>" +
638             "<body>" +
639             "<font size=\"-3\" face=\"summary\">"
640             if (summary == "false") {
641                 htmlStr=htmlStr+"<p>Set query param '?summary' to true to only show summary statistics</p>"
642             } else {
643                 htmlStr=htmlStr+"<p>Set query param '?summary' to false to only show full statistics</p>"
644             }
645             htmlStr=htmlStr+"</font>" +
646             "<h3>Enrichment Coordinator Service</h3>" +
647             "<font face=\"monospace\">" +
648             "Status:..........." + formatDataRow(ecs1) + "<br>" +
649             "Producers:........" + formatDataRow(ecs2) + "<br>" +
650             "Types:............" + formatDataRow(ecs3) + "<br>" +
651             "Jobs:............." + formatDataRow(ecs4) + "<br>" +
652             "</font>"
653             if (summary == "false") {
654                 htmlStr=htmlStr+
655                 "<h4>Details</h4>" +
656                 "<font face=\"monospace\">" +
657                 "Producer ids:....." + formatDataRow(ecs_producers) + "<br>" +
658                 "Type ids:........." + formatDataRow(ecs_types) + "<br>" +
659                 "<br>";
660                 for(var i=0;i<ecs_producer_type_arr.length;i++) {
661                     var tmp=ecs_producer_type_arr[i]
662                     if (tmp != undefined) {
663                         var s = "Producer types...." + formatDataRow(ecs_producer_type_arr[i]) + "<br>"
664                         htmlStr=htmlStr+s
665                     }
666                 }
667                 htmlStr=htmlStr+"<br>";
668                 for(var i=0;i<ecs_producer_jobs_arr.length;i++) {
669                     var tmp=ecs_producer_jobs_arr[i]
670                     if (tmp != undefined) {
671                         var s = "Producer jobs....." + formatDataRow(ecs_producer_jobs_arr[i]) + "<br>"
672                         htmlStr=htmlStr+s
673                     }
674                 }
675                 htmlStr=htmlStr+"<br>";
676                 for(var i=0;i<ecs_producer_status_arr.length;i++) {
677                     var tmp=ecs_producer_status_arr[i]
678                     if (tmp != undefined) {
679                         var s = "Producer status..." + formatDataRow(ecs_producer_status_arr[i]) + "<br>"
680                         htmlStr=htmlStr+s
681                     }
682                 }
683                 htmlStr=htmlStr+"<br>"+"<br>" +
684                 "</font>"
685             }
686             htmlStr=htmlStr+
687             "<h3>Producer stub</h3>" +
688             "<font face=\"monospace\">" +
689             "Producers:........" + formatDataRow(ps2) + "<br>" +
690             "Types:............" + formatDataRow(ps3) + "<br>" +
691             "Jobs:............." + formatDataRow(ps4) + "<br>" +
692             "</font>"
693             if (summary == "false") {
694                 htmlStr=htmlStr+
695                 "<h4>Details</h4>" +
696                 "<font face=\"monospace\">" +
697                 "Producer ids:....." + formatDataRow(ps_producers) + "<br>" +
698                 "Type ids:........." + formatDataRow(ps_types) + "<br>" +
699                 "<br>";
700                 for(var i=0;i<ps_producer_type_arr.length;i++) {
701                     var tmp=ps_producer_type_arr[i]
702                     if (tmp != undefined) {
703                         var s = "Producer types...." + formatDataRow(ps_producer_type_arr[i]) + "<br>"
704                         htmlStr=htmlStr+s
705                     }
706                 }
707                 htmlStr=htmlStr+"<br>";
708                 for(var i=0;i<ps_producer_jobs_arr.length;i++) {
709                     var tmp=ps_producer_jobs_arr[i]
710                     if (tmp != undefined) {
711                         var s = "Producer jobs....." + formatDataRow(ps_producer_jobs_arr[i]) + "<br>"
712                         htmlStr=htmlStr+s
713                     }
714                 }
715                 htmlStr=htmlStr+"<br>";
716                 for(var i=0;i<ps_producer_delivery_arr.length;i++) {
717                     var tmp=ps_producer_delivery_arr[i]
718                     if (tmp != undefined) {
719                         var s = "Producer delivery." + formatDataRow(ps_producer_delivery_arr[i]) + "<br>"
720                         htmlStr=htmlStr+s
721                     }
722                 }
723             }
724             htmlStr=htmlStr+
725             "</font>" +
726            "</body>" +
727           "</html>";
728         res.send(htmlStr);
729 })
730
731 // Monitor for policy management
732 app.get("/mon",function(req, res){
733
734     console.log("Creating policy metrics page " + refreshCount_pol)
735
736     if (refreshCount_pol < 0) {
737         refreshCount_pol=5
738         fetchAllMetrics_pol()
739     }
740     refreshCount_pol=5
741
742     var bn=req.query.basename
743
744     if (bn == undefined) {
745         getCtr=0
746         return res.redirect('/mon?basename=ricsim');
747     } else {
748         ricbasename=bn
749     }
750
751     //Build web page
752         var htmlStr = "<!DOCTYPE html>" +
753           "<html>" +
754           "<head>" +
755             "<meta http-equiv=\"refresh\" content=\"2\">"+  //2 sec auto refresh
756             "<title>Policy Agent and simulator monitor</title>"+
757             "</head>" +
758             "<body>" +
759             "<font size=\"-3\" face=\"monospace\">" +
760             "<p>Change basename in url if other ric sim prefix is used</p>" +
761             "</font>" +
762             "<h3>Policy agent</h3>" +
763             "<font face=\"monospace\">" +
764             "Status:..............................." + formatDataRow(ag1) + "<br>" +
765             "Services:............................." + formatIdRowCompact(ag2) + "<br>" +
766             "Types:................................" + formatIdRowCompact(ag3) + "<br>" +
767             "Number of instances:.................." + formatDataRow(ag4) + "<br>" +
768             "Near-RT RICs:........................." + formatDataRow(ag5) + "<br>" +
769             "</font>" +
770             "<h3>MR Stub interface</h3>" +
771             "<font face=\"monospace\">"+
772             "Submitted requests:............................" + formatDataRow(mr1) + "<br>" +
773             "Fetched requests:.............................." + formatDataRow(mr2) + "<br>" +
774             "Current requests waiting:......................" + formatDataRow(mr3) + "<br>" +
775             "Submitted responses:..........................." + formatDataRow(mr4) + "<br>" +
776             "Fetched responses.............................." + formatDataRow(mr5) + "<br>" +
777             "Current responses waiting......................" + formatDataRow(mr6) + "<br>" +
778             "</font>"+
779             "<h3>Callback receiver</h3>" +
780             "<font face=\"monospace\">" +
781             "Callbacks received:..................." + formatDataRow(cr1) + "<br>" +
782             "Callbacks fetched:...................." + formatDataRow(cr2) + "<br>" +
783             "Number of waiting callback messages:.." + formatDataRow(cr3) + "<br>" +
784             "</font>" +
785             "<h3>Near-RT RIC Simulators</h3>" +
786             "<font face=\"monospace\">"
787
788             htmlStr=htmlStr+padding("Near-RT RIC Simulator name", 35,"&nbsp;")
789             htmlStr=htmlStr+padding("Types", 10,"&nbsp;")
790             htmlStr=htmlStr+padding("Instances", 12,"&nbsp;")
791             htmlStr=htmlStr+padding("Data delivery", 12,"&nbsp;")+"<br>"
792             htmlStr=htmlStr+padding("",70,"=")+"<br>"
793             for(var simIndex=0;simIndex<simnames.length;simIndex++) {
794                 htmlStr=htmlStr+padding(simnames[simIndex]+ " ("+simports[simIndex]+")",35,"&nbsp;");
795                 htmlStr=htmlStr+padding(simvar2[simIndex],10,"&nbsp;")
796                 htmlStr=htmlStr+padding(simvar1[simIndex],12    ,"&nbsp;")
797                 htmlStr=htmlStr+padding(simvar6[simIndex],12,"&nbsp;")
798                 htmlStr=htmlStr+"<br>";
799             }
800
801             htmlStr=htmlStr+"<br>";
802             htmlStr=htmlStr+padding("Near-RT RIC Simulator name", 35,"&nbsp;")
803             htmlStr=htmlStr+padding("Version", 20,"&nbsp;")
804             htmlStr=htmlStr+padding("Type-IDs", 10,"&nbsp;")+"<br>"
805             htmlStr=htmlStr+padding("",65,"=")+"<br>"
806             for(simIndex=0;simIndex<simnames.length;simIndex++) {
807                 htmlStr=htmlStr+padding(simnames[simIndex]+ " ("+simports[simIndex]+")",35,"&nbsp;");
808                 htmlStr=htmlStr+padding(simvar4[simIndex],20,"&nbsp;")
809                 htmlStr=htmlStr+padding(formatIdRowCompact(simvar3[simIndex]),10,"&nbsp;")
810                 htmlStr=htmlStr+"<br>";
811             }
812
813             htmlStr=htmlStr+"<br>";
814             htmlStr=htmlStr+padding("Near-RT RIC Simulator name", 35,"&nbsp;")
815             htmlStr=htmlStr+padding("Remote hosts", 50,"&nbsp;")+"<br>"
816             htmlStr=htmlStr+padding("",90,"=")+"<br>"
817             for(simIndex=0;simIndex<simnames.length;simIndex++) {
818                 htmlStr=htmlStr+padding(simnames[simIndex]+ " ("+simports[simIndex]+")",35,"&nbsp;");
819                 htmlStr=htmlStr+padding(simvar5[simIndex],50,"&nbsp;")
820                 htmlStr=htmlStr+"<br>";
821             }
822
823             htmlStr=htmlStr+
824            "</body>" +
825           "</html>";
826         res.send(htmlStr);
827 })
828
829 var httpServer = http.createServer(app);
830 var httpPort=9999;
831 httpServer.listen(httpPort);
832 console.log("Simulator monitor listening (http) at "+httpPort);
833 console.log("Open the web page on localhost:9999/mon to view the policy statistics page.")
834 console.log("Open the web page on localhost:9999/mon2 to view the enrichment statistics page.")