Skip to content

Instantly share code, notes, and snippets.

@victorjonsson
Last active March 4, 2024 12:47
Show Gist options
  • Save victorjonsson/f9dc8478df39958ca07ec3f4e4dcbcaf to your computer and use it in GitHub Desktop.
Save victorjonsson/f9dc8478df39958ca07ec3f4e4dcbcaf to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body class="p-5" onload="renderLog(document.getElementById('the-log').value)">
<textarea id="the-log" onchange="renderLog(this.value)" style="width:80%">2022-05-23 15:55:58.6740|INFO|GXApp.Services.Filesystem.LogService+LogServiceInstance|====> MALÅ Controller App starting <====
2022-05-23 15:55:58.7772|INFO|IoActorV2| AppVersion: 10.20512, ComLib v10.02
2022-05-23 15:55:58.7974|INFO|IoActorV2| Device Model: SM-T545, Manufacturer: samsung, DeviceName: Galaxy Tab Active Pro, Version:11, Platform: Android, Idiom: Tablet, DeviceType: Physical
2022-05-23 15:55:58.8023|INFO|ActorSystem| Antenna Service initialized.
2022-05-23 15:55:58.9335|INFO|ActorSystem| SetComlibDebugFile: Disabled
2022-05-23 15:55:58.9557|INFO|ActorSystem| HomeViewModelInstance: New appVersion 10.20512 installed (from previous ). Reset feature tour flag
2022-05-23 15:55:58.9598|INFO|ActorSystem| HomeViewModelInstance: Instance initiated
2022-05-23 15:56:06.6653|INFO|IoActorV2| MsgConnect from IoActorV2 : New Ip addresses found. lastUsedIpAddress: 0.0.0.0, try ReInitComLib(192.168.210.86) with init delay 1000
2022-05-23 15:56:07.7080|INFO|IoActorV2| MsgConnect from IoActorV2 : ReInitComLib(192.168.210.86) success.
2022-05-23 15:56:07.7398|INFO|IoActorV2| CheckGnssStatus: GnssStatus updated from -1 to NoData
2022-05-23 15:56:07.7398|INFO|IoActorV2| MsgConnect from ActorSystem : New Ip addresses found. lastUsedIpAddress: 0.0.0.0, try ReInitComLib(192.168.210.86) with init delay 2000
2022-05-23 15:56:09.7481|INFO|IoActorV2| MsgConnect from ActorSystem : ReInitComLib(192.168.210.86) success.
2022-05-23 15:56:09.7730|INFO|IoActorV2| MsgConnect from IoActorV2 : New Ip addresses found. lastUsedIpAddress: 0.0.0.0, try ReInitComLib(192.168.210.86) with init delay 3000
2022-05-23 15:56:12.7739|INFO|IoActorV2| MsgConnect from IoActorV2 : ReInitComLib(192.168.210.86) success.
2022-05-23 15:56:12.7982|INFO|IoActorV2| MsgConnect from ActorSystem : New Ip addresses found. lastUsedIpAddress: 0.0.0.0, try ReInitComLib(192.168.210.86) with init delay 4000
2022-05-23 15:56:16.7997|INFO|IoActorV2| MsgConnect from ActorSystem : ReInitComLib(192.168.210.86) success.
2022-05-23 15:56:17.0418|INFO|IoActorV2| MsgConnect from IoActorV2 : New Ip addresses found. lastUsedIpAddress: 0.0.0.0, try ReInitComLib(192.168.210.86) with init delay 5000
2022-05-23 15:56:22.0430|INFO|IoActorV2| MsgConnect from IoActorV2 : ReInitComLib(192.168.210.86) success.
2022-05-23 15:56:22.2849|INFO|IoActorV2| MsgConnect from ActorSystem : New Ip addresses found. lastUsedIpAddress: 0.0.0.0, try ReInitComLib(192.168.210.86) with init delay 6000
2022-05-23 15:56:28.2852|INFO|IoActorV2| MsgConnect from ActorSystem : ReInitComLib(192.168.210.86) success.
2022-05-23 15:56:28.3476|INFO|IoActorV2| MsgConnect from ActorSystem : Comlib connect success
2022-05-23 15:56:28.5107|INFO|IoActorV2| MsgConnect from ActorSystem : HandleMsgConnect(): SDCardStatus read from settings and set to 0
2022-05-23 15:56:28.5644|INFO|IoActorV2| MsgConnect from ActorSystem : HandleMsgConnect(): SDCardStatus check OK
2022-05-23 15:56:28.6601|INFO|IoActorV2| MsgConnect from ActorSystem : Antenna connected
2022-05-23 15:56:28.7777|WARN|ActorSystem| timeInterval is zero, setting HorizontalTickInterval = 0.05
2022-05-23 15:56:29.0299|INFO|IoActorV2| MsgGetBatteryVoltage from BoundaryReceiverActor : Internal GPS NMEA output enable success
2022-05-23 15:56:29.0892|INFO|ActorSystem| Refresh: Call GetAntennaSettings() and GetBatteryVoltage()
2022-05-23 15:56:29.3056|INFO|IoActorV2| CheckGnssStatus: GnssStatus updated from -4 to GPSFix
2022-05-23 15:56:29.7426|INFO|IoActorV2| Setting trig type to WHEEL: distanceInterval=0.0248053469303383 m
2022-05-23 15:56:29.7576|INFO|IoActorV2| TestPattern mode set to False
2022-05-23 15:56:49.1091|INFO|GXApp.Droid.Renderers.LoggingButtonRenderer|"StartupInfoPopupPageSkipButton"
2022-05-23 15:56:49.4522|INFO|ActorSystem| ShowProjectChecking: DONE
2022-05-23 15:56:50.3724|INFO|GXApp.Droid.Renderers.LoggingButtonRenderer|"2DButton"
2022-05-23 15:56:51.5710|INFO|GXApp.Droid.Renderers.LoggingButtonRenderer|"ProjectInfoPopupPageOkButton"
2022-05-23 15:56:59.4152|INFO|GXApp.Views.MeasurementSettingsPage|"TriggerPicker","Distance"
2022-05-23 15:56:59.4300|INFO|GXApp.Views.MeasurementSettingsPage|"WheelSelectionPicker","Core"
2022-05-23 15:56:59.4664|INFO|GXApp.Views.MeasurementSettingsPage|"PositioningSelectionPicker","Internal GPS"
2022-05-23 15:56:59.4792|INFO|GXApp.Views.MeasurementSettingsPage|"VerticalScaleSelectionPicker","Depth"
2022-05-23 15:56:59.4944|INFO|GXApp.Views.MeasurementSettingsPage|"MeasurementUnitSelectionPicker","Metric"
2022-05-23 15:56:59.5125|INFO|GXApp.Views.MeasurementSettingsPage|"MalaVisionModeSelectionPicker","PRODUCTION"
2022-05-23 15:56:59.5258|INFO|GXApp.Views.MeasurementSettingsPage|"RepairModeSelectionPicker","On"
2022-05-23 15:57:03.9503|INFO|GXApp.Views.MeasurementSettingsPage|"TriggerPicker","Time"
2022-05-23 15:57:04.0848|INFO|IoActorV2| Setting trig type to TIME: timeInterval=0.05 s
2022-05-23 15:57:09.2228|INFO|ActorSystem| GxPageViewModel(): SDCardStatus check returned OK
2022-05-23 15:57:09.4979|INFO|ActorSystem| Antenna Service: StartMeasuring(Random,1,0) ProjectID=5f84b903-cc85-42b6-8a25-30b78eda4507 ProfileID=db7f2692-5bd6-46d4-ba76-91dfc10b160d
2022-05-23 15:57:09.5646|INFO|ActorSystem| Start measurement sent: Proj2D-0001 - Profile 1 [1], MonitorID:0, AntennaID:26602001, AntennaModel:GX750, Trig:Time, Interval:0.05 s, Positioning:AntennaGnss, COR:Yes, Voltage:
2022-05-23 15:57:09.5646|INFO|GXApp.Droid.Renderers.LoggingButtonRenderer|"StartStopButton"
2022-05-23 15:57:09.7736|INFO|IoActorV2| Measuring started
2022-05-23 15:57:09.7904|INFO|ActorSystem| OnMeasuringStarted(): Measurement started received
2022-05-23 15:57:09.7904|INFO|ActorSystem| Measurement started received
2022-05-23 15:57:09.9715|ERROR|ActorSystem| AddTraceTimeData Exception: System.NullReferenceException: Object reference not set to an instance of an object
at GXApp.Services.ProjectService+ProjectServiceInstance.AddTraceTimeData (System.UInt32 traceNr, System.DateTime anntennaTraceTime, System.Boolean isPps) [0x00006] in <997ef4725b8b414694455fbe73bbbe13>:0
2022-05-23 15:57:09.9715|ERROR|ActorSystem| AddTraceTimeData Exception: System.NullReferenceException: Object reference not set to an instance of an object
at GXApp.Services.ProjectService+ProjectServiceInstance.AddTraceTimeData (System.UInt32 traceNr, System.DateTime anntennaTraceTime, System.Boolean isPps) [0x00006] in <997ef4725b8b414694455fbe73bbbe13>:0
2022-05-23 15:57:09.9995|INFO|IoActorV2| MsgPoll from IoActorV2 : Trace 1
2022-05-23 15:57:12.8216|INFO|ActorSystem| MeasuringCmd: Stop button pressed. Enter stop procedure: Proj2D-0001 - Profile 1 [1]
2022-05-23 15:57:12.8216|INFO|GXApp.Droid.Renderers.LoggingButtonRenderer|"StartStopButton"
2022-05-23 15:57:12.8293|INFO|ActorSystem| MeasuringCmd: Call _antenna.SyncStopMeasuring()
2022-05-23 15:57:13.8789|INFO|IoActorV2| MsgSyncStopMeasuring from ActorSystem : StopMeasurement() returned 0
2022-05-23 15:57:13.8914|INFO|IoActorV2| MsgSyncStopMeasuring from ActorSystem : StopMeasurement() success in HandleMsgSyncMeasuring()
2022-05-23 15:57:13.9597|INFO|ActorSystem| MeasuringCmd: SyncStopMeasuring IsSyncReady:True cntSyncStop:0
2022-05-23 15:57:13.9757|INFO|ActorSystem| MeasuringCmd: Ignore call SyncMeasurement since 0 missedTraces
2022-05-23 15:57:13.9848|INFO|ActorSystem| MeasuringCmd: Now send stop measurement sent
2022-05-23 15:57:13.9932|INFO|ActorSystem| MeasuringCmd: Stop measurement sent
2022-05-23 15:57:14.9999|INFO|IoActorV2| MsgStopMeasuring from ActorSystem : HandleMsgStopMeasuring: MsgCorData _lastTraceNrInCorFile=61 _syncInProgress=False Timestamp=23/05/2022 13:57:13 SyncTimestamp=23/05/2022 13:57:13</textarea>
<hr>
<script type="text/html" id="log-template">
<div class="card" style="width: 90%">
<small style="color: #999; padding:1rem 0 0 1rem">%HEAD%</small>
<small class="gps" style="position: absolute; right:15px; top:10px; color: gray">📍 %GPS_STATUS%</small>
<div class="card-body">
<h5 class="card-title" title="%MESSAGE%">%TITLE%</h5>
<p class="card-text log-summary"></p>
<p style="display:none" class="card-text log-entries"></p>
</div>
</div>
<div class="arrow" style="display: none; font-size:300%; padding-left: 1rem; color:#999">
<strong style="font-size:30%; margin:25px 0 0; position:absolute">%TIME%</strong>
</div>
</script>
<div id="container"></div>
<script>
const parseLogLine = (line) => {
const parts = line.split('|');
try {
return {
date: new Date(parts[0].trim()),
type: parts[1].trim(),
id: parts[2].trim(),
message: parts.filter((v,i) => i > 2).join('|'),
traceData: '',
title: '',
children: []
}
} catch(err) {
console.warn("unable to parse line " + line + ', will return as trace data');
return {
date: undefined,
type: '',
id: '',
message: line,
traceData: '',
title: '',
children: []
}
}
};
const parseLog = logData => {
return logData.trim().split('\n').map(line => parseLogLine(line));
}
const gpsNoData = 'NoData';
let previousGpsState = gpsNoData;
const renderLogSection = (logSection, container) => {
const template = document.getElementById('log-template').innerHTML;
const element = document.createElement('DIV');
const gpsKeyWords = 'GnssStatus updated from';
if (logSection.message.indexOf('App starting') > -1) {
previousGpsState = 'NoData';
}
const gpsStatuses = logSection.children
.filter(entry => entry.message.indexOf(gpsKeyWords) > -1)
.map(entry => entry.message.split(gpsKeyWords)[1].split(' ')[3]);
let gpsMessage = gpsStatuses.length === 0 ? previousGpsState : gpsStatuses.join(', ')
if (gpsMessage !== gpsNoData) {
const internalGps = logSection.children.some(c => c.message.indexOf('Internal GPS NMEA') > -1);
if (internalGps) {
gpsMessage += ' (internal)';
}
}
previousGpsState = gpsMessage === gpsNoData ? gpsNoData : (gpsStatuses.length ? gpsStatuses.pop() : gpsMessage);
const html = template
.replace('%TITLE%', logSection.title)
.replace('%MESSAGE%', logSection.message)
.replace('%GPS_STATUS%', gpsMessage)
.replace('%HEAD%', getNiceDate(logSection.date) + ' ' + getClock(logSection.date));
element.innerHTML = html;
container.appendChild(element);
element.setAttribute('data-date', logSection.date.toString());
const logEntryContainer = element.querySelector('.log-entries');
let counts = {}, currentStatusColor;
logSection.children.forEach(logEntry => {
const logEntryElem = document.createElement('DIV');
let message = logEntry.message + '\n' + logEntry.traceData;
if (!logEntry.date) {
// this is only a new line of last message
logEntryElem.innerHTML = '<div style="background: '+currentStatusColor+'">' + message + '</div>';
} else {
counts[logEntry.type] = (counts[logEntry.type] || 0) + 1;
currentStatusColor = logEntry.type === 'ERROR' ? ('pink') : (logEntry.type === 'WARN' ? 'lightyellow' : '')
if (message.indexOf(gpsKeyWords) > -1) {
message = '📍 ' + message;
}
logEntryElem.innerHTML = '<div style="background: '+currentStatusColor+'">' +getClock(logEntry.date)+ ' ' +logEntry.type+ ' -> ' + message + '</div>';
}
logEntryContainer.appendChild(logEntryElem);
});
element.querySelector('.log-summary').innerHTML = '<span>'+JSON.stringify(counts)+'</span> <a href="#" onclick="this.parentNode.parentNode.querySelector(\'.log-entries\').style.display =\'block\'; return false; ">See logs</a>';
if (gpsMessage === 'NoData') {
element.querySelector('.gps').style.filter = 'grayscale(100%)';
}
return element;
}
const updateTimePast = (logEntryElem, newDate) => {
if (newDate && logEntryElem) {
const date = new Date(logEntryElem.getAttribute('data-date'));
const arrowElem = logEntryElem.querySelector('.arrow');
if (getNiceDate(date) !== getNiceDate(newDate)) {
arrowElem.innerHTML = '<span style="font-weight: bold; padding:25px 0 10px; display:block; font-size: 60%">' + getNiceDate(newDate) + '</span>';
} else {
const milliSeconds = newDate.getTime() - date.getTime();
const seconds = Math.round(milliSeconds / 1000);
const timePast = seconds > 60 ? (Math.floor(seconds/60) +'min '+ seconds%60 +'s') : seconds + 's'
arrowElem.querySelector('strong').innerText = timePast;
}
arrowElem.style.display = 'block';
}
}
const getClock = date => {
return date.toString().split(' ').filter((v,i) => i > 3 && i <5).join(' ');
}
const getNiceDate = date => {
return date.toString().split(' ').filter((v,i) => i < 3).join(' ') + ' '
}
window.renderLog = (someData) => {
let logSections = [];
let logEntryHtmlNode;
let nextLogSectionIndex;
const container = document.getElementById('container');
container.innerHTML = '';
parseLog(someData).filter(d => !!d).forEach(d => {
if (d.message.indexOf('App starting') > -1) {
nextLogSectionIndex = logSections.push(d) - 1;
logSections[nextLogSectionIndex].title = '💡 App starting';
} else if (d.message.indexOf('Antenna connected') > -1) {
nextLogSectionIndex = logSections.push(d) - 1;
logSections[nextLogSectionIndex].title = '📡 Antenna connected';
} else if (d.message.indexOf('Measuring started') > -1) {
nextLogSectionIndex = logSections.push(d) - 1;
logSections[nextLogSectionIndex].title = '▶️ Measuring started';
} else if (d.message.indexOf('MeasuringCmd: Stop measurement sent') > -1) {
nextLogSectionIndex = logSections.push(d) - 1;
logSections[nextLogSectionIndex].title = '⛔ Measuring stopped';
} else if (d.message.indexOf('Set connected=false, since lastPing') > -1) {
nextLogSectionIndex = logSections.push(d) - 1;
logSections[nextLogSectionIndex].title = '💥📡💥 Lost antenna connection';
} else {
if (nextLogSectionIndex === undefined) {
nextLogSectionIndex = logSections.push(d) - 1;
logSections[nextLogSectionIndex].title = 'Log started...';
} else {
logSections[nextLogSectionIndex].children.push(d);
}
}
});
logSections.forEach(logSection => {
if (logEntryHtmlNode) {
updateTimePast(logEntryHtmlNode, logSection.date);
}
try {
logEntryHtmlNode = renderLogSection(logSection, container);
} catch (err) {
console.error('Unable to render log section', err, logSection);
}
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment