Merge pull request #16 from accius/Modular-Staging

error logging silencing
pull/27/head
accius 3 days ago committed by GitHub
commit 6b739c42a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -38,8 +38,8 @@ let consecutiveFailures = 0;
let lastFailureTime = 0; let lastFailureTime = 0;
let lastLogTime = 0; let lastLogTime = 0;
const FAILURE_THRESHOLD = 3; // Open after 3 failures const FAILURE_THRESHOLD = 3; // Open after 3 failures
const CIRCUIT_RESET_TIME = 2 * 60 * 1000; // 2 minutes before retry const CIRCUIT_RESET_TIME = 5 * 60 * 1000; // 5 minutes before retry
const LOG_INTERVAL = 30000; // Only log every 30 seconds const LOG_INTERVAL = 60000; // Only log every 60 seconds
function getCacheKey(params) { function getCacheKey(params) {
// Round coordinates to 1 decimal place for better cache hits // Round coordinates to 1 decimal place for better cache hits

@ -41,6 +41,26 @@ if (ITURHFPROP_URL) {
app.use(cors()); app.use(cors());
app.use(express.json()); app.use(express.json());
// ============================================
// RATE-LIMITED LOGGING
// ============================================
// Prevents log spam when services are down
const errorLogState = {};
const ERROR_LOG_INTERVAL = 60000; // Only log same error once per minute
function logErrorOnce(category, message) {
const key = `${category}:${message}`;
const now = Date.now();
const lastLogged = errorLogState[key] || 0;
if (now - lastLogged >= ERROR_LOG_INTERVAL) {
errorLogState[key] = now;
console.error(`[${category}] ${message}`);
return true;
}
return false;
}
// Serve static files - use 'dist' in production (Vite build), 'public' in development // Serve static files - use 'dist' in production (Vite build), 'public' in development
const staticDir = process.env.NODE_ENV === 'production' const staticDir = process.env.NODE_ENV === 'production'
? path.join(__dirname, 'dist') ? path.join(__dirname, 'dist')
@ -526,7 +546,7 @@ app.get('/api/dxcluster/spots', async (req, res) => {
} catch (error) { } catch (error) {
clearTimeout(timeout); clearTimeout(timeout);
if (error.name !== 'AbortError') { if (error.name !== 'AbortError') {
console.error('[DX Cluster] HamQTH error:', error.message); logErrorOnce('DX Cluster', `HamQTH: ${error.message}`);
} }
} }
return null; return null;
@ -554,7 +574,7 @@ app.get('/api/dxcluster/spots', async (req, res) => {
} catch (error) { } catch (error) {
clearTimeout(timeout); clearTimeout(timeout);
if (error.name !== 'AbortError') { if (error.name !== 'AbortError') {
console.error('[DX Cluster] DX Spider Proxy error:', error.message); logErrorOnce('DX Cluster', `Proxy: ${error.message}`);
} }
} }
return null; return null;
@ -679,9 +699,9 @@ app.get('/api/dxcluster/spots', async (req, res) => {
}); });
client.on('error', (err) => { client.on('error', (err) => {
// Only log unexpected errors, not connection resets (they're common) // Only log unexpected errors, not connection issues (they're common)
if (!err.message.includes('ECONNRESET') && !err.message.includes('ETIMEDOUT') && !err.message.includes('ENOTFOUND')) { if (!err.message.includes('ECONNRESET') && !err.message.includes('ETIMEDOUT') && !err.message.includes('ENOTFOUND') && !err.message.includes('ECONNREFUSED')) {
console.error(`[DX Cluster] DX Spider ${node.host} error:`, err.message); logErrorOnce('DX Cluster', `DX Spider ${node.host}: ${err.message}`);
} }
cleanup(); cleanup();
}); });
@ -1542,7 +1562,7 @@ app.get('/api/myspots/:callsign', async (req, res) => {
res.json(spotsWithLocations); res.json(spotsWithLocations);
} catch (error) { } catch (error) {
console.error('[My Spots] Error:', error.message); logErrorOnce('My Spots', error.message);
res.json([]); res.json([]);
} }
}); });
@ -1770,7 +1790,7 @@ async function fetchIonosondeData() {
return validStations; return validStations;
} catch (error) { } catch (error) {
console.error('[Ionosonde] Fetch error:', error.message); logErrorOnce('Ionosonde', `Fetch error: ${error.message}`);
return ionosondeCache.data || []; return ionosondeCache.data || [];
} }
} }
@ -1785,7 +1805,7 @@ app.get('/api/ionosonde', async (req, res) => {
stations: stations stations: stations
}); });
} catch (error) { } catch (error) {
console.error('[Ionosonde] API error:', error.message); logErrorOnce('Ionosonde', `API: ${error.message}`);
res.status(500).json({ error: 'Failed to fetch ionosonde data' }); res.status(500).json({ error: 'Failed to fetch ionosonde data' });
} }
}); });
@ -1923,12 +1943,12 @@ async function fetchITURHFPropPrediction(txLat, txLon, rxLat, rxLon, ssn, month,
clearTimeout(timeoutId); clearTimeout(timeoutId);
if (!response.ok) { if (!response.ok) {
console.log('[Hybrid] ITURHFProp returned error:', response.status, response.statusText); logErrorOnce('Hybrid', `ITURHFProp returned ${response.status}`);
return null; return null;
} }
const data = await response.json(); const data = await response.json();
console.log('[Hybrid] ITURHFProp prediction received, MUF:', data.muf); // Only log success occasionally to reduce noise
// Cache the result // Cache the result
iturhfpropCache = { iturhfpropCache = {
@ -1940,7 +1960,9 @@ async function fetchITURHFPropPrediction(txLat, txLon, rxLat, rxLon, ssn, month,
return data; return data;
} catch (err) { } catch (err) {
console.log('[Hybrid] ITURHFProp service error:', err.name, err.message); if (err.name !== 'AbortError') {
logErrorOnce('Hybrid', `ITURHFProp: ${err.message}`);
}
return null; return null;
} }
} }
@ -1952,17 +1974,17 @@ async function fetchITURHFPropHourly(txLat, txLon, rxLat, rxLon, ssn, month) {
if (!ITURHFPROP_URL) return null; if (!ITURHFPROP_URL) return null;
try { try {
console.log('[Hybrid] Fetching 24-hour prediction from ITURHFProp...');
const url = `${ITURHFPROP_URL}/api/predict/hourly?txLat=${txLat}&txLon=${txLon}&rxLat=${rxLat}&rxLon=${rxLon}&ssn=${ssn}&month=${month}`; const url = `${ITURHFPROP_URL}/api/predict/hourly?txLat=${txLat}&txLon=${txLon}&rxLat=${rxLat}&rxLon=${rxLon}&ssn=${ssn}&month=${month}`;
const response = await fetch(url, { timeout: 60000 }); // 60s timeout for 24-hour calc const response = await fetch(url, { timeout: 60000 }); // 60s timeout for 24-hour calc
if (!response.ok) return null; if (!response.ok) return null;
const data = await response.json(); const data = await response.json();
console.log('[Hybrid] Received 24-hour prediction');
return data; return data;
} catch (err) { } catch (err) {
console.log('[Hybrid] ITURHFProp hourly unavailable:', err.message); if (err.name !== 'AbortError') {
logErrorOnce('Hybrid', `ITURHFProp hourly: ${err.message}`);
}
return null; return null;
} }
} }

Loading…
Cancel
Save

Powered by TurnKey Linux.