diff --git a/Main_LogStatus_Content.asp b/Main_LogStatus_Content.asp index 656855a..74b45b5 100644 --- a/Main_LogStatus_Content.asp +++ b/Main_LogStatus_Content.asp @@ -25,15 +25,16 @@ p{font-weight:bolder}thead.collapsible-jquery{color:#fff;padding:0;width:100%;bo @@ -185,14 +186,18 @@ var clockinterval,bootinterval,timeoutsenabled=!0;function showclock(){JS_timeOb
- +       - + - + +      + +      +
@@ -200,13 +205,17 @@ var clockinterval,bootinterval,timeoutsenabled=!0;function showclock(){JS_timeOb
 
- +
System Messages (click to show/hide)
System Messages (click to show/hide)
- + +      + +      +
diff --git a/Main_LogStatus_Content.js b/Main_LogStatus_Content.js index fe477fd..dd98480 100644 --- a/Main_LogStatus_Content.js +++ b/Main_LogStatus_Content.js @@ -1,7 +1,15 @@ +/**----------------------------**/ +/** Last Modified: 2025-Nov-30 **/ +/**----------------------------**/ + var timeoutsenabled = true; var clockinterval; var bootinterval; +let logFileInfoListInterval = null; +let isInitialLoading = false; + +var logRotate_InfoListArray = []; function showclock() { @@ -21,7 +29,8 @@ function showclock() document.getElementById('log_messages').style.width = '99%'; } -function showbootTime(){ +function showbootTime() +{ Days = Math.floor(boottime / (60*60*24)); Hours = Math.floor((boottime / 3600) % 24); Minutes = Math.floor(boottime % 3600 / 60); @@ -33,25 +42,30 @@ function showbootTime(){ boottime += 1; } -function capitalise(string){ +function capitalise(string) +{ return string.charAt(0).toUpperCase()+string.slice(1); } -function GetCookie(cookiename,returntype){ - if(cookie.get('uiscribe_'+cookiename) != null){ +function GetCookie(cookiename,returntype) +{ + if (cookie.get('uiscribe_'+cookiename) != null) + { return cookie.get('uiscribe_'+cookiename); } - else{ - if(returntype == 'string'){ + else + { + if (returntype == 'string'){ return ''; } - else if(returntype == 'number'){ + else if (returntype == 'number'){ return 0; } } } -function SetCookie(cookiename,cookievalue){ +function SetCookie(cookiename,cookievalue) +{ cookie.set('uiscribe_'+cookiename,cookievalue,10*365); } @@ -67,30 +81,41 @@ $.fn.serializeObject = function(){ return o; }; -function SetCurrentPage(){ +function SetCurrentPage() +{ document.config_form.next_page.value = window.location.pathname.substring(1); document.config_form.current_page.value = window.location.pathname.substring(1); } -function initial(){ +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Nov-28] **/ +/**----------------------------------------**/ +function initial() +{ + isInitialLoading = true; SetCurrentPage(); LoadCustomSettings(); ScriptUpdateLayout(); + GetLogRotateInfoList(); + setTimeout(GetLogFileInfoList, 7000); show_menu(); showclock(); showbootTime(); clockinterval = setInterval(showclock,1000); bootinterval = setInterval(showbootTime,1000); showDST(); - get_conf_file(); + GetLogsUserTable(); + logFileInfoListInterval = setInterval(GetLogFileInfoList,180000); } -function ScriptUpdateLayout(){ +function ScriptUpdateLayout() +{ var localver = GetVersionNumber('local'); var serverver = GetVersionNumber('server'); $('#uiscribe_version_local').text(localver); - if(localver != serverver && serverver != 'N/A'){ + if (localver != serverver && serverver != 'N/A') + { $('#uiscribe_version_server').text('Updated version available: '+serverver); showhide('btnChkUpdate',false); showhide('uiscribe_version_server',true); @@ -98,133 +123,175 @@ function ScriptUpdateLayout(){ } } -function reload(){ +function reload() +{ location.reload(true); } -function get_logfile(filename){ - var filenamesafe = filename.replace('.log',''); +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Nov-30] **/ +/**----------------------------------------**/ +function get_logfile(fileName) +{ + let fileNameShort = fileName.replace('.log',''); + $.ajax({ - url: '/ext/uiScribe/'+filename+'.htm', + url: '/ext/uiScribe/'+fileName+'.htm', dataType: 'text', timeout: 3000, - error: function(xhr){ - if(timeoutsenabled == true && window['timeoutenabled_'+filenamesafe] == true){ - window['timeout_'+filenamesafe] = setTimeout(get_logfile,2000,filename); + error: function(xhr) + { + if (timeoutsenabled == true && window['timeoutenabled_'+fileNameShort] == true) + { + window['timeout_'+fileNameShort] = setTimeout(get_logfile,2000,fileName); } }, - success: function(data){ - if(timeoutsenabled == true && window['timeoutenabled_'+filenamesafe] == true){ - if(filename != 'messages'){ - if(data.length > 0){ - document.getElementById('log_'+filename.substring(0,filename.indexOf('.'))).innerHTML = data; - if(document.getElementById('auto_scroll').checked){ - $('#log_'+filename.substring(0,filename.indexOf('.'))).scrollTop(9999999); + success: function(data) + { + let logFileDataElem = document.getElementById('log_'+fileNameShort); + + if (timeoutsenabled == true && window['timeoutenabled_'+fileNameShort] == true) + { + if (data.length === 0) + { + logFileDataElem.innerHTML = '*** The log file is either empty or does not yet exist ***'; + } + if (fileName != 'messages') + { + if (data.length > 0) + { + logFileDataElem.innerHTML = data; + if (document.getElementById('auto_scroll').checked) + { + $('#log_'+fileNameShort).scrollTop(9999999); } } } - else{ - if(data.length > 0){ - document.getElementById('log_'+filename).innerHTML = data; - if(document.getElementById('auto_scroll').checked){ - $('#log_'+filename).scrollTop(9999999); + else + { + if (data.length > 0) + { + logFileDataElem.innerHTML = data; + if (document.getElementById('auto_scroll').checked) + { + $('#log_'+fileName).scrollTop(9999999); } } } - window['timeout_'+filenamesafe] = setTimeout(get_logfile,3000,filename); + window['timeout_'+fileNameShort] = setTimeout(get_logfile,3000,fileName); } } }); } -function get_conf_file(){ +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Nov-28] **/ +/**----------------------------------------**/ +function GetLogsUserTable() +{ $.ajax({ - url: '/ext/uiScribe/logs.htm', + url: '/ext/uiScribe/logs_user.htm', timeout: 2000, dataType: 'text', - error: function(xhr){ - setTimeout(get_conf_file,1000); + error: function(xhr) + { + setTimeout(GetLogsUserTable,2000); }, - success: function(data){ - var logs=data.split('\n'); - logs.sort(); - logs=logs.filter(Boolean); - + success: function(data) + { + var logFiles = data.split('\n'); + logFiles.sort(); + logFiles = logFiles.filter(Boolean); + var logconfigtablehtml='Logs to display in WebUI'; - - for(var i = 0; i < logs.length; i++){ - var filename=logs[i].substring(logs[i].lastIndexOf('/')+1); - if(filename.indexOf('#') != -1){ - filename = filename.substring(0,filename.indexOf('#')).replace('.log','').replace('.htm','').trim(); - logconfigtablehtml += ''; - logconfigtablehtml += ''; + + for (var i = 0; i < logFiles.length; i++) + { + var fileName = logFiles[i].substring(logFiles[i].lastIndexOf('/')+1); + if (fileName.indexOf('#') != -1) + { + fileName = fileName.substring(0,fileName.indexOf('#')).replace('.log','').replace('.htm','').trim(); + logconfigtablehtml += ''; + logconfigtablehtml += ''; } - else{ - filename = filename.replace(".log","").replace(".htm","").trim(); - logconfigtablehtml += ''; - logconfigtablehtml += ''; + else + { + fileName = fileName.replace(".log","").replace(".htm","").trim(); + logconfigtablehtml += ''; + logconfigtablehtml += ''; } - if((i+1) % 4 == 0){ + if ((i+1) % 4 == 0) + { logconfigtablehtml += '
'; } } - + logconfigtablehtml += ''; logconfigtablehtml += ''; logconfigtablehtml += ''; logconfigtablehtml += ''; logconfigtablehtml += ''; $('#table_config').append(logconfigtablehtml); - logs.reverse(); - - for(var i = 0; i < logs.length; i++){ - var commentstart=logs[i].indexOf('#'); - if(commentstart != -1){ - continue - } - filename=logs[i].substring(logs[i].lastIndexOf('/')+1); - $('#table_messages').after(BuildLogTable(filename)); + logFiles.reverse(); + + for (var i = 0; i < logFiles.length; i++) + { + var commentstart = logFiles[i].indexOf('#'); + if (commentstart != -1) { continue; } + fileName = logFiles[i].substring(logFiles[i].lastIndexOf('/')+1); + $('#table_messages').after(BuildLogTable(fileName)); } - + + let logFileInfoStr = GetLogFileSizeInfo('messages'); + document.getElementById('fileTitle_messages').innerHTML = logFileInfoStr + '   (click to show/hide)' AddEventHandlers(); + isInitialLoading = false; } }); } -function DownloadAllLogFile(){ +function DownloadAllLogFiles() +{ $('.btndownload').each(function(index){$(this).trigger('click');}); } -function DownloadLogFile(btnlog){ - $(btnlog).prop('disabled',true); - $(btnlog).addClass('btndisabled'); +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Nov-28] **/ +/**----------------------------------------**/ +function DownloadLogFile(btnLog) +{ + $(btnLog).prop('disabled',true); + $(btnLog).addClass('btndisabled'); var filepath = ''; - if(btnlog.name == 'btnmessages'){ + if (btnLog.name === 'btnDownload_messages') + { filepath='/ext/uiScribe/messages.htm'; } - else{ - filepath='/ext/uiScribe/'+btnlog.name.replace('btn','')+'.log.htm'; + else + { + filepath='/ext/uiScribe/'+btnLog.name.replace('btnDownload_','')+'.log.htm'; } fetch(filepath).then(resp => resp.blob()).then(blob => { const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.style.display = 'none'; a.href = url; - a.download = btnlog.name.replace('btn','')+'.log'; + a.download = btnLog.name.replace('btnDownload_','')+'.log'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); - $(btnlog).prop('disabled',false); - $(btnlog).removeClass('btndisabled'); + $(btnLog).prop('disabled',false); + $(btnLog).removeClass('btndisabled'); }) .catch(() => { console.log('File download failed!'); - $(btnlog).prop('disabled',false); - $(btnlog).removeClass('btndisabled'); + $(btnLog).prop('disabled',false); + $(btnLog).removeClass('btndisabled'); }); } -function update_status(){ +function update_status() +{ $.ajax({ url: '/ext/uiScribe/detect_update.js', dataType: 'script', @@ -232,19 +299,24 @@ function update_status(){ error: function(xhr){ setTimeout(update_status,1000); }, - success: function(){ - if(updatestatus == 'InProgress'){ + success: function() + { + if (updatestatus == 'InProgress') + { setTimeout(update_status,1000); } - else{ + else + { document.getElementById('imgChkUpdate').style.display = 'none'; showhide('uiscribe_version_server',true); - if(updatestatus != 'None'){ + if (updatestatus != 'None') + { $('#uiscribe_version_server').text('Updated version available: '+updatestatus); showhide('btnChkUpdate',false); showhide('btnDoUpdate',true); } - else{ + else + { $('#uiscribe_version_server').text('No update available'); showhide('btnChkUpdate',true); showhide('btnDoUpdate',false); @@ -254,7 +326,103 @@ function update_status(){ }); } -function CheckUpdate(){ +var logRotateStatus = ''; + +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function Update_LogRotate_Status(logObj) +{ + $.ajax({ + url: '/ext/uiScribe/logRotateStatus.js', + dataType: 'script', + timeout: 3000, + error: function(xhr){ + setTimeout(Update_LogRotate_Status,1000,logObj); + }, + success: function() + { + let theStatus = ''; + if (logRotateStatus === 'InProgress') + { + setTimeout(Update_LogRotate_Status,2000,logObj); + } + else if (logRotateStatus === 'ERROR') + { + theStatus = logRotateStatus; + } + else if (logRotateStatus === 'DONE') + { + theStatus = logRotateStatus; + } + $(logObj).prop('disabled',false); + $(logObj).removeClass('btndisabled'); + document.getElementById(logObj.id).style.display = ''; + document.getElementById('imgChkUpdate').style.display = 'none'; + } + }); +} + +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function RotateLogFile(logObj, logFileName) +{ + if (typeof logFileInfoListInterval !== 'undefined' && logFileInfoListInterval !== null) + { + clearInterval(logFileInfoListInterval); + logFileInfoListInterval = null; + } + + $(logObj).prop('disabled',true); + $(logObj).addClass('btndisabled'); + + let waitValue = 30; + if (logFileName === 'ALL') + { + if (logRotate_InfoListArray.length > 5) + { waitValue = 60; } + else + { waitValue = 45; } + } + let actionScriptVal = 'start_uiScribeRotateLog_' + logFileName; + document.config_form.action_script.value = actionScriptVal; + document.config_form.action_wait.value = waitValue; + showLoading(); + document.config_form.submit(); +} + +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function ClearLogFile(logObj, logFileName) +{ + if (typeof logFileInfoListInterval !== 'undefined' && logFileInfoListInterval !== null) + { + clearInterval(logFileInfoListInterval); + logFileInfoListInterval = null; + } + + $(logObj).prop('disabled',true); + $(logObj).addClass('btndisabled'); + + let waitValue = 30; + if (logFileName === 'ALL') + { + if (logRotate_InfoListArray.length > 5) + { waitValue = 60; } + else + { waitValue = 45; } + } + let actionScriptVal = 'start_uiScribeClearLog_' + logFileName; + document.config_form.action_script.value = actionScriptVal; + document.config_form.action_wait.value = waitValue; + showLoading(); + document.config_form.submit(); +} + +function CheckUpdate() +{ showhide('btnChkUpdate',false); document.formScriptActions.action_script.value='start_uiScribecheckupdate'; document.formScriptActions.submit(); @@ -262,14 +430,25 @@ function CheckUpdate(){ setTimeout(update_status,2000); } -function DoUpdate(){ +function DoUpdate() +{ document.config_form.action_script.value = 'start_uiScribedoupdate'; document.config_form.action_wait.value = 10; showLoading(); document.config_form.submit(); } -function SaveConfig(){ +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Nov-28] **/ +/**----------------------------------------**/ +function SaveConfig() +{ + if (typeof logFileInfoListInterval !== 'undefined' && logFileInfoListInterval !== null) + { + clearInterval(logFileInfoListInterval); + logFileInfoListInterval = null; + } + document.getElementById('amng_custom').value = JSON.stringify($('config_form').serializeObject()); document.config_form.action_script.value = 'start_uiScribeconfig'; document.config_form.action_wait.value = 5; @@ -277,16 +456,17 @@ function SaveConfig(){ document.config_form.submit(); } -function GetVersionNumber(versiontype){ +function GetVersionNumber(versiontype) +{ var versionprop; - if(versiontype == 'local'){ + if (versiontype == 'local'){ versionprop = custom_settings.uiscribe_version_local; } - else if(versiontype == 'server'){ + else if (versiontype == 'server'){ versionprop = custom_settings.uiscribe_version_server; } - if(typeof versionprop == 'undefined' || versionprop == null){ + if (typeof versionprop == 'undefined' || versionprop == null){ return 'N/A'; } else{ @@ -294,34 +474,155 @@ function GetVersionNumber(versiontype){ } } -function BuildLogTable(name){ +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function GetLogRotateInfoList() +{ + $.ajax({ + url: '/ext/uiScribe/logRotateInfoList.js', + dataType: 'script', + timeout: 1000, + error: function(xhr){ + setTimeout(GetLogRotateInfoList, 1000); + }, + success: function() + { + if (logRotate_InfoListArray.length === 0) + { return false; } + if (isInitialLoading) { return true; } + SetLogFileSizeInfo(); + } + }); +} + +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function GetLogFileInfoList() +{ + document.formScriptActions.action_script.value='start_uiScribeLogFileInfoList'; + document.formScriptActions.submit(); + setTimeout(GetLogRotateInfoList,3000); +} + +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function SetLogFileSizeInfo() +{ + $.ajax({ + url: '/ext/uiScribe/logs_user.htm', + timeout: 2000, + dataType: 'text', + error: function(xhr) + { + setTimeout(SetLogFileSizeInfo,2000); + }, + success: function(data) + { + let logFileName, fileNameShort, logFileTitleElem, logFileInfoStr; + let logFiles = data.split('\n'); + logFiles.sort(); + logFiles = logFiles.filter(Boolean); + + for (var indx = 0; indx < logFiles.length; indx++) + { + var commentstart = logFiles[indx].indexOf('#'); + if (commentstart != -1) { continue; } + logFileName = logFiles[indx].substring(logFiles[indx].lastIndexOf('/')+1); + fileNameShort = logFileName.replace('.log',''); + + logFileTitleElem = document.getElementById('fileTitle_' + fileNameShort); + if (typeof logFileTitleElem !== 'undefined' && logFileTitleElem !== null) + { + logFileInfoStr = GetLogFileSizeInfo(logFileName); + logFileTitleElem.innerHTML = logFileInfoStr + '   (click to show/hide)' + } + } + + logFileTitleElem = document.getElementById('fileTitle_messages'); + if (typeof logFileTitleElem !== 'undefined' && logFileTitleElem !== null) + { + logFileInfoStr = GetLogFileSizeInfo('messages'); + logFileTitleElem.innerHTML = logFileInfoStr + '   (click to show/hide)' + } + } + }); +} + +/**-------------------------------------**/ +/** Added by Martinski W. [2025-Nov-28] **/ +/**-------------------------------------**/ +function GetLogFileSizeInfo(theFileName) +{ + let logFilePath, logFileSize, logFileName, logFileInfoStr; + let fileSizeOK = false; + + for (var indx = 0; indx < logRotate_InfoListArray.length; indx++) + { + logFilePath = logRotate_InfoListArray[indx].LOG_PATH0; + logFileSize = logRotate_InfoListArray[indx].LOG_SIZE0; + logFileName = logFilePath.replace('/opt/var/log/',''); + if (logFileName === theFileName) + { fileSizeOK = true; break; } + } + + if (logFileSize === '' || !fileSizeOK) + { logFileInfoStr = theFileName; } + else + { logFileInfoStr = theFileName + ' [' + logFileSize + ']'; } + + return logFileInfoStr; +} + +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Nov-28] **/ +/**----------------------------------------**/ +function BuildLogTable(logFileName) +{ + let logFileInfoStr = GetLogFileSizeInfo(logFileName); + let fileNameShort = logFileName.substring(0,logFileName.indexOf('.')); + var loghtml = '
 
'; - loghtml += ''; - loghtml += ''; + loghtml += '
'+name+' (click to show/hide)
'; + loghtml += ''; + loghtml += ''; + loghtml += ''; loghtml += '
'+logFileInfoStr+'   (click to show/hide)
'; - loghtml += ''; + loghtml += ''; loghtml += '
'; - loghtml += ''; + loghtml += ''; + loghtml += '     '; + loghtml += ''; + loghtml += '     '; + loghtml += ''; + loghtml += '
'; + return loghtml; } -function AddEventHandlers(){ +function AddEventHandlers() +{ $('.collapsible-jquery').off('click').on('click',function(){ var filename = $(this).prop('id').replace('thead_',''); - if(filename != 'messages'){ + if (filename != 'messages') + { filename += '.log'; } - var filenamesafe = filename.replace('.log',''); - if($(this).siblings().is(':hidden') == true){ - window['timeoutenabled_'+filenamesafe] = true; + var fileNameShort = filename.replace('.log',''); + if ($(this).siblings().is(':hidden') == true) + { + window['timeoutenabled_'+fileNameShort] = true; get_logfile(filename); } - else{ - clearTimeout(window['timeout_'+filenamesafe]); - window['timeoutenabled_'+filenamesafe] = false; + else + { + clearTimeout(window['timeout_'+fileNameShort]); + window['timeoutenabled_'+fileNameShort] = false; } $(this).siblings().toggle('fast'); }); @@ -332,58 +633,71 @@ function AddEventHandlers(){ $('.collapsible-jquery-config').off('click').on('click',function(){ $(this).siblings().toggle('fast',function(){ - if($(this).css('display') == 'none'){ + if ($(this).css('display') == 'none') + { SetCookie($(this).siblings()[0].id,'collapsed'); } - else{ + else + { SetCookie($(this).siblings()[0].id,'expanded'); } }) }); $('.collapsible-jquery-config').each(function(index,element){ - if(GetCookie($(this)[0].id,'string') == 'collapsed'){ + if (GetCookie($(this)[0].id,'string') == 'collapsed') + { $(this).siblings().toggle(false); } - else{ + else + { $(this).siblings().toggle(true); } }); } -function ToggleRefresh(){ - if($('#auto_refresh').prop('checked') == true){ +function ToggleRefresh() +{ + if ($('#auto_refresh').prop('checked') == true) + { $('#auto_scroll').prop('disabled',false) - timeoutsenabled=true; + timeoutsenabled = true; $('.collapsible-jquery').each(function(index,element){ var filename = $(this).prop('id').replace('thead_',''); - if(filename != 'messages'){ + if (filename != 'messages') + { filename += '.log'; } - if($(this).siblings().is(':hidden') == false){ + if ($(this).siblings().is(':hidden') == false) + { get_logfile(filename); } }); } - else{ + else + { $('#auto_scroll').prop('disabled',true) - timeoutsenabled=false; + timeoutsenabled = false; } } -function ResizeAll(action){ +function ResizeAll(action) +{ $('.collapsible-jquery').each(function(index,element){ - if(action == 'show'){ + if (action == 'show') + { $(this).siblings().toggle(true); var filename = $(this).prop('id').replace('thead_',''); window['timeoutenabled_'+filename] = true; - if(filename != 'messages'){ + if (filename != 'messages') + { filename += '.log'; } get_logfile(filename); } - else{ + else + { $(this).siblings().toggle(false); var filename = $(this).prop('id').replace('thead_',''); window['timeoutenabled_'+filename] = false; diff --git a/README.md b/README.md index 7192b2d..258f581 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # uiScribe ## v1.4.10 -### Updated on 2025-Nov-20 +### Updated on 2025-Nov-30 ## About uiScribe updates the System Log page to show log files created by Scribe (syslog-ng). Requires [**Scribe**](https://github.com/cynicastic/scribe) diff --git a/uiScribe.sh b/uiScribe.sh index 398b266..ad049a5 100644 --- a/uiScribe.sh +++ b/uiScribe.sh @@ -13,7 +13,7 @@ ## Forked from https://github.com/jackyaz/uiScribe ## ## ## ######################################################## -# Last Modified: 2025-Nov-16 +# Last Modified: 2025-Nov-30 #------------------------------------------------------- ########### Shellcheck directives ########## @@ -30,15 +30,15 @@ ### Start of script variables ### readonly SCRIPT_NAME="uiScribe" readonly SCRIPT_VERSION="v1.4.10" -readonly SCRIPT_VERSTAG="25111620" +readonly SCRIPT_VERSTAG="25113022" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" -readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME.d" +readonly SCRIPT_DIR="/jffs/addons/${SCRIPT_NAME}.d" readonly SCRIPT_PAGE_DIR="$(readlink -f /www/user)" -readonly SCRIPT_WEB_DIR="$SCRIPT_PAGE_DIR/$SCRIPT_NAME" +readonly SCRIPT_WEB_DIR="${SCRIPT_PAGE_DIR}/$SCRIPT_NAME" readonly SHARED_DIR="/jffs/addons/shared-jy" readonly SHARED_REPO="https://raw.githubusercontent.com/AMTM-OSR/shared-jy/master" -readonly SHARED_WEB_DIR="$SCRIPT_PAGE_DIR/shared-jy" +readonly SHARED_WEB_DIR="${SCRIPT_PAGE_DIR}/shared-jy" [ -z "$(nvram get odmpid)" ] && ROUTER_MODEL="$(nvram get productid)" || ROUTER_MODEL="$(nvram get odmpid)" ##-------------------------------------## @@ -50,6 +50,27 @@ readonly branchxStr_TAG="[Branch: $SCRIPT_BRANCH]" readonly versionDev_TAG="${SCRIPT_VERSION}_${SCRIPT_VERSTAG}" readonly versionMod_TAG="$SCRIPT_VERSION on $ROUTER_MODEL" +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +readonly oneKByte=1024 +readonly oneMByte=1048576 +readonly oneGByte=1073741824 +readonly optTempDir="/opt/tmp" +readonly optVarLogDir="/opt/var/log" +readonly logRotateStr="logrotate" +readonly logRotateCmd="/opt/sbin/$logRotateStr" +readonly logRotateDir="/opt/etc/${logRotateStr}.d" +readonly logRotateTemp="${optTempDir}/${logRotateStr}.temp" +readonly logRotateDaily="${optTempDir}/${logRotateStr}.daily" +readonly logRotateOutput="${optTempDir}/${logRotateStr}.out" +readonly logRotateConfig="/opt/etc/${logRotateStr}.conf" +readonly logRotateStatusT="${optTempDir}/${logRotateStr}.status" +readonly logRotateStatusJS="${SCRIPT_WEB_DIR}/logRotateStatus.js" +readonly logRotateInfoListJS="${SCRIPT_DIR}/logRotateInfoList.js" +readonly logClearStatusT="${optTempDir}/${logRotateStr}Clear.status" +readonly logClearStatusJS="${SCRIPT_WEB_DIR}/logClearStatus.js" + ### End of script variables ### ### Start of output format variables ### @@ -344,6 +365,9 @@ Validate_Number() fi } +##----------------------------------------## +## Modified by Martinski W. [2025-Nov-28] ## +##----------------------------------------## Create_Dirs() { if [ ! -d "$SCRIPT_DIR" ]; then @@ -357,10 +381,18 @@ Create_Dirs() if [ ! -d "$SCRIPT_WEB_DIR" ]; then mkdir -p "$SCRIPT_WEB_DIR" fi + + if [ ! -d "$optTempDir" ]; then + mkdir -m 775 "$optTempDir" 2>/dev/null + fi + + if [ ! -d "$optVarLogDir" ]; then + mkdir -m 755 "$optVarLogDir" 2>/dev/null + fi } ##----------------------------------------## -## Modified by Martinski W. [2025-Jun-15] ## +## Modified by Martinski W. [2025-Nov-28] ## ##----------------------------------------## Create_Symlinks() { @@ -377,31 +409,39 @@ Create_Symlinks() then rm -f "$SCRIPT_DIR/.logs_user" fi - - if [ ! -f "$SCRIPT_DIR/.logs_user" ]; then + if [ ! -f "$SCRIPT_DIR/.logs_user" ] + then touch "$SCRIPT_DIR/.logs_user" fi while IFS='' read -r line || [ -n "$line" ] do - if [ "$(grep -c "$line" "$SCRIPT_DIR/.logs_user")" -eq 0 ]; then - printf "%s\\n" "$line" >> "$SCRIPT_DIR/.logs_user" + if [ "$(grep -c "$line" "$SCRIPT_DIR/.logs_user")" -eq 0 ] + then + printf "%s\n" "$line" >> "$SCRIPT_DIR/.logs_user" fi done < "$SCRIPT_DIR/.logs" rm -f "$SCRIPT_WEB_DIR/"*.htm 2>/dev/null - ln -s "$SCRIPT_DIR/.logs_user" "$SCRIPT_WEB_DIR/logs.htm" 2>/dev/null - ln -s /opt/var/log/messages "$SCRIPT_WEB_DIR/messages.htm" 2>/dev/null + ln -s "${optVarLogDir}/messages" "$SCRIPT_WEB_DIR/messages.htm" 2>/dev/null + ln -s "$SCRIPT_DIR/.logs_user" "$SCRIPT_WEB_DIR/logs_user.htm" 2>/dev/null + while IFS='' read -r line || [ -n "$line" ] do ln -s "$line" "$SCRIPT_WEB_DIR/$(basename "$line").htm" 2>/dev/null done < "$SCRIPT_DIR/.logs" + _Get_LogRotate_FileInfoList_ + ln -s "$logRotateInfoListJS" "${SCRIPT_WEB_DIR}/logRotateInfoList.js" 2>/dev/null + if [ ! -d "$SHARED_WEB_DIR" ]; then ln -s "$SHARED_DIR" "$SHARED_WEB_DIR" 2>/dev/null fi } +##----------------------------------------## +## Modified by Martinski W. [2025-Nov-28] ## +##----------------------------------------## Logs_FromSettings() { SETTINGSFILE="/jffs/addons/custom_settings.txt" @@ -418,13 +458,14 @@ Logs_FromSettings() syslog-ng --preprocess-into="$SCRIPT_DIR/tmplogs.txt" && grep -A 1 "destination" "$SCRIPT_DIR/tmplogs.txt" | grep "file(\"" | grep -v "#" | grep -v "messages" | sed -e 's/file("//;s/".*$//' | awk '{$1=$1;print}' > "$SCRIPT_DIR/.logs" rm -f "$SCRIPT_DIR/tmplogs.txt" 2>/dev/null - echo "" > "$LOGS_USER" + echo > "$LOGS_USER" comment=" #excluded#" while IFS='' read -r line || [ -n "$line" ] do - if [ "$(grep -c "$line" "$LOGS_USER")" -eq 0 ]; then - printf "%s%s\\n" "$line" "$comment" >> "$LOGS_USER" + if [ "$(grep -c "$line" "$LOGS_USER")" -eq 0 ] + then + printf "%s%s\n" "$line" "$comment" >> "$LOGS_USER" fi done < "$SCRIPT_DIR/.logs" @@ -432,8 +473,8 @@ Logs_FromSettings() do loglinenumber="$(grep -n "$log" "$LOGS_USER" | cut -f1 -d':')" logline="$(sed "$loglinenumber!d" "$LOGS_USER" | awk '{$1=$1};1')" - - if echo "$logline" | grep -q "#excluded" ; then + if echo "$logline" | grep -q "#excluded" + then sed -i "$loglinenumber"'s/ #excluded#//' "$LOGS_USER" fi done @@ -442,13 +483,17 @@ Logs_FromSettings() mv -f /tmp/uiscribe-logs "$LOGS_USER" rm -f "$SCRIPT_WEB_DIR/"*.htm 2>/dev/null - ln -s "$SCRIPT_DIR/.logs_user" "$SCRIPT_WEB_DIR/logs.htm" 2>/dev/null - ln -s /opt/var/log/messages "$SCRIPT_WEB_DIR/messages.htm" 2>/dev/null + ln -s "${optVarLogDir}/messages" "$SCRIPT_WEB_DIR/messages.htm" 2>/dev/null + ln -s "$SCRIPT_DIR/.logs_user" "$SCRIPT_WEB_DIR/logs_user.htm" 2>/dev/null + while IFS='' read -r line || [ -n "$line" ] do ln -s "$line" "$SCRIPT_WEB_DIR/$(basename "$line").htm" 2>/dev/null done < "$SCRIPT_DIR/.logs" + _Get_LogRotate_FileInfoList_ + ln -s "$logRotateInfoListJS" "${SCRIPT_WEB_DIR}/logRotateInfoList.js" 2>/dev/null + Print_Output true "Merge of updated logs from WebUI completed successfully" "$PASS" else Print_Output true "No updated logs from WebUI found, no merge into $LOGS_USER necessary" "$PASS" @@ -463,20 +508,16 @@ Generate_Log_List() { ScriptHeader goback=false - printf "Retrieving list of log files...\n\n" + printf " Retrieving list of log files...\n\n" logCount="$(wc -l < "$SCRIPT_DIR/.logs_user")" COUNTER=1 until [ "$COUNTER" -gt "$logCount" ] do logfile="$(sed "$COUNTER!d" "$SCRIPT_DIR/.logs_user" | awk '{$1=$1};1')" - if [ "$COUNTER" -lt 10 ]; then - printf "%s) %s\n" "$COUNTER" "$logfile" - else - printf "%s) %s\n" "$COUNTER" "$logfile" - fi + printf "%2d) %s\n" "$COUNTER" "$logfile" COUNTER="$((COUNTER + 1))" done - printf "\ne) Go back\n" + printf "\n e) Go back\n" while true do @@ -626,6 +667,343 @@ Auto_Startup() esac } +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_GetFileSize_() +{ + local typeUnits sizeUnits sizeInfo fileSize + if [ $# -eq 0 ] || [ -z "$1" ] || [ ! -f "$1" ] + then echo 0 ; return 1 + fi + + if [ $# -lt 2 ] || [ -z "$2" ] || \ + ! echo "$2" | grep -qE "^(B|KB|MB|GB|HR|HRx)$" + then typeUnits="B" ; else typeUnits="$2" + fi + + _GetNum_() { printf "%.1f" "$(echo "$1" | awk "{print $1}")" ; } + + case "$typeUnits" in + B|KB|MB|GB) + fileSize="$(ls -1l "$1" | awk -F ' ' '{print $3}')" + case "$typeUnits" in + KB) fileSize="$(_GetNum_ "($fileSize / $oneKByte)")" ;; + MB) fileSize="$(_GetNum_ "($fileSize / $oneMByte)")" ;; + GB) fileSize="$(_GetNum_ "($fileSize / $oneGByte)")" ;; + esac + echo "$fileSize" + ;; + HR|HRx) + fileSize="$(ls -1lh "$1" | awk -F ' ' '{print $3}')" + sizeInfo="${fileSize}B" + sizeUnits="$(echo "$sizeInfo" | tr -d '.0-9')" + if [ "$typeUnits" = "HR" ] + then + [ "$sizeUnits" = "B" ] && \ + sizeInfo="$(echo "$sizeInfo" | grep -oE '[0-9]+') Bytes" + echo "$sizeInfo" + return 0 + fi + case "$sizeUnits" in + MB) fileSize="$(_GetFileSize_ "$1" KB)" + sizeInfo="$sizeInfo (${fileSize}KB)" + ;; + GB) fileSize="$(_GetFileSize_ "$1" MB)" + sizeInfo="$sizeInfo (${fileSize}MB)" + ;; + B) sizeInfo="$(echo "$sizeInfo" | grep -oE '[0-9]+') Bytes" + ;; + esac + echo "$sizeInfo" + ;; + *) echo 0 ;; + esac + return 0 +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Get_LogRotate_ConfigFile_() +{ + if [ $# -eq 0 ] || [ -z "$1" ] || \ + [ ! -s "${optVarLogDir}/$1" ] + then + echo ; return 1 + fi + local theConfigFile theConfLogExp logFileRegExp configFileOK + + configFileOK=false + theConfLogExp="${logRotateDir}/*" + logFileRegExp="${optVarLogDir}/.*([.]log)?" + + for theConfigFile in $(ls -1 $theConfLogExp 2>/dev/null) + do + if [ ! -s "$theConfigFile" ] || \ + ! grep -qE "$logFileRegExp" "$theConfigFile" + then continue + fi + if grep -qE "${optVarLogDir}/$1" "$theConfigFile" + then + configFileOK=true ; break + fi + done + + "$configFileOK" && echo "$theConfigFile" || echo +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Get_LogRotate_FileInfoList_() +{ + local theConfLogExp theConfigFile theConfigCount + local logFileList logFileCount logFileSize logFileRegExp + + { + printf 'var logRotate_InfoListArray =' + } > "$logRotateInfoListJS" + + theConfigCount=0 + theConfLogExp="${logRotateDir}/*" + logFileRegExp="${optVarLogDir}/(.*|[.]log)" + + for theConfigFile in $(ls -1 $theConfLogExp 2>/dev/null) + do + if [ ! -s "$theConfigFile" ] || \ + ! grep -qE "$logFileRegExp" "$theConfigFile" + then continue + fi + logFileList="$(grep -oE "$logFileRegExp" "$theConfigFile" | awk -F' ' '{print $1}')" + [ -z "$logFileList" ] && continue + + if [ "$theConfigCount" -gt 0 ] + then printf ',\n' >> "$logRotateInfoListJS" + else printf '\n[\n' >> "$logRotateInfoListJS" + fi + { + printf " { LR_CONFIG: '${theConfigFile}'," + } >> "$logRotateInfoListJS" + + logFileCount=0 + for logFPath in $logFileList + do + if [ "$logFileCount" -eq 0 ] + then printf '\n' >> "$logRotateInfoListJS" + else printf ',\n' >> "$logRotateInfoListJS" + fi + logFileSize="$(_GetFileSize_ "$logFPath" HRx)" + [ "$logFileSize" = "0" ] && logFileSize="0 Bytes" + { + printf " LOG_PATH${logFileCount}: '%s',\n" "$logFPath" + printf " LOG_SIZE${logFileCount}: '%s'" "$logFileSize" + } >> "$logRotateInfoListJS" + logFileCount="$((logFileCount + 1))" + done + { + printf '\n }' + } >> "$logRotateInfoListJS" + theConfigCount="$((theConfigCount + 1))" + done + + if [ "$theConfigCount" -eq 0 ] + then + printf ' [];\n' >> "$logRotateInfoListJS" + else + printf '\n];\n' >> "$logRotateInfoListJS" + fi +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Run_RotateLogFile_() +{ + rm -f "$logRotateStatusJS" + + if [ $# -eq 0 ] || [ -z "$1" ] || [ ! -x "$logRotateCmd" ] + then + echo "var logRotateStatus = 'ERROR';" > "$logRotateStatusJS" + echo "ERROR: LogRotate is NOT available." > "$logRotateStatusT" + return 1 + fi + local logRotateConf="" + + case "$1" in + ALL) logRotateConf="$logRotateConfig" + ;; + *) logRotateConf="$(_Get_LogRotate_ConfigFile_ "$1")" + ;; + esac + + if [ -z "$logRotateConf" ] || [ ! -s "$logRotateConf" ] + then + echo "var logRotateStatus = 'ERROR';" > "$logRotateStatusJS" + { + [ ! -s "${optVarLogDir}/$1" ] && \ + echo "Log file [${optVarLogDir}/$1] NOT found or is EMPTY." + [ -n "$logRotateConf" ] && \ + echo "Check if LogRotate config file ["$logRotateConf"] exists." + } > "$logRotateStatusT" + return 1 + fi + echo "var logRotateStatus = 'InProgress';" > "$logRotateStatusJS" + + $logRotateCmd "$logRotateConf" > "$logRotateOutput" 2>&1 + tail -v "$logRotateOutput" > "$logRotateStatusT" + [ -s "$logRotateOutput" ] && \ + cat "$logRotateOutput" > "$logRotateDaily" + echo "LogRotate '$1' was completed." >> "$logRotateStatusT" + echo "var logRotateStatus = 'DONE';" > "$logRotateStatusJS" + + sleep 1 + _Get_LogRotate_FileInfoList_ +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Set_LogRotateClear_ConfigOptions_() +{ + cat << 'EOF' +{ + hourly + size 0k + rotate 9 + compress + create + dateext + dateformat -%Y%m%d%H%M%S + missingok + notifempty + sharedscripts + postrotate + /usr/bin/killall -HUP syslog-ng + endscript +} +EOF +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Get_LogRotateClear_ConfigFile_() +{ + if [ $# -eq 0 ] || [ -z "$1" ] || \ + [ ! -s "${optVarLogDir}/$1" ] + then + echo ; return 1 + fi + local logFileName="$1" theConfigFile + theConfigFile="${optTempDir}/ClearLog_${logFileName%.*}.conf" + rm -f "$theConfigFile" + + echo "${optVarLogDir}/$logFileName" > "$theConfigFile" + _Set_LogRotateClear_ConfigOptions_ >> "$theConfigFile" + chmod 644 "$theConfigFile" + echo "$theConfigFile" +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Run_ClearAllLogFiles_() +{ + local logFilePath="${optVarLogDir}/messages" + local logRotateConf="${optTempDir}/ClearLog_ALL.conf" + + rm -f "$logRotateConf" + + [ -s "$logFilePath" ] && \ + echo "$logFilePath" > "$logRotateConf" + + [ ! -s "${SCRIPT_DIR}/.logs_user" ] && \ + touch "${SCRIPT_DIR}/.logs_user" + + while IFS='' read -r theLINE || [ -n "$theLINE" ] + do + if echo "$theLINE" | grep -qoF '#excluded#' + then continue + fi + logFilePath="$(echo "$theLINE" | sed 's/ *$//')" + [ -s "$logFilePath" ] && \ + echo "$logFilePath" >> "$logRotateConf" + done < "${SCRIPT_DIR}/.logs_user" + + if [ -z "$logRotateConf" ] || [ ! -s "$logRotateConf" ] + then + echo "var logClearStatus = 'ERROR';" > "$logClearStatusJS" + { + echo "Log files in [$optVarLogDir] NOT found or are EMPTY." + } > "$logClearStatusT" + return 1 + fi + + _Set_LogRotateClear_ConfigOptions_ >> "$logRotateConf" + chmod 644 "$logRotateConf" + echo "var logClearStatus = 'InProgress';" > "$logClearStatusJS" + + $logRotateCmd "$logRotateConf" > "$logRotateOutput" 2>&1 + tail -v "$logRotateOutput" > "$logClearStatusT" + [ -s "$logRotateOutput" ] && \ + cat "$logRotateOutput" > "$logRotateDaily" + echo "LogRotateClear 'ALL' was completed." >> "$logClearStatusT" + echo "var logClearStatus = 'DONE';" > "$logClearStatusJS" + rm -f "$logRotateConf" + + sleep 1 + _Get_LogRotate_FileInfoList_ +} + +##-------------------------------------## +## Added by Martinski W. [2025-Nov-28] ## +##-------------------------------------## +_Run_ClearLogFile_() +{ + rm -f "$logClearStatusJS" + + if [ $# -eq 0 ] || [ -z "$1" ] || [ ! -x "$logRotateCmd" ] + then + echo "var logClearStatus = 'ERROR';" > "$logClearStatusJS" + echo "ERROR: LogRotate is NOT available." > "$logClearStatusJS" + return 1 + fi + local logFilePath logRotateConf="" + + case "$1" in + ALL) _Run_ClearAllLogFiles_ ; return "$?" + ;; + *) logRotateConf="$(_Get_LogRotateClear_ConfigFile_ "$1")" + ;; + esac + + if [ -z "$logRotateConf" ] || [ ! -s "$logRotateConf" ] + then + logFilePath="${optVarLogDir}/$1" + echo "var logClearStatus = 'ERROR';" > "$logClearStatusJS" + { + [ ! -s "$logFilePath" ] && \ + echo "Log file [$logFilePath] NOT found or is EMPTY." + [ -n "$logRotateConf" ] && \ + echo "Check if LogRotate config file ["$logRotateConf"] exists." + } > "$logClearStatusT" + return 1 + fi + echo "var logClearStatus = 'InProgress';" > "$logClearStatusJS" + + $logRotateCmd "$logRotateConf" > "$logRotateOutput" 2>&1 + tail -v "$logRotateOutput" > "$logClearStatusT" + [ -s "$logRotateOutput" ] && \ + cat "$logRotateOutput" > "$logRotateDaily" + echo "LogRotateClear '$1' was completed." >> "$logClearStatusT" + echo "var logClearStatus = 'DONE';" > "$logClearStatusJS" + rm -f "$logRotateConf" + + sleep 1 + _Get_LogRotate_FileInfoList_ +} + ##----------------------------------------## ## Modified by Martinski W. [2025-Jun-09] ## ##----------------------------------------## @@ -818,14 +1196,14 @@ MainMenu() { Create_Dirs Create_Symlinks - printf "WebUI for %s is available at:\n${SETTING}%s${CLEARFORMAT}\n\n" "$SCRIPT_NAME" "$(Get_WebUI_URL)" - - printf "1. Customise list of logs displayed by %s\n\n" "$SCRIPT_NAME" - printf "rf. Clear user preferences for displayed logs\n\n" - printf "u. Check for updates\n" - printf "uf. Force update %s with latest version\n\n" "$SCRIPT_NAME" - printf "e. Exit %s\n\n" "$SCRIPT_NAME" - printf "z. Uninstall %s\n" "$SCRIPT_NAME" + printf " WebUI for %s is available at:\n ${SETTING}%s${CLEARFORMAT}\n\n" "$SCRIPT_NAME" "$(Get_WebUI_URL)" + + printf " 1. Customise list of logs displayed by %s\n\n" "$SCRIPT_NAME" + printf " rf. Clear user preferences for displayed logs\n\n" + printf " u. Check for updates\n" + printf " uf. Force update %s with latest version\n\n" "$SCRIPT_NAME" + printf " e. Exit %s\n\n" "$SCRIPT_NAME" + printf " z. Uninstall %s\n" "$SCRIPT_NAME" printf "\n" printf "${BOLD}########################################################${CLEARFORMAT}\n" printf "\n" @@ -928,7 +1306,7 @@ Check_Requirements() CHECKSFAILED="true" fi - if [ ! -f /opt/bin/scribe ] + if [ ! -x /opt/bin/scribe ] || [ ! -x /jffs/scripts/scribe ] then Print_Output false "Scribe is NOT installed!" "$ERR" CHECKSFAILED="true" @@ -1179,7 +1557,7 @@ then fi ##----------------------------------------## -## Modified by Martinski W. [2025-Jun-27] ## +## Modified by Martinski W. [2025-Nov-28] ## ##----------------------------------------## case "$1" in install) @@ -1193,15 +1571,27 @@ case "$1" in exit 0 ;; service_event) - if [ "$2" = "start" ] && [ "$3" = "${SCRIPT_NAME}config" ] + [ "$2" != "start" ] && exit 0 + if [ "$3" = "${SCRIPT_NAME}config" ] then Logs_FromSettings - elif [ "$2" = "start" ] && [ "$3" = "${SCRIPT_NAME}checkupdate" ] + elif [ "$3" = "${SCRIPT_NAME}checkupdate" ] then Update_Check - elif [ "$2" = "start" ] && [ "$3" = "${SCRIPT_NAME}doupdate" ] + elif [ "$3" = "${SCRIPT_NAME}doupdate" ] then Update_Version force unattended + elif echo "$3" | grep -qE "^${SCRIPT_NAME}RotateLog_.*" + then + logFileName="$(echo "$3" | cut -d'_' -f2)" + _Run_RotateLogFile_ "$logFileName" + elif echo "$3" | grep -qE "^${SCRIPT_NAME}ClearLog_.*" + then + logFileName="$(echo "$3" | cut -d'_' -f2)" + _Run_ClearLogFile_ "$logFileName" + elif echo "$3" | grep -qE "^${SCRIPT_NAME}LogFileInfoList" + then + _Get_LogRotate_FileInfoList_ fi exit 0 ;;