Added error log parsing capability

Bryan Roe committed Apr 13, 2021 at 18:14 UTC 20086dc361d721bf413d51b6a96c1f96fa426360
2 files changed +196 -1
agents/meshcore.js
+17 -1
@@ -2736,7 +2736,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
2736 var response = null;
2737 switch (cmd) {
2738 case 'help': { // Displays available commands
2739 - var fin = '', f = '', availcommands = 'agentupdate,msh,timerinfo,coreinfo,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,wslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,wallpaper,agentmsg';
2739 + var fin = '', f = '', availcommands = 'agentupdate,errorlog,msh,timerinfo,coreinfo,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,wslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,wallpaper,agentmsg';
2740 if (require('os').dns != null) { availcommands += ',dnsinfo'; }
2741 if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
2742 if (amt != null) { availcommands += ',amt,amtconfig,amtevents'; }
@@ -2764,6 +2764,22 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
2764 agentUpdate_Start(null, { sessionid: sessionid });
2765 }
2766 break;
2767 + case 'errorlog':
2768 + switch(args['_'].length)
2769 + {
2770 + case 0:
2771 + // All Error Logs
2772 + response = JSON.stringify(require('util-agentlog').read(), null, 1);
2773 + break;
2774 + case 1:
2775 + // Error Logs, by either count or timestamp
2776 + response = JSON.stringify(require('util-agentlog').read(parseInt(args['_'][0])), null, 1);
2777 + break;
2778 + default:
2779 + response = "Proper usage:\r\n errorlog [lastCount|linuxEpoch]";
2780 + break;
2781 + }
2782 + break;
2783 case 'msh':
2784 response = JSON.stringify(_MSH(), null, 2);
2785 break;
agents/modules_meshcore/util-agentlog.js new
+179
@@ -0,0 +1,179 @@
1 +/*
2 +Copyright 2021 Intel Corporation
3 +
4 +Licensed under the Apache License, Version 2.0 (the "License");
5 +you may not use this file except in compliance with the License.
6 +You may obtain a copy of the License at
7 +
8 + http://www.apache.org/licenses/LICENSE-2.0
9 +
10 +Unless required by applicable law or agreed to in writing, software
11 +distributed under the License is distributed on an "AS IS" BASIS,
12 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 +See the License for the specific language governing permissions and
14 +limitations under the License.
15 +*/
16 +
17 +
18 +function parseLine(entry)
19 +{
20 + var test = entry.match(/^\[.*M\]/);
21 + if (test == null)
22 + {
23 + test = entry.match(/\[.+ => .+:[0-9]+\]/);
24 + if (test != null)
25 + {
26 + // Windows Crash Entry
27 + var file = test[0].substring(1).match(/(?!.+ ).+(?=:)/);
28 + var line = test[0].match(/(?!:)[0-9]+(?=\]$)/);
29 + var fn = test[0].match(/(?!\[).+(?= =>)/);
30 +
31 + if (file != null) { this.results.peek().f = file[0].trim(); }
32 + if (line != null) { this.results.peek().l = line[0]; }
33 + if (fn != null) { this.results.peek().fn = fn[0]; }
34 + }
35 + else
36 + {
37 + test = entry.match(/^[\.\/].+\(\) \[0x[0-9a-fA-F]+\]$/);
38 + if (test != null)
39 + {
40 + // Linux Crash Stack with no symbols
41 + test = test[0].match(/(?!\[)0x[0-9a-fA-F]+(?=\]$)/);
42 + if (test != null)
43 + {
44 + if (this.results.peek().sx == null) { this.results.peek().sx = []; }
45 + this.results.peek().sx.unshift(test[0]);
46 + }
47 + }
48 + else
49 + {
50 + test = entry.match(/^\[.+_[0-9a-fA-F]{16}\]$/);
51 + if(test!=null)
52 + {
53 + // Linux Crash ID
54 + test = test[0].match(/(?!_)[0-9a-fA-F]{16}(?=\]$)/);
55 + this.results.peek().h = test[0];
56 + }
57 + }
58 +
59 + test = entry.match(/(?!^=>)\/+.+:[0-9]+$/);
60 + if(test!=null)
61 + {
62 + // Linux Crash Entry
63 + if (this.results.peek().s == null) { this.results.peek().s = []; }
64 + this.results.peek().s.unshift(test[0]);
65 + }
66 +
67 + }
68 + return;
69 + }
70 + test = test[0];
71 +
72 + var dd = test.substring(1, test.length -1);
73 + var c = dd.split(' ');
74 + var t = c[1].split(':');
75 + if (c[2] == 'PM') { t[0] = parseInt(t[0]) + 12; if (t[0] == 24) { t[0] = 0; } }
76 +
77 + var d = Date.parse(c[0] + 'T' + t.join(':'));
78 + var msg = entry.substring(test.length).trim();
79 + var hash = msg.match(/^\[[0-9a-fA-F]{16}\]/);
80 + if (hash != null)
81 + {
82 + hash = hash[0].substring(1, hash[0].length - 1);
83 + msg = msg.substring(hash.length + 2).trim();
84 + }
85 + else
86 + {
87 + hash = msg.match(/^\[\]/);
88 + if(hash!=null)
89 + {
90 + msg = msg.substring(2).trim();
91 + hash = null;
92 + }
93 + }
94 +
95 + var log = { t: Math.floor(d / 1000), m: msg };
96 + if (hash != null) { log.h = hash; }
97 +
98 + // Check for File/Line in generic log entry
99 + test = msg.match(/^.+:[0-9]+ \([0-9]+,[0-9]+\)/);
100 + if (test != null)
101 + {
102 + log.m = log.m.substring(test[0].length).trim();
103 + log.f = test[0].match(/^.+(?=:[0-9]+)/)[0];
104 + log.l = test[0].match(/(?!:)[0-9]+(?= \([0-9]+,[0-9]+\)$)/)[0];
105 + }
106 +
107 + this.results.push(log);
108 +}
109 +
110 +function readLog_data(buffer)
111 +{
112 + var lines = buffer.toString().split('\n');
113 + while(lines.length > 0)
114 + {
115 + parseLine.call(this, lines.shift());
116 + }
117 +}
118 +
119 +function readLogEx(path)
120 +{
121 + var ret = [];
122 + try
123 + {
124 + var s = require('fs').createReadStream(path);
125 + s.results = ret;
126 + s.on('data', readLog_data);
127 + s.resume();
128 + s.removeAllListeners('data');
129 + s = null;
130 + }
131 + catch(z)
132 + {
133 + }
134 +
135 + return (ret);
136 +}
137 +
138 +function readLog(criteria, path)
139 +{
140 + var objects = readLogEx(path == null ? (process.execPath.split('.exe').join('') + '.log') : path);
141 + var ret = [];
142 +
143 + if (typeof (criteria) == 'string')
144 + {
145 + try
146 + {
147 + var dstring = Date.parse(criteria);
148 + criteria = Math.floor(dstring / 1000);
149 + }
150 + catch(z)
151 + {
152 + }
153 + }
154 +
155 + if (typeof (criteria) == 'number')
156 + {
157 + if(criteria < 1000)
158 + {
159 + // Return the last xxx entries
160 + ret = objects.slice(objects.length - ((criteria > objects.length) ? objects.length : criteria));
161 + }
162 + else
163 + {
164 + // Return entries that are newer than xxx
165 + var i;
166 + for (i = 0; i < objects.length && objects[i].t <= criteria; ++i) { }
167 + ret = objects.slice(i);
168 + }
169 + }
170 + else
171 + {
172 + ret = objects;
173 + }
174 +
175 + return (ret);
176 +}
177 +
178 +module.exports = { read: readLog, readEx: readLogEx }
179 +