Virtualized display of log files
A complete virtualized log display class for multiple log files, search, update etc. Can easily treat massive log files, as only the part of the logfile in view is actually rendered.
by adb014
HTML
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
<div class="container p-3 border">
<div class="row">
<div class="col-md-4">
<h5>Logs :</h5>
</div>
<div class="col-md-8 text-end">
<input type="button" class="btn btn-primary btn-sm" id="loghide" value="All logs">
<input type="search" class="input-lg rounded" id="logsearch" placeholder="Search">
</div>
</div>
<span id="logwind"></span>
</div>
CSS
.container {
margin-top: 20px;
margin-bottom: 20px;
}
JavaScript
// Based very loosely on https://stackoverflow.com/questions/17626717/large-list-rendering-in-javascript
class DisplayLogs {
constructor(id, logs, hidescrollbar = false, emphasis = "", filter = "", render = "", openatend = false) {
const temp = document.getElementById(id);
this.view = null;
this.logs = (typeof (logs) === "string" ? [logs] : logs);
this.emphasis = emphasis;
this.filter = filter;
this.render = render;
this.tab = 0;
this.lastScrollTop = 0;
this.hidescrollbar = hidescrollbar;
this.highlight = { tab: -1, line: -1 };
this.nitems = this.numberOfItems();
this.openatend = openatend;
temp.textContent = ""; // Clear existing content
if (this.logs.length === 1) {
let el = temp.appendChild(document.createElement("div"));
el.id = "logpane";
el.setAttribute("style", "height: 500px; position: relative; overflow-x: auto; overflow-y: auto;");
el.appendChild(document.createElement("div")).id = "heightForcer";
el = el.appendChild(document.createElement("div"));
el.id = "log0";
el.className = "container tab-pane active";
} else {
let el = temp.appendChild(document.createElement("ul"));
el.className = "nav nav-tabs";
el.id = "logs";
el.setAttribute("role", "tablist");
for (let i = 0; i < this.logs.length; i += 1) {
const li = el.appendChild(document.createElement("li"));
li.className = "nav-item";
const link = li.appendChild(document.createElement("a"));
link.className = "nav-link" + (i === 0 ? " active" : "");
link.id = "navlog" + i;
link.setAttribute("data-bs-toggle", "tab");
link.href = "#log" + i;
link.textContent = i;
}
el =...