Add in Pino logging and make UI consistent across the app.

This commit is contained in:
Cameron Redmore 2025-04-25 19:34:17 +01:00
parent 727746030c
commit 300040bd58
19 changed files with 590 additions and 235 deletions

View file

@ -621,7 +621,6 @@ router.post('/mantis-summaries/generate', async(req, res) =>
generateTodaysSummary()
.then(() =>
{
console.log('Summary generation process finished successfully (async).');
})
.catch(error =>
{

View file

@ -158,8 +158,6 @@ router.post('/verify-registration', async(req, res) =>
const { verified, registrationInfo } = verification;
console.log(verification);
if (verified && registrationInfo)
{
const { credential, credentialDeviceType, credentialBackedUp } = registrationInfo;
@ -242,12 +240,8 @@ router.post('/generate-authentication-options', async(req, res) =>
return res.status(404).json({ error: 'User not found' });
}
console.log('User found:', user);
const userAuthenticators = await getUserAuthenticators(user.id);
console.log('User authenticators:', userAuthenticators);
const options = await generateAuthenticationOptions({
rpID,
// Require users to use a previously-registered authenticator

View file

@ -16,6 +16,8 @@ import session from 'express-session';
import { PrismaSessionStore } from '@quixo3/prisma-session-store';
import { PrismaClient } from '@prisma/client';
import { v4 as uuidv4 } from 'uuid';
import pino from 'pino';
import pinoHttp from 'pino-http';
import apiRoutes from './routes/api.js';
import authRoutes from './routes/auth.js';
import chatRoutes from './routes/chat.js';
@ -27,6 +29,47 @@ import { requireAuth } from './middlewares/authMiddleware.js';
dotenv.config();
// Initialize Pino logger
const targets = [];
// Console logging (pretty-printed in development)
if (process.env.NODE_ENV !== 'production')
{
targets.push({
target: 'pino-pretty',
options: {
colorize: true
},
level: process.env.LOG_LEVEL || 'info'
});
}
else
{
// Basic console logging in production
targets.push({
target: 'pino/file', // Log to stdout in production
options: { destination: 1 }, // 1 is stdout
level: process.env.LOG_LEVEL || 'info'
});
}
// Database logging via custom transport
targets.push({
target: './utils/prisma-pino-transport.js', // Path to the custom transport
options: {}, // No specific options needed for this transport
level: process.env.DB_LOG_LEVEL || 'info' // Separate level for DB logging if needed
});
const logger = pino({
level: process.env.LOG_LEVEL || 'info', // Overall minimum level
transport: {
targets: targets
}
});
// Initialize pino-http middleware
const httpLogger = pinoHttp({ logger });
// Define Relying Party details (Update with your actual details)
export const rpID = process.env.NODE_ENV === 'production' ? 'stylepoint.uk' : 'localhost';
export const rpName = 'StylePoint';
@ -39,9 +82,12 @@ const prisma = new PrismaClient();
const app = express();
// Add pino-http middleware
app.use(httpLogger);
if(!process.env.SESSION_SECRET)
{
console.error('SESSION_SECRET environment variable is not set. Please set it to a strong secret key.');
logger.error('SESSION_SECRET environment variable is not set. Please set it to a strong secret key.');
process.exit(1); // Exit the process if the secret is not set
}
@ -70,15 +116,14 @@ app.use(session({
// Run daily at 1:00 AM server time (adjust as needed)
cron.schedule('0 1 * * *', async() =>
{
console.log('Running scheduled Mantis summary task...');
try
{
await generateAndStoreMantisSummary();
console.log('Scheduled Mantis summary task completed.');
logger.info('Scheduled Mantis summary task completed successfully.');
}
catch (error)
{
console.error('Error running scheduled Mantis summary task:', error);
logger.error({ error }, 'Error running scheduled Mantis summary task');
}
}, {
scheduled: true,
@ -108,5 +153,5 @@ app.use(express.static('public', { index: false }));
app.listen(8000, () =>
{
console.log('Server is running on http://localhost:8000');
logger.info('Server is running on http://localhost:8000');
});

View file

@ -113,16 +113,13 @@ export async function generateAndStoreMantisSummary()
if (tickets.length === 0)
{
summaryText = 'No Mantis tickets updated recently.';
console.log('No recent Mantis tickets found.');
}
else
{
console.log(`Found ${tickets.length} recent Mantis tickets. Generating summary...`);
let prompt = promptTemplate.replaceAll('$DATE', new Date().toISOString().split('T')[0]);
prompt = prompt.replaceAll('$MANTIS_TICKETS', JSON.stringify(tickets, null, 2));
summaryText = await askGemini(prompt);
console.log('Mantis summary generated successfully by AI.');
}
// Store the summary in the database using Prisma upsert
@ -139,7 +136,6 @@ export async function generateAndStoreMantisSummary()
summaryText: summaryText,
},
});
console.log(`Mantis summary for ${today.toISOString().split('T')[0]} stored/updated in the database.`);
}
catch (error)

View file

@ -10,8 +10,6 @@ export async function askGemini(content)
const GOOGLE_API_KEY = await getSetting('GEMINI_API_KEY');
console.log('Google API Key:', GOOGLE_API_KEY); // Debugging line to check the key
if (!GOOGLE_API_KEY)
{
throw new Error('Google API key is not set in the database.');

View file

@ -0,0 +1,47 @@
import { PrismaClient } from '@prisma/client';
import build from 'pino-abstract-transport';
const prisma = new PrismaClient();
export default async function(opts)
{
return build(async(source) =>
{
for await (const obj of source)
{
try
{
const { time, level, msg, ...meta } = obj;
// Pino levels are numeric, convert to string names if needed
const levelMap = {
'10': 'trace',
'20': 'debug',
'30': 'info',
'40': 'warn',
'50': 'error',
'60': 'fatal'
};
const levelString = levelMap[level] || 'info'; // Default to info
await prisma.log.create({
data: {
timestamp: new Date(time),
level: levelString,
message: msg,
// Store remaining properties in the meta field if it exists
meta: Object.keys(meta).length > 0 ? meta : undefined,
},
});
}
catch (error)
{
console.error('Failed to write log to database:', error);
}
}
}, {
async close(err)
{
await prisma.$disconnect();
}
});
}