read format
This commit is contained in:
75
index.html
75
index.html
@@ -31,7 +31,7 @@
|
|||||||
--text3: #555966;
|
--text3: #555966;
|
||||||
--accent: #4f8ef7;
|
--accent: #4f8ef7;
|
||||||
--accent-dim: #4f8ef720;
|
--accent-dim: #4f8ef720;
|
||||||
--trace: #818594;
|
--trace: #808080;
|
||||||
--debug: #555966;
|
--debug: #555966;
|
||||||
--info: #4f8ef7;
|
--info: #4f8ef7;
|
||||||
--warn: #f5a623;
|
--warn: #f5a623;
|
||||||
@@ -841,8 +841,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- Log parsing ----
|
// ---- Log parsing ----
|
||||||
function parseLogs(text) {
|
function parseLogs(text, filedate = null) {
|
||||||
const lines = text.split('\n').filter(l => l.trim());
|
const lines = text.split(/\r?\n/).filter(l => l.trim());
|
||||||
const logs = [];
|
const logs = [];
|
||||||
|
|
||||||
// Try JSON Lines
|
// Try JSON Lines
|
||||||
@@ -859,9 +859,12 @@ function parseLogs(text) {
|
|||||||
/^(\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+(DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL)\s+(.+)$/i,
|
/^(\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+(DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL)\s+(.+)$/i,
|
||||||
// INFO 2024-01-15 10:23:45 message
|
// INFO 2024-01-15 10:23:45 message
|
||||||
/^(DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL)\s+(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?)\s+(.+)$/i,
|
/^(DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL)\s+(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?)\s+(.+)$/i,
|
||||||
|
// 10:23:43.333 [INF] message
|
||||||
|
/^(\d{2}:\d{2}:\d{2}\.\d{3})\s\[(INF|WRN|ERR|CRT|DBG|TRC)\]\s(.*)$/
|
||||||
];
|
];
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
debugger
|
||||||
while (i < lines.length) {
|
while (i < lines.length) {
|
||||||
const line = lines[i].trim();
|
const line = lines[i].trim();
|
||||||
let matched = false;
|
let matched = false;
|
||||||
@@ -875,7 +878,17 @@ function parseLogs(text) {
|
|||||||
} else {
|
} else {
|
||||||
timeStr = g1; levelStr = g2.toUpperCase().replace('WARNING', 'WARN'); msg = g3;
|
timeStr = g1; levelStr = g2.toUpperCase().replace('WARNING', 'WARN'); msg = g3;
|
||||||
}
|
}
|
||||||
const time = new Date(timeStr);
|
levelStr = translateLogLevel(levelStr)
|
||||||
|
let time
|
||||||
|
if (filedate === null) {
|
||||||
|
time = new Date(timeStr)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const [hours, mins, secs, ms] = timeStr.split(/[:.]/).map(Number);
|
||||||
|
let temp_date = filedate.setHours(hours, mins, secs, ms)
|
||||||
|
time = new Date(filedate)
|
||||||
|
}
|
||||||
|
|
||||||
if (!isNaN(time)) {
|
if (!isNaN(time)) {
|
||||||
// Collect continuation lines (stack traces etc.)
|
// Collect continuation lines (stack traces etc.)
|
||||||
let exception = '';
|
let exception = '';
|
||||||
@@ -937,7 +950,7 @@ function parseLogs(text) {
|
|||||||
|
|
||||||
const buckets = Array.from({ length: BUCKETS }, (_, i) => ({
|
const buckets = Array.from({ length: BUCKETS }, (_, i) => ({
|
||||||
t: new Date(minT + i * bucketSize),
|
t: new Date(minT + i * bucketSize),
|
||||||
DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0, FATAL: 0, total: 0
|
TRACE: 0, DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0, FATAL: 0, total: 0
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (const log of logs) {
|
for (const log of logs) {
|
||||||
@@ -950,14 +963,14 @@ function parseLogs(text) {
|
|||||||
if (chart) chart.destroy();
|
if (chart) chart.destroy();
|
||||||
|
|
||||||
const colorMap = {
|
const colorMap = {
|
||||||
DEBUG: '#55596640', INFO: '#4f8ef760', WARN: '#f5a62370', ERROR: '#e8504a80', FATAL: '#c72b2b90'
|
TRACE: '#80808080', DEBUG: '#55596640', INFO: '#4f8ef760', WARN: '#f5a62370', ERROR: '#e8504a80', FATAL: '#c72b2b90'
|
||||||
};
|
};
|
||||||
|
|
||||||
chart = new Chart(canvas, {
|
chart = new Chart(canvas, {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
labels: buckets.map(b => b.t),
|
labels: buckets.map(b => b.t),
|
||||||
datasets: ['FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG'].map(level => ({
|
datasets: ['FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'].map(level => ({
|
||||||
label: level,
|
label: level,
|
||||||
data: buckets.map(b => b[level]),
|
data: buckets.map(b => b[level]),
|
||||||
backgroundColor: colorMap[level],
|
backgroundColor: colorMap[level],
|
||||||
@@ -1161,13 +1174,55 @@ function parseLogs(text) {
|
|||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = e => {
|
reader.onload = e => {
|
||||||
const text = e.target.result;
|
const text = e.target.result;
|
||||||
allLogs = parseLogs(text);
|
var date = parseDateFromFilename(file.name);
|
||||||
|
allLogs = parseLogs(text, date);
|
||||||
if (!allLogs.length) { allLogs = generateDemoLogs(); }
|
if (!allLogs.length) { allLogs = generateDemoLogs(); }
|
||||||
initView(file.name);
|
initView(file.name);
|
||||||
};
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDateFromFilename(filename) {
|
||||||
|
const formats = [
|
||||||
|
{ regex: /(\d{4})[-_](\d{2})[-_](\d{2})/, map: (m) => `${m[1]}-${m[2]}-${m[3]}` }, // YYYY-MM-DD
|
||||||
|
{ regex: /(\d{2})[-_](\d{2})[-_](\d{4})/, map: (m) => `${m[3]}-${m[2]}-${m[1]}` }, // DD-MM-YYYY
|
||||||
|
{ regex: /(\d{4})(\d{2})(\d{2})/, map: (m) => `${m[1]}-${m[2]}-${m[3]}` } // YYYYMMDD
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { regex, map } of formats) {
|
||||||
|
const match = filename.match(regex);
|
||||||
|
if (match) {
|
||||||
|
const isoString = map(match);
|
||||||
|
const date = new Date(isoString);
|
||||||
|
if (!isNaN(date.getTime())) return date;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateLogLevel(level) {
|
||||||
|
//DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0, FATAL: 0, total: 0
|
||||||
|
// Normalize input to handle lowercase or uppercase variations
|
||||||
|
switch (level.toLowerCase()) {
|
||||||
|
case 'trc':
|
||||||
|
return "TRACE";
|
||||||
|
case 'dbg':
|
||||||
|
return "DEBUG";
|
||||||
|
case 'inf':
|
||||||
|
return "INFO";
|
||||||
|
case 'wrn':
|
||||||
|
case 'warning': // Multiple cases can map to the same result
|
||||||
|
return "WARN";
|
||||||
|
case 'error':
|
||||||
|
return "ERROR";
|
||||||
|
case 'fatal':
|
||||||
|
case 'crt':
|
||||||
|
return "FATAL";
|
||||||
|
default:
|
||||||
|
return level; // Unknown level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadDemo() {
|
function loadDemo() {
|
||||||
allLogs = generateDemoLogs();
|
allLogs = generateDemoLogs();
|
||||||
initView('demo.log');
|
initView('demo.log');
|
||||||
@@ -1257,7 +1312,7 @@ function parseLogs(text) {
|
|||||||
const file = e.dataTransfer.files[0];
|
const file = e.dataTransfer.files[0];
|
||||||
if (file) loadFile(file);
|
if (file) loadFile(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load demo on start
|
// Load demo on start
|
||||||
loadDemo();
|
loadDemo();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user