From 952aa7a3b58e5d4905b20afa3b7d03cf49dd7173 Mon Sep 17 00:00:00 2001 From: Rim Date: Wed, 2 Apr 2025 07:33:09 -0400 Subject: [PATCH] chore: logger helper function to convert ISO string to user's local datetime --- app.js | 75 +++++++++++++++++++++++----------------------- src/js/frontend.js | 6 ++-- src/js/logger.js | 2 +- src/js/utils.js | 20 +++++++++++++ 4 files changed, 62 insertions(+), 41 deletions(-) create mode 100644 src/js/utils.js diff --git a/app.js b/app.js index 753abeb..6422822 100644 --- a/app.js +++ b/app.js @@ -2,10 +2,11 @@ const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const API = require('./src/js/index.js'); -const { logger } = require('./src/js/logger'); +const { logger } = require('./src/js/logger.js'); const favicon = require('serve-favicon'); const app = express(); const port = process.env.PORT || 3512; +require('./src/js/utils.js') app.set('trust proxy', true); @@ -98,7 +99,7 @@ const sanitizeJsonOutput = (data) => { try { return JSON.parse(sanitizedString); } catch (e) { - console.error('Error parsing sanitized JSON:', e); + logger.error('Error parsing sanitized JSON:', e); return data; // Return original data if parsing fails } }; @@ -165,7 +166,7 @@ const ensureLogin = async (ssoToken) => { ]); logger.debug(`Login successful: ${JSON.stringify(loginResult)}`); - logger.debug(`Session created at: ${new Date().toISOString()}`); + logger.debug(`Session created at: ${global.Utils.toIsoString(new Date())}`); activeSessions.set(ssoToken, new Date()); } else { logger.debug('Using existing session'); @@ -176,7 +177,7 @@ const ensureLogin = async (ssoToken) => { const handleApiError = (error, res) => { logger.error('API Error:', error); logger.error(`Error Stack: ${error.stack}`); - logger.error(`Error Time: ${new Date().toISOString()}`); + logger.error(`Error Time: ${global.Utils.toIsoString(new Date())}`); // Try to extract more useful information from the error let errorMessage = error.message || 'Unknown API error'; @@ -190,7 +191,7 @@ const handleApiError = (error, res) => { message: 'Failed to parse API response. This usually means the SSO token is invalid or expired.', error_type: 'InvalidResponseError', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -199,7 +200,7 @@ const handleApiError = (error, res) => { status: 'error', message: errorMessage, error_type: errorName, - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); }; @@ -265,13 +266,13 @@ app.post('/api/stats', async (req, res) => { try { await ensureLogin(ssoToken); } catch (loginError) { - console.error('Login error:', loginError); + logger.error('Login error:', loginError); return res.status(200).json({ status: 'error', error_type: 'LoginError', message: 'SSO token login failed', details: loginError.message || 'Unknown login error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -290,7 +291,7 @@ app.post('/api/stats', async (req, res) => { return res.status(200).json({ status: 'error', message: `${game} requires Uno ID (numerical ID)`, - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -347,7 +348,7 @@ app.post('/api/stats', async (req, res) => { return res.status(200).json({ status: 'error', message: 'Invalid game selected', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } } else if (apiCall === 'combatHistory') { @@ -397,7 +398,7 @@ app.post('/api/stats', async (req, res) => { return res.status(200).json({ status: 'error', message: 'Invalid game selected', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } } else if (apiCall === 'mapList') { @@ -410,14 +411,14 @@ app.post('/api/stats', async (req, res) => { return res.status(200).json({ status: 'error', message: 'Map list is only available for Modern Warfare', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } } logger.debug('Data fetched successfully'); logger.debug(`Response Size: ~${JSON.stringify(data).length / 1024} KB`); - logger.debug(`Response Time: ${new Date().toISOString()}`); + logger.debug(`Response Time: ${global.Utils.toIsoString(new Date())}`); // Safely handle the response data if (!data) { @@ -426,7 +427,7 @@ app.post('/api/stats', async (req, res) => { status: 'partial_success', message: 'No data returned from API, but no error thrown', data: null, - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -437,20 +438,20 @@ app.post('/api/stats', async (req, res) => { return res.json({ // status: "success", data: processJsonOutput(data, { sanitize, replaceKeys }), - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } catch (apiError) { return handleApiError(apiError, res); } } catch (serverError) { - console.error('Server Error:', serverError); + logger.error('Server Error:', serverError); // Return a structured error response even for unexpected errors return res.status(200).json({ status: 'server_error', message: 'The server encountered an unexpected error', error_details: serverError.message || 'Unknown server error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } }); @@ -503,7 +504,7 @@ app.post('/api/matches', async (req, res) => { error_type: 'LoginError', message: 'SSO token login failed', details: loginError.message || 'Unknown login error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -527,7 +528,7 @@ app.post('/api/matches', async (req, res) => { return res.status(200).json({ status: 'error', message: `${game} requires Uno ID (numerical ID)`, - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -577,7 +578,7 @@ app.post('/api/matches', async (req, res) => { return res.status(200).json({ status: 'error', message: 'Invalid game selected', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -586,7 +587,7 @@ app.post('/api/matches', async (req, res) => { return res.json({ // status: "success", data: processJsonOutput(data, { sanitize, replaceKeys }), - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } catch (apiError) { return handleApiError(apiError, res); @@ -596,7 +597,7 @@ app.post('/api/matches', async (req, res) => { status: 'server_error', message: 'The server encountered an unexpected error', error_details: serverError.message || 'Unknown server error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } }); @@ -650,7 +651,7 @@ app.post('/api/matchInfo', async (req, res) => { error_type: 'LoginError', message: 'SSO token login failed', details: loginError.message || 'Unknown login error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -710,7 +711,7 @@ app.post('/api/matchInfo', async (req, res) => { return res.status(200).json({ status: 'error', message: 'Invalid game selected', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -719,7 +720,7 @@ app.post('/api/matchInfo', async (req, res) => { return res.json({ // status: "success", data: processJsonOutput(data, { sanitize, replaceKeys }), - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } catch (apiError) { return handleApiError(apiError, res); @@ -729,7 +730,7 @@ app.post('/api/matchInfo', async (req, res) => { status: 'server_error', message: 'The server encountered an unexpected error', error_details: serverError.message || 'Unknown server error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } }); @@ -792,7 +793,7 @@ app.post('/api/user', async (req, res) => { error_type: 'LoginError', message: 'SSO token login failed', details: loginError.message || 'Unknown login error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -843,7 +844,7 @@ app.post('/api/user', async (req, res) => { return res.status(200).json({ status: 'error', message: 'Invalid user API call selected', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -852,7 +853,7 @@ app.post('/api/user', async (req, res) => { return res.json({ // status: "success", data: processJsonOutput(data, { sanitize, replaceKeys }), - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } catch (apiError) { return handleApiError(apiError, res); @@ -862,7 +863,7 @@ app.post('/api/user', async (req, res) => { status: 'server_error', message: 'The server encountered an unexpected error', error_details: serverError.message || 'Unknown server error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } }); @@ -912,7 +913,7 @@ app.post('/api/search', async (req, res) => { error_type: 'LoginError', message: 'SSO token login failed', details: loginError.message || 'Unknown login error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } @@ -937,7 +938,7 @@ app.post('/api/search', async (req, res) => { return res.json({ // status: "success", data: processJsonOutput(data, { sanitize, replaceKeys }), - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), // link: "Stats pulled using codtracker.rimmyscorner.com", }); } catch (apiError) { @@ -948,7 +949,7 @@ app.post('/api/search', async (req, res) => { status: 'server_error', message: 'The server encountered an unexpected error', error_details: serverError.message || 'Unknown server error', - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), }); } }); @@ -970,7 +971,7 @@ app.post('/api/log', (req, res) => { logData = req.body; } else { // If no parsable data found, create a basic log entry - logData = { eventType: 'unknown', timestamp: new Date().toISOString() }; + logData = { eventType: 'unknown', timestamp: global.Utils.toIsoString(new Date()) }; } // Enrich log with server-side data @@ -982,7 +983,7 @@ app.post('/api/log', (req, res) => { referer, origin, requestHeaders: sanitizeHeaders(req.headers), - serverTimestamp: new Date().toISOString(), + serverTimestamp: global.Utils.toIsoString(new Date()), requestId: req.id || Math.random().toString(36).substring(2, 15), }, }; @@ -1020,13 +1021,13 @@ function sanitizeHeaders(headers) { function storeLogInDatabase(logData) { // Example with MongoDB db.collection('user_logs').insertOne(logData) - .catch(err => console.error('Failed to store log in database:', err)); + .catch(err => logger.error('Failed to store log in database:', err)); } */ // Basic health check endpoint app.get('/health', (req, res) => { - res.json({ status: 'ok', timestamp: new Date().toISOString() }); + res.json({ status: 'ok', timestamp: global.Utils.toIsoString(new Date()) }); }); // Serve the main HTML file diff --git a/src/js/frontend.js b/src/js/frontend.js index 43ca220..0d2e0ef 100644 --- a/src/js/frontend.js +++ b/src/js/frontend.js @@ -33,7 +33,7 @@ const clientLogger = { [ JSON.stringify({ eventType, - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), ...data, }), ], @@ -49,10 +49,10 @@ const clientLogger = { keepalive: true, body: JSON.stringify({ eventType, - timestamp: new Date().toISOString(), + timestamp: global.Utils.toIsoString(new Date()), ...data, }), - }).catch((e) => console.error('Logging error:', e)); + }).catch((e) => logger.error('Logging error:', e)); } }, }; diff --git a/src/js/logger.js b/src/js/logger.js index 604fa79..63888f0 100644 --- a/src/js/logger.js +++ b/src/js/logger.js @@ -54,7 +54,7 @@ class Logger { } formatLogEntry(type, message, data = {}) { - const timestamp = new Date().toISOString(); + const timestamp = global.Utils.toIsoString(new Date()); const logObject = { timestamp, type, diff --git a/src/js/utils.js b/src/js/utils.js new file mode 100644 index 0000000..6bedf91 --- /dev/null +++ b/src/js/utils.js @@ -0,0 +1,20 @@ +global.Utils = { + toIsoString + }; + +function toIsoString(date) { + var tzo = -date.getTimezoneOffset(), + dif = tzo >= 0 ? '+' : '-', + pad = function(num) { + return (num < 10 ? '0' : '') + num; + }; + + return date.getFullYear() + + '-' + pad(date.getMonth() + 1) + + '-' + pad(date.getDate()) + + 'T' + pad(date.getHours()) + + ':' + pad(date.getMinutes()) + + ':' + pad(date.getSeconds()) + + dif + pad(Math.floor(Math.abs(tzo) / 60)) + + ':' + pad(Math.abs(tzo) % 60); + } \ No newline at end of file