Log Parser
-
Love the new log parser, would be nice to have a stand-alone one as well that can run locally on my computer?
-
You can actually copy/paste the embedded javascript to a standalone html page if you want. Here you go:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"></link> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <div id="parser"> <h4>Paste log from gateway or node here:</h4> <textarea class="form-control" @change="parse" rows="10" v-model="source"></textarea> <button @click="parse" class="btn btn-primary">Parse</button> <button @click="source=''" class="btn btn-default">Clear</button> <h4>Human readable output:</h4> <div class="table-responsive"> <table class="table table-condensed"> <tr> <th>Node Id</th> <th>Child Sensor</th> <th>Command Type</th> <th>Ack Req/Resp</th> <th>Type</th> <th>Payload</th> <th>Description</th> </tr> <tr v-for="r in parsed"> <td v-for="c in r" v-html="c"></td> </tr> </table> </div> </div> <script> var types = { "presentation":[ "S_DOOR", "S_MOTION", "S_SMOKE", "S_LIGHT", "S_DIMMER", "S_COVER", "S_TEMP", "S_HUM", "S_BARO", "S_WIND", "S_RAIN", "S_UV", "S_WEIGHT", "S_POWER", "S_HEATER", "S_DISTANCE", "S_LIGHT_LEVEL", "S_ARDUINO_NODE", "S_ARDUINO_REPEATER_NODE", "S_LOCK", "S_IR", "S_WATER", "S_AIR_QUALITY", "S_CUSTOM", "S_DUST", "S_SCENE_CONTROLLER", "S_RGB_LIGHT", "S_RGBW_LIGHT", "S_COLOR_SENSOR", "S_HVAC", "S_MULTIMETER", "S_SPRINKLER", "S_WATER_LEAK", "S_SOUND", "S_VIBRATION", "S_MOISTURE", "S_INFO", "S_GAS", "S_GPS", "S_WATER_QUALITY" ], "internal": [ "I_BATTERY_LEVEL", "I_TIME", "I_VERSION", "I_ID_REQUEST", "I_ID_RESPONSE", "I_INCLUSION_MODE", "I_CONFIG", "I_FIND_PARENT_REQUEST", "I_FIND_PARENT_RESPONSE", "I_LOG_MESSAGE", "I_CHILDREN", "I_SKETCH_NAME", "I_SKETCH_VERSION", "I_REBOOT", "I_GATEWAY_READY", "I_SIGNING_PRESENTATION", "I_NONCE_REQUEST", "I_NONCE_RESPONSE", "I_HEARTBEAT_REQUEST", "I_PRESENTATION", "I_DISCOVER_REQUEST", "I_DISCOVER_RESPONSE", "I_HEARTBEAT_RESPONSE", "I_LOCKED", "I_PING", "I_PONG", "I_REGISTRATION_REQUEST", "I_REGISTRATION_RESPONSE", "I_DEBUG" ], "subtype":[ "V_TEMP", "V_HUM", "V_STATUS", "V_PERCENTAGE", "V_PRESSURE", "V_FORECAST", "V_RAIN", "V_RAINRATE", "V_WIND", "V_GUST", "V_DIRECTION", "V_UV", "V_WEIGHT", "V_DISTANCE", "V_IMPEDANCE", "V_ARMED", "V_TRIPPED", "V_WATT", "V_KWH", "V_SCENE_ON", "V_SCENE_OFF", "V_HVAC_FLOW_STATE", "V_HVAC_SPEED", "V_LIGHT_LEVEL", "V_VAR1", "V_VAR2", "V_VAR3", "V_VAR4", "V_VAR5", "V_UP", "V_DOWN", "V_STOP", "V_IR_SEND", "V_IR_RECEIVE", "V_FLOW", "V_VOLUME", "V_LOCK_STATUS", "V_LEVEL", "V_VOLTAGE", "V_CURRENT", "V_RGB", "V_RGBW", "V_ID", "V_UNIT_PREFIX", "V_HVAC_SETPOINT_COOL", "V_HVAC_SETPOINT_HEAT", "V_HVAC_FLOW_MODE", "V_TEXT", "V_CUSTOM", "V_POSITION", "V_IR_RECORD", "V_PH", "V_ORP", "V_EC", "V_VAR", "V_VA", "V_POWER_FACTOR" ], command: [ "PRESENTATION", "SET", "REQ", "INTERNAL", "STREAM" ], "payloadtype":[ "P_STRING", "P_BYTE", "P_INT16", "P_UINT16", "P_LONG32", "P_ULONG32", "P_CUSTOM", "P_FLOAT32" ]}; var match = [ { re: /^(?:\d+ )?MCO:BGN:INIT (\w+),CP=([^,]+),VER=(.*)/, d: "Core initialization of <b>$1</b>, with capabilities $2, library version $3" }, { re: /^(?:\d+ )?MCO:BGN:BFR/, d: "Callback before()" }, { re: /^(?:\d+ )?MCO:BGN:STP/, d: "Callback setup()" }, { re: /^(?:\d+ )?MCO:BGN:INIT OK,TSP=(.*)/, d: "Core initialized, transport status <b>$1</b>, (1=initialized, 0=not initialized, NA=not available)" }, { re: /^(?:\d+ )?MCO:BGN:NODE UNLOCKED/, d: "Node successfully unlocked (see signing chapter)" }, { re: /^(?:\d+ )?!MCO:BGN:TSP FAIL/, d: "Transport initialization failed" }, { re: /^(?:\d+ )?MCO:REG:REQ/, d: "Registration request" }, { re: /^(?:\d+ )?MCO:REG:NOT NEEDED/, d: "No registration needed (i.e. GW)" }, { re: /^(?:\d+ )?!MCO:SND:NODE NOT REG/, d: "Node is not registered, cannot send message" }, { re: /^(?:\d+ )?MCO:PIM:NODE REG=(\d+)/, d: "Registration response received, registration status <b>$1</b>" }, { re: /^(?:\d+ )?MCO:PIM:ROUTE N=(\d+),R=(\d+)/, d: "Routing table, messages to node <b>$1</b> are routed via node <b>$2</b>" }, { re: /^(?:\d+ )?MCO:SLP:MS=(\d+),SMS=(\d+),I1=(\d+),M1=(\d+),I2=(\d+),M2=(\d+)/, d: "Sleep node, duration <b>$1</b> ms, SmartSleep=<b>$2</b>, Int1=<b>$3</b>, Mode1=<b>$4</b>, Int2=<b>$5</b>, Mode2=<b>$6</b>" }, { re: /^(?:\d+ )?MCO:SLP:TPD/, d: "Sleep node, powerdown transport" }, { re: /^(?:\d+ )?MCO:SLP:WUP=(-?\d+)/, d: "Node woke-up, reason/IRQ=<b>$1</b> (-2=not possible, -1=timer, >=0 IRQ)" }, { re: /^(?:\d+ )?!MCO:SLP:FWUPD/, d: "Sleeping not possible, FW update ongoing" }, { re: /^(?:\d+ )?!MCO:SLP:REP/, d: "Sleeping not possible, repeater feature enabled" }, { re: /^(?:\d+ )?!MCO:SLP:TNR/, d: " Transport not ready, attempt to reconnect until timeout" }, { re: /^(?:\d+ )?MCO:NLK:NODE LOCKED. UNLOCK: GND PIN (\d+) AND RESET/, d: "Node locked during booting, see signing documentation for additional information" }, { re: /^(?:\d+ )?MCO:NLK:TPD/, d: "Powerdown transport" }, { re: /^(?:\d+ )?TSM:INIT/, d: "Transition to <b>Init</b> state" }, { re: /^(?:\d+ )?TSM:INIT:STATID=(\d+)/, d: "Init static node id <b>$1</b>" }, { re: /^(?:\d+ )?TSM:INIT:TSP OK/, d: "Transport device configured and fully operational" }, { re: /^(?:\d+ )?TSM:INIT:GW MODE/, d: "Node is set up as GW, thus omitting ID and findParent states" }, { re: /^(?:\d+ )?!TSM:INIT:TSP FAIL/, d: "Transport device initialization failed" }, { re: /^(?:\d+ )?TSM:FPAR/, d: "Transition to <b>Find Parent</b> state" }, { re: /^(?:\d+ )?TSM:FPAR:STATP=(\d+)/, d: "Static parent <b>$1</b> has been set, skip finding parent" }, { re: /^(?:\d+ )?TSM:FPAR:OK/, d: "Parent node identified" }, { re: /^(?:\d+ )?!TSM:FPAR:NO REPLY/, d: "No potential parents replied to find parent request" }, { re: /^(?:\d+ )?!TSM:FPAR:FAIL/, d: "Finding parent failed" }, { re: /^(?:\d+ )?TSM:ID/, d: "Transition to <b>Request Id</b> state" }, { re: /^(?:\d+ )?TSM:ID:OK,ID=(\d+)/, d: "Node id <b>$1</b> is valid" }, { re: /^(?:\d+ )?TSM:ID:REQ/, d: "Request node id from controller" }, { re: /^(?:\d+ )?!TSM:ID:FAIL,ID=(\d+)/, d: "Id verification failed, <b>$1</b> is invalid" }, { re: /^(?:\d+ )?TSM:UPL/, d: "Transition to <b>Check Uplink</b> state" }, { re: /^(?:\d+ )?TSM:UPL:OK/, d: "Uplink OK, GW returned ping" }, { re: /^(?:\d+ )?!TSM:UPL:FAIL/, d: "Uplink check failed, i.e. GW could not be pinged" }, { re: /^(?:\d+ )?TSM:READY/, d: "Transition to <b>Ready</b> state" }, { re: /^(?:\d+ )?TSM:READY:SRT/, d: "Save routing table" }, { re: /^(?:\d+ )?TSM:READY:ID=(\d+),PAR=(\d+),DIS=(\d+)/, d: "Transport ready, node id <b>$1</b>, parent node id <b>$2</b>, distance to GW is <b>$3</b>" }, { re: /^(?:\d+ )?!TSM:READY:UPL FAIL,SNP/, d: "Too many failed uplink transmissions, search new parent" }, { re: /^(?:\d+ )?!TSM:READY:FAIL,STATP/, d: "Too many failed uplink transmissions, static parent enforced" }, { re: /^(?:\d+ )?TSM:FAIL:CNT=(\d+)/, d: "Transition to <b>Failure</b> state, consecutive failure counter is <b>$1</b>" }, { re: /^(?:\d+ )?TSM:FAIL:PDT/, d: "Power-down transport" }, { re: /^(?:\d+ )?TSM:FAIL:RE-INIT/, d: "Attempt to re-initialize transport" }, { re: /^(?:\d+ )?TSF:CKU:OK,FCTRL/, d: "Uplink OK, flood control prevents pinging GW in too short intervals" }, { re: /^(?:\d+ )?TSF:CKU:OK/, d: "Uplink OK" }, { re: /^(?:\d+ )?TSF:CKU:DGWC,O=(\d+),N=(\d+)/, d: "Uplink check revealed changed network topology, old distance <b>$1</b>, new distance <b>$2</b>" }, { re: /^(?:\d+ )?TSF:CKU:FAIL/, d: "No reply received when checking uplink" }, { re: /^(?:\d+ )?TSF:SID:OK,ID=(\d+)/, d: "Node id <b>$1</b> assigned" }, { re: /^(?:\d+ )?!TSF:SID:FAIL,ID=(\d+)/, d: "Assigned id <b>$1</b> is invalid" }, { re: /^(?:\d+ )?TSF:PNG:SEND,TO=(\d+)/, d: "Send ping to destination <b>$1</b>" }, { re: /^(?:\d+ )?TSF:WUR:MS=(\d+)/, d: "Wait until transport ready, timeout <b>$1</b>" }, { re: /^(?:\d+ )?TSF:MSG:ACK REQ/, d: "ACK message requested" }, { re: /^(?:\d+ )?TSF:MSG:ACK/, d: "ACK message, do not proceed but forward to callback" }, { re: /^(?:\d+ )?TSF:MSG:FPAR RES,ID=(\d+),D=(\d+)/, d: "Response to find parent request received from node <b>$1</b> with distance <b>$2</b> to GW" }, { re: /^(?:\d+ )?TSF:MSG:FPAR PREF FOUND/, d: "Preferred parent found, i.e. parent defined via MY_PARENT_NODE_ID" }, { re: /^(?:\d+ )?TSF:MSG:FPAR OK,ID=(\d+),D=(\d+)/, d: "Find parent response from node <b>$1</b> is valid, distance <b>$2</b> to GW" }, { re: /^(?:\d+ )?TSF:MSG:FPAR INACTIVE/, d: "Find parent response received, but no find parent request active, skip response" }, { re: /^(?:\d+ )?TSF:MSG:FPAR REQ,ID=(\d+)/, d: "Find parent request from node <b>$1</b>" }, { re: /^(?:\d+ )?TSF:MSG:PINGED,ID=(\d+),HP=(\d+)/, d: "Node pinged by node <b>$1</b> with <b>$2</b> hops" }, { re: /^(?:\d+ )?TSF:MSG:PONG RECV,HP=(\d+)/, d: "Pinged node replied with <b>$1</b> hops" }, { re: /^(?:\d+ )?TSF:MSG:BC/, d: "Broadcast message received" }, { re: /^(?:\d+ )?TSF:MSG:GWL OK/, d: "Link to GW ok" }, { re: /^(?:\d+ )?TSF:MSG:FWD BC MSG/, d: "Controlled broadcast message forwarding" }, { re: /^(?:\d+ )?TSF:MSG:REL MSG/, d: "Relay message" }, { re: /^(?:\d+ )?TSF:MSG:REL PxNG,HP=(\d+)/, d: "Relay PING/PONG message, increment hop counter to <b>$1</b>" }, { re: /^(?:\d+ )?!TSF:MSG:LEN,(\d+)!=(\d+)/, d: "Invalid message length, <b>$1</b> (actual) != <b>$2</b> (expected)" }, { re: /^(?:\d+ )?!TSF:MSG:PVER,(\d+)!=(\d+)/, d: "Message protocol version mismatch, <b>$1</b> (actual) != <b>$2</b> (expected)" }, { re: /^(?:\d+ )?!TSF:MSG:SIGN VERIFY FAIL/, d: "Signing verification failed" }, { re: /^(?:\d+ )?!TSF:MSG:REL MSG,NORP/, d: "Node received a message for relaying, but node is not a repeater, message skipped" }, { re: /^(?:\d+ )?!TSF:MSG:SIGN FAIL/, d: "Signing message failed" }, { re: /^(?:\d+ )?!TSF:MSG:GWL FAIL/, d: "GW uplink failed" }, { re: /^(?:\d+ )?TSF:SAN:OK/, d: "Sanity check passed" }, { re: /^(?:\d+ )?!TSF:SAN:FAIL/, d: "Sanity check failed, attempt to re-initialize radio" }, { re: /^(?:\d+ )?TSF:CRT:OK/, d: "Clearing routing table successful" }, { re: /^(?:\d+ )?TSF:LRT:OK/, d: "Loading routing table successful" }, { re: /^(?:\d+ )?TSF:SRT:OK/, d: "Saving routing table successful" }, { re: /^(?:\d+ )?!TSF:RTE:FPAR ACTIVE/, d: "Finding parent active, message not sent" }, { re: /^(?:\d+ )?!TSF:RTE:DST (\d+) UNKNOWN/, d: "Routing for destination <b>$1</b> unknown, sending message to parent" }, { re: /^(?:\d+ )?!TSF:SND:TNR/, d: "Transport not ready, message cannot be sent" }, { re: /^(?:\d+ )?TSF:MSG:READ,(\d+)-(\d+)-(\d+),s=(\d+),c=(\d+),t=(\d+),pt=(\d+),l=(\d+),sg=(\d+):(.*)/, d: "<u><b>Received Message</b></u><br><b>Sender</b>: $1<br><b>Last Node</b>: $2<br><b>Destination</b>: $3<br><b>Sensor Id</b>: $4<br><b>Command</b>: {command:$5}<br><b>Message Type</b>: {type:$5:$6}<br><b>Payload Type</b>: {pt:$7}<br><b>Payload Length</b>: $8<br><b>Signing</b>: $9<br><b>Payload</b>: $10" }, { re: /^(?:\d+ )?TSF:MSG:SEND,(\d+)-(\d+)-(\d+)-(\d+),s=(\d+),c=(\d+),t=(\d+),pt=(\d+),l=(\d+),sg=(\d+),ft=(\d+),st=(\w+):(.*)/, d: "<u><b>Sent Message</b></u><br><b>Sender</b>: $1<br><b>Last Node</b>: $2<br><b>Next Node</b>: $3<br><b>Destination</b>: $4<br><b>Sensor Id</b>: $5<br><b>Command</b>: {command:$6}<br><b>Message Type</b>:{type:$6:$7}<br><b>Payload Type</b>: {pt:$8}<br><b>Payload Length</b>: $9<br><b>Signing</b>: $10<br><b>Failed uplink counter</b>: $11<br><b>Status</b>: $12 (OK=success, NACK=no radio ACK received)<br><b>Payload</b>: $13" }, { re: /^(?:\d+ )?!TSF:MSG:SEND,(\d+)-(\d+)-(\d+)-(\d+),s=(\d+),c=(\d+),t=(\d+),pt=(\d+),l=(\d+),sg=(\d+),ft=(\d+),st=(\w+):(.*)/, d: "<u><b style='color:red'>Sent Message</b></u><br><b>Sender</b>: $1<br><b>Last Node</b>: $2<br><b>Next Node</b>: $3<br><b>Destination</b>: $4<br><b>Sensor Id</b>: $5<br><b>Command</b>: {command:$6}<br><b>Message Type</b>:{type:$6:$7}<br><b>Payload Type</b>: {pt:$8}<br><b>Payload Length</b>: $9<br><b>Signing</b>: $10<br><b>Failed uplink counter</b>: $11<br><b>Status</b>: $12 (OK=success, NACK=no radio ACK received)<br><b>Payload</b>: $13" }, ]; new Vue({ el: "#parser", data: function() { return { source: "", parsed: [] }; }, methods: { selector: function(cmd) { switch (cmd) { case "0": return "presentation"; break; case "1": case "2": return "subtype"; break; case "3": return "internal"; break; } }, match: function(msg) { var self = this; for (var i=0, len=match.length;i<len; i++) { var r = match[i]; if (r.re.test(msg)) { msg = msg.replace(r.re, r.d); msg = msg.replace(/{command:(\d+)}/g, function(match, m1) { return types.command[m1] }); msg = msg.replace(/{pt:(\d+)}/g, function(match, m1) { return types.payloadtype[m1] }); return msg.replace(/{type:(\d+):(\d+)}/g, function(match, cmd, type) { return types[self.selector(cmd)][type] }); } } }, parse: function() { var self = this; var rows = this.source.split("\n"); this.parsed = _.map(rows, function(r) { var p = r.split(";"); if (p.length !== 6) { var desc = self.match(r); return ["","","","",desc?"":"Unknown", r, desc]; } var sel = self.selector(p[2]); var desc = ""; if (p[2] == "3" && p[4] == "9") { desc = self.match(p[5]); } return [ p[0], p[1], types.command[p[2]], p[3]=="1"?"true":"false", types[sel][p[4]], p[5], desc ]; }); } } }); </script>
-
Brilliant, THANKS!