Merge pull request #75 from itdoginfo/feature/error-notification (#47)

Feature/error notification
This commit is contained in:
itdoginfo
2025-04-03 14:52:00 +03:00
committed by GitHub
2 changed files with 103 additions and 3 deletions

View File

@@ -12,6 +12,8 @@ const STATUS_COLORS = {
WARNING: '#ff9800' WARNING: '#ff9800'
}; };
const ERROR_POLL_INTERVAL = 5000; // 5 seconds
async function safeExec(command, args = [], timeout = 7000) { async function safeExec(command, args = [], timeout = 7000) {
try { try {
const controller = new AbortController(); const controller = new AbortController();
@@ -850,6 +852,84 @@ function checkDNSAvailability() {
}); });
} }
async function getPodkopErrors() {
try {
const result = await safeExec('/usr/bin/podkop', ['check_logs']);
if (!result || !result.stdout) return [];
const logs = result.stdout.split('\n');
const errors = logs.filter(log =>
// log.includes('saved for future filters') ||
log.includes('[critical]')
);
console.log('Found errors:', errors);
return errors;
} catch (error) {
console.error('Error getting podkop logs:', error);
return [];
}
}
let errorPollTimer = null;
let lastErrorsSet = new Set();
let isInitialCheck = true;
function showErrorNotification(error, isMultiple = false) {
const notificationContent = E('div', { 'class': 'alert-message error' }, [
E('pre', { 'class': 'error-log' }, error)
]);
ui.addNotification(null, notificationContent);
}
function startErrorPolling() {
if (errorPollTimer) {
clearInterval(errorPollTimer);
}
async function checkErrors() {
const result = await safeExec('/usr/bin/podkop', ['check_logs']);
if (!result || !result.stdout) return;
const logs = result.stdout;
const errorLines = logs.split('\n').filter(line =>
// line.includes('saved for future filters') ||
line.includes('[critical]')
);
if (errorLines.length > 0) {
const currentErrors = new Set(errorLines);
if (isInitialCheck) {
if (errorLines.length > 0) {
showErrorNotification(errorLines.join('\n'), true);
}
isInitialCheck = false;
} else {
const newErrors = [...currentErrors].filter(error => !lastErrorsSet.has(error));
newErrors.forEach(error => {
showErrorNotification(error, false);
});
}
lastErrorsSet = currentErrors;
}
}
checkErrors();
errorPollTimer = setInterval(checkErrors, ERROR_POLL_INTERVAL);
}
function stopErrorPolling() {
if (errorPollTimer) {
clearInterval(errorPollTimer);
errorPollTimer = null;
}
}
return view.extend({ return view.extend({
async render() { async render() {
document.head.insertAdjacentHTML('beforeend', ` document.head.insertAdjacentHTML('beforeend', `
@@ -1348,8 +1428,10 @@ return view.extend({
const diagnosticsContainer = document.getElementById('diagnostics-status'); const diagnosticsContainer = document.getElementById('diagnostics-status');
if (document.hidden) { if (document.hidden) {
stopDiagnosticsUpdates(); stopDiagnosticsUpdates();
stopErrorPolling();
} else if (diagnosticsContainer && diagnosticsContainer.hasAttribute('data-loading')) { } else if (diagnosticsContainer && diagnosticsContainer.hasAttribute('data-loading')) {
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
}); });
@@ -1360,6 +1442,7 @@ return view.extend({
if (!this.hasAttribute('data-loading')) { if (!this.hasAttribute('data-loading')) {
this.setAttribute('data-loading', 'true'); this.setAttribute('data-loading', 'true');
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
}); });
} }
@@ -1375,9 +1458,11 @@ return view.extend({
if (container && !container.hasAttribute('data-loading')) { if (container && !container.hasAttribute('data-loading')) {
container.setAttribute('data-loading', 'true'); container.setAttribute('data-loading', 'true');
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
} else { } else {
stopDiagnosticsUpdates(); stopDiagnosticsUpdates();
stopErrorPolling();
} }
} }
}); });
@@ -1388,6 +1473,7 @@ return view.extend({
if (container && !container.hasAttribute('data-loading')) { if (container && !container.hasAttribute('data-loading')) {
container.setAttribute('data-loading', 'true'); container.setAttribute('data-loading', 'true');
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
} }
} }

View File

@@ -45,6 +45,7 @@ nolog() {
} }
start() { start() {
log "Starting podkop"
migration migration
config_foreach process_validate_service config_foreach process_validate_service
@@ -1857,12 +1858,24 @@ check_fakeip() {
check_logs() { check_logs() {
nolog "Showing podkop logs from system journal..." nolog "Showing podkop logs from system journal..."
if command -v logread >/dev/null 2>&1; then if ! command -v logread >/dev/null 2>&1; then
logread -e podkop | tail -n 50
else
nolog "Error: logread command not found" nolog "Error: logread command not found"
return 1 return 1
fi fi
# Get all logs first
local all_logs=$(logread)
# Find the last occurrence of "Starting podkop"
local start_line=$(echo "$all_logs" | grep -n "podkop.*Starting podkop" | tail -n 1 | cut -d: -f1)
if [ -z "$start_line" ]; then
nolog "No 'Starting podkop' message found in logs"
return 1
fi
# Output all logs from the last start
echo "$all_logs" | tail -n +"$start_line"
} }
show_sing_box_config() { show_sing_box_config() {
@@ -1918,6 +1931,7 @@ show_config() {
-e 's/\(ss:\/\/[^@]*@\)/ss:\/\/MASKED@/g' \ -e 's/\(ss:\/\/[^@]*@\)/ss:\/\/MASKED@/g' \
-e 's/\(pbk=[^&]*\)/pbk=MASKED/g' \ -e 's/\(pbk=[^&]*\)/pbk=MASKED/g' \
-e 's/\(sid=[^&]*\)/sid=MASKED/g' \ -e 's/\(sid=[^&]*\)/sid=MASKED/g' \
-e 's/\(option dns_server '\''[^'\'']*\.dns\.nextdns\.io'\''\)/option dns_server '\''MASKED.dns.nextdns.io'\''/g' \
> "$tmp_config" > "$tmp_config"
cat "$tmp_config" cat "$tmp_config"