chore: logger helper function to convert ISO string to user's local datetime

This commit is contained in:
Rim 2025-04-02 07:33:09 -04:00
parent 7ccc0be712
commit 952aa7a3b5
4 changed files with 62 additions and 41 deletions

75
app.js
View File

@ -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

View File

@ -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));
}
},
};

View File

@ -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,

20
src/js/utils.js Normal file
View File

@ -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);
}