mirror of
https://github.com/unraid/webgui.git
synced 2025-12-31 14:40:36 -06:00
- Replaced existing resize functions with fillAvailableHeight calls in multiple pages for consistent dynamic height adjustments. - Updated PageMap.page, Processes.page, Syslog.page, Vars.page, DockerContainers.page, VMMachines.page to utilize fillAvailableHeight with appropriate parameters. - Wrapped relevant elements in 'js-fill-available-height' and 'js-actions' divs for improved structure and layout clarity.
229 lines
7.5 KiB
Plaintext
229 lines
7.5 KiB
Plaintext
Menu="UNRAID-OS"
|
|
Title="System Log"
|
|
Icon="icon-log"
|
|
Tag="list"
|
|
---
|
|
<?php
|
|
/* Copyright 2005-2023, Lime Technology
|
|
* Copyright 2012-2023, Bergware International.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*/
|
|
?>
|
|
<?php
|
|
$zip = htmlspecialchars(str_replace(' ', '_', strtolower($var['NAME'])));
|
|
$log = '/var/log/syslog';
|
|
$prev = '/boot/logs/syslog-previous';
|
|
$cfg = '/boot/config/rsyslog.cfg';
|
|
$max = 5000;
|
|
$select = [];
|
|
$logs = [];
|
|
if (file_exists($cfg)) {
|
|
$syslog = parse_ini_file($cfg);
|
|
if (!empty($syslog['local_server']) && !empty($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log', GLOB_NOSORT)) {
|
|
natsort($logs);
|
|
}
|
|
}
|
|
if (file_exists($prev)) {
|
|
// add syslog-previous to front of logs array
|
|
array_unshift($logs, $prev);
|
|
}
|
|
if (count($logs)) {
|
|
// add syslog to front of logs array
|
|
array_unshift($logs, $log);
|
|
$select[] = "<select onchange='showLog(this.value)'>";
|
|
foreach ($logs as $file) {
|
|
$select[] = mk_option(1, $file, basename($file));
|
|
}
|
|
$select[] = "</select>";
|
|
}
|
|
$select = implode($select);
|
|
?>
|
|
<script>
|
|
var logfile = "<?=$log?>";
|
|
|
|
function zipfile(){
|
|
var d = new Date();
|
|
return "<?=$zip?>-"+logfile.split('/').reverse()[0].replace('.log','')+'-'+d.toISOString().substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
|
|
}
|
|
function cleanUp(file) {
|
|
if (document.hasFocus()) {
|
|
$('input#download').val("_(Download)_").prop('disabled',false);
|
|
$.post('/webGui/include/Download.php',{cmd:'delete',file:file});
|
|
} else {
|
|
setTimeout(function(){cleanUp(file);},2000);
|
|
}
|
|
}
|
|
function syslog(file) {
|
|
$('input#download').val("_(Downloading)_...").prop('disabled',true);
|
|
$.post('/webGui/include/Download.php',{cmd:'save',source:logfile,file:file},function(zip) {
|
|
location = zip;
|
|
setTimeout(function(){cleanUp(file);},4000);
|
|
});
|
|
}
|
|
function highlight(checked,line) {
|
|
var o = checked ? '-' : '';
|
|
var n = ($('span.text').css('display')=='none' && !checked) ? 'none' : '';
|
|
switch (line) {
|
|
case 'E': $('span.'+o+'error').css('display',n); $('span.error'+o).toggleClass('error -error error-'); break;
|
|
case 'W': $('span.'+o+'warn').css('display',n); $('span.warn'+o).toggleClass('warn -warn warn-'); break;
|
|
case 'S': $('span.'+o+'system').css('display',n); $('span.system'+o).toggleClass('system -system system-'); break;
|
|
case 'A': $('span.'+o+'array').css('display',n); $('span.array'+o).toggleClass('array -array array-'); break;
|
|
case 'L': $('span.'+o+'login').css('display',n); $('span.login'+o).toggleClass('login -login login-'); break;
|
|
case 'N': $('span.text,span[class^="-"]').css('display',checked ? 'none':''); break;
|
|
}
|
|
$('span.label').show();
|
|
}
|
|
function toggle(checked) {
|
|
highlight(checked,'E');
|
|
highlight(checked,'W');
|
|
highlight(checked,'S');
|
|
highlight(checked,'A');
|
|
highlight(checked,'L');
|
|
$('span.label input[type=checkbox]').not('.ctrl').prop('checked',checked);
|
|
}
|
|
|
|
function showLog(log) {
|
|
logfile = log;
|
|
$('span.label input[type=checkbox]').prop('checked', true);
|
|
$('span.label').each(function() {
|
|
var type = $(this).attr('class').replace('label', '').replace(/-/g, '');
|
|
$(this).removeClass().addClass(type + ' label');
|
|
});
|
|
timers.syslog = setTimeout(function() { $('div.spinner.fixed').show('slow'); }, 500);
|
|
|
|
$.post('/webGui/include/Syslog.php', { log: log, max: $('#max').val() || <?=$max?> }, function(data) {
|
|
clearTimeout(timers.syslog);
|
|
let logContainer = document.querySelector("pre.up");
|
|
if (!logContainer) return; // Safety check
|
|
|
|
$('pre.up').html(data);
|
|
$('div.spinner.fixed').hide('slow');
|
|
|
|
/* Ensuring reliable scroll behavior on Chrome */
|
|
function scrollToBottom() {
|
|
logContainer.style.scrollBehavior = 'smooth';
|
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|
}
|
|
|
|
/* 1. Delay with setTimeout */
|
|
setTimeout(scrollToBottom, 50);
|
|
|
|
/* 2. Force Chrome to reflow/repaint */
|
|
logContainer.style.display = "none";
|
|
setTimeout(function() {
|
|
logContainer.style.display = "block";
|
|
scrollToBottom();
|
|
}, 10);
|
|
|
|
/* 3. Use requestAnimationFrame */
|
|
requestAnimationFrame(scrollToBottom);
|
|
|
|
/* 4. Repeat scroll a few times as a backup (Fixes rare cases in Chrome) */
|
|
setTimeout(scrollToBottom, 100);
|
|
setTimeout(scrollToBottom, 500);
|
|
});
|
|
}
|
|
|
|
$(function() {
|
|
$('input#max').on('keydown',function(e) {
|
|
if (e.keyCode === 13) {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
showLog(logfile);
|
|
}
|
|
});
|
|
showLog(logfile);
|
|
|
|
<?if (_var($display,'resize')):?>
|
|
fillAvailableHeight({
|
|
targetElementSelector: '.js-fill-available-height',
|
|
elementSelectorsForHeight: [
|
|
'.js-syslog-controls',
|
|
'.js-syslog-actions',
|
|
],
|
|
});
|
|
<?endif;?>
|
|
});
|
|
</script>
|
|
|
|
<div class="js-syslog-controls syslog-controls">
|
|
<div class="flex flex-row justify-between items-center gap-4 flex-wrap w-full">
|
|
<div class="flex flex-row items-center gap-4">
|
|
<div class="lite label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<span class="flex-shrink-0">_(Log size)_:</span>
|
|
<input type="number" id="max" value="" placeholder="<?=$max?>">
|
|
</label>
|
|
</div>
|
|
|
|
<?if (!empty($select)):?>
|
|
<div class="lite label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<span class="flex-shrink-0">_(Log file)_:</span>
|
|
<?= $select ?>
|
|
</label>
|
|
</div>
|
|
<?endif;?>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap flex-row items-center gap-3">
|
|
<div class="lite label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<input type="checkbox" class="ctrl" onclick="highlight(!this.checked, 'N')" checked>
|
|
_(Text)_
|
|
</label>
|
|
</div>
|
|
<span class="error label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<input type="checkbox" onclick="highlight(this.checked, 'E')" checked>
|
|
_(Error)_
|
|
</label>
|
|
</span>
|
|
<span class="warn label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<input type="checkbox" onclick="highlight(this.checked, 'W')" checked>
|
|
_(Warning)_
|
|
</label>
|
|
</span>
|
|
<span class="system label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<input type="checkbox" onclick="highlight(this.checked, 'S')" checked>
|
|
_(System)_
|
|
</label>
|
|
</span>
|
|
<span class="array label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<input type="checkbox" onclick="highlight(this.checked, 'A')" checked>
|
|
_(Array)_
|
|
</label>
|
|
</span>
|
|
<span class="login label">
|
|
<label class="flex flex-row items-center gap-2">
|
|
<input type="checkbox" onclick="highlight(this.checked, 'L')" checked>
|
|
_(Login)_
|
|
</label>
|
|
</span>
|
|
<span class="lite label">
|
|
<label class="flex items-center gap-2">
|
|
<input type="checkbox" class="ctrl" onclick="toggle(this.checked)" checked>
|
|
_(Toggle All)_
|
|
</label>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<pre class="js-fill-available-height up"></pre>
|
|
|
|
<div class="js-syslog-actions flex flex-row items-center gap-2">
|
|
<input type="button" id="download" value="_(Download)_" onclick="syslog(zipfile())">
|
|
<input type="button" value="_(Refresh)_" onclick="showLog(logfile)">
|
|
<input type="button" value="_(Done)_" onclick="done()">
|
|
</div>
|