using winston logger

This commit is contained in:
orangecoding
2025-09-13 18:57:56 +02:00
parent e868cdce86
commit 21415dcff3
19 changed files with 230 additions and 49 deletions

View File

@@ -3,6 +3,7 @@ import { setKnownListings, getKnownListings } from './services/storage/listingsS
import * as notify from './notification/notify.js';
import Extractor from './services/extractor/extractor.js';
import urlModifier from './services/queryStringMutator.js';
import logger from './services/logger.js';
class FredyRuntime {
/**
@@ -59,7 +60,7 @@ class FredyRuntime {
})
.catch((err) => {
reject(err);
console.error(err);
logger.error(err);
});
});
}
@@ -104,9 +105,7 @@ class FredyRuntime {
const filteredList = listings.filter((listing) => {
const similar = this._similarityCache.hasSimilarEntries(listing.title, listing.address);
if (similar) {
/* eslint-disable no-console */
console.debug(`Filtering similar entry for title: ${listing.title} and address ${listing.address}`);
/* eslint-enable no-console */
logger.debug(`Filtering similar entry for title: ${listing.title} and address ${listing.address}`);
}
return !similar;
});
@@ -115,7 +114,7 @@ class FredyRuntime {
}
_handleError(err) {
if (err.name !== 'NoNewListingsWarning') console.error(err);
if (err.name !== 'NoNewListingsWarning') logger.error(err);
}
}

View File

@@ -13,6 +13,7 @@ import files from 'serve-static';
import path from 'path';
import { getDirName } from '../utils.js';
import { demoRouter } from './routes/demoRouter.js';
import logger from '../services/logger.js';
const service = restana();
const staticService = files(path.join(getDirName(), '../ui/public'));
const PORT = config.port || 9998;
@@ -34,7 +35,6 @@ service.use('/api/login', loginRouter);
//this route is unsecured intentionally as it is being queried from the login page
service.use('/api/demo', demoRouter);
/* eslint-disable no-console */
service.start(PORT).then(() => {
console.info(`Started API service on port ${PORT}`);
logger.debug(`Started API service on port ${PORT}`);
});

View File

@@ -2,6 +2,7 @@ import restana from 'restana';
import { config, getDirName, readConfigFromStorage, refreshConfig } from '../../utils.js';
import fs from 'fs';
import { handleDemoUser } from '../../services/storage/userStorage.js';
import logger from '../../services/logger.js';
const service = restana();
const generalSettingsRouter = service.newRouter();
generalSettingsRouter.get('/', async (req, res) => {
@@ -20,7 +21,7 @@ generalSettingsRouter.post('/', async (req, res) => {
await refreshConfig();
handleDemoUser();
} catch (err) {
console.error(err);
logger.error(err);
res.send(new Error('Error while trying to write settings.'));
return;
}

View File

@@ -3,6 +3,7 @@ import * as jobStorage from '../../services/storage/jobStorage.js';
import * as userStorage from '../../services/storage/userStorage.js';
import { config } from '../../utils.js';
import { isAdmin } from '../security.js';
import logger from '../../services/logger.js';
const service = restana();
const jobRouter = service.newRouter();
function doesJobBelongsToUser(job, req) {
@@ -43,7 +44,7 @@ jobRouter.post('/', async (req, res) => {
});
} catch (error) {
res.send(new Error(error));
console.error(error);
logger.error(error);
}
res.send();
});
@@ -58,7 +59,7 @@ jobRouter.delete('', async (req, res) => {
}
} catch (error) {
res.send(new Error(error));
console.error(error);
logger.error(error);
}
res.send();
});
@@ -77,7 +78,7 @@ jobRouter.put('/:jobId/status', async (req, res) => {
}
} catch (error) {
res.send(new Error(error));
console.error(error);
logger.error(error);
}
res.send();
});

View File

@@ -3,6 +3,7 @@ import * as userStorage from '../../services/storage/userStorage.js';
import * as hasher from '../../services/security/hash.js';
import { config } from '../../utils.js';
import { trackDemoAccessed } from '../../services/tracking/Tracker.js';
import logger from '../../services/logger.js';
const service = restana();
const loginRouter = service.newRouter();
loginRouter.get('/user', async (req, res) => {
@@ -35,7 +36,7 @@ loginRouter.post('/', async (req, res) => {
res.send(200);
return;
} else {
console.error(`User ${username} tried to login, but password was wrong.`);
logger.error(`User ${username} tried to login, but password was wrong.`);
}
res.send(401);
});

View File

@@ -5,6 +5,7 @@ import Handlebars from 'handlebars';
import fetch from 'node-fetch';
import { markdown2Html } from '../../services/markdown.js';
import { getDirName, normalizeImageUrl } from '../../utils.js';
import logger from '../../services/logger.js';
const __dirname = getDirName();
const template = fs.readFileSync(path.resolve(__dirname + '/notification/emailTemplate/template.hbs'), 'utf8');
@@ -24,7 +25,7 @@ const toBase64 = async (url) => {
const ab = await res.arrayBuffer();
return Buffer.from(ab).toString('base64');
} catch (error) {
console.error(`Error fetching image from ${url}:`, error.message);
logger.error(`Error fetching image from ${url}:`, error.message);
throw error;
}
};
@@ -62,7 +63,7 @@ const mapListingsWithCid = async (serviceName, jobKey, listings) => {
item.hasImage = true;
item.imageCid = cid;
} catch (error) {
console.warn(`Skipping image for listing ${i} due to error: ${error.message}`);
logger.warn(`Skipping image for listing ${i} due to error: ${error.message}`);
}
}

View File

@@ -37,6 +37,7 @@
import utils, { buildHash } from '../utils.js';
import { convertWebToMobile } from '../services/immoscout/immoscout-web-translator.js';
import logger from '../services/logger.js';
let appliedBlackList = [];
async function getListings(url) {
@@ -52,7 +53,7 @@ async function getListings(url) {
}),
});
if (!response.ok) {
console.error('Error fetching data from ImmoScout Mobile API:', response.statusText);
logger.error('Error fetching data from ImmoScout Mobile API:', response.statusText);
return [];
}

View File

@@ -2,6 +2,7 @@ import { setInterval } from 'node:timers';
import { removeJobsByUserName } from './storage/jobStorage.js';
import { config } from '../utils.js';
import { getUsers } from './storage/userStorage.js';
import logger from './logger.js';
/**
* if we are running in demo environment, we have to cleanup the db files (specifically the jobs table)
@@ -29,7 +30,7 @@ function cleanup() {
if (config.demoMode) {
const demoUser = getUsers(false).find((user) => user.username === 'demo');
if (demoUser == null) {
console.error('Demo user not found, cannot remove Jobs');
logger.error('Demo user not found, cannot remove Jobs');
return;
}
removeJobsByUserName(demoUser.id);

View File

@@ -1,6 +1,7 @@
import { setDebug } from './utils.js';
import puppeteerExtractor from './puppeteerExtractor.js';
import { loadParser, parse } from './parser/parser.js';
import logger from '../logger.js';
const DEFAULT_OPTIONS = {
debug: false,
@@ -32,7 +33,7 @@ export default class Extractor {
loadParser(this.responseText);
}
} catch (error) {
console.error('Error trying to load page.', error);
logger.error('Error trying to load page.', error);
}
return this;
};

View File

@@ -1,4 +1,5 @@
import * as cheerio from 'cheerio';
import logger from '../../logger.js';
let $ = null;
@@ -8,19 +9,19 @@ export function loadParser(text) {
export function parse(crawlContainer, crawlFields, text, url) {
if (!text) {
console.warn('No content found for ', url);
logger.warn('No content found for ', url);
return null;
}
if (!crawlContainer || !crawlFields) {
console.warn('Cannot parse, selector was empty for url ', url);
logger.warn('Cannot parse, selector was empty for url ', url);
return null;
}
const result = [];
if ($(crawlContainer).length === 0) {
console.warn('No elements in crawl container found for url ', url);
logger.warn('No elements in crawl container found for url ', url);
return null;
}
@@ -58,7 +59,7 @@ export function parse(crawlContainer, crawlFields, text, url) {
parsedObject[key] = value || null;
} catch (error) {
console.error(`Error parsing field '${key}' with selector '${fieldSelector}':`, error);
logger.error(`Error parsing field '${key}' with selector '${fieldSelector}':`, error);
parsedObject[key] = null;
}
}
@@ -66,9 +67,7 @@ export function parse(crawlContainer, crawlFields, text, url) {
if (parsedObject.id != null) {
result.push(parsedObject);
} else {
/* eslint-disable no-console */
console.debug('ID not found. Not relaying object.');
/* eslint-enable no-console */
logger.debug('ID not found. Not relaying object.');
}
});
@@ -91,7 +90,7 @@ function applyModifiers(value, modifiers) {
value = value.replace(/\n/g, ' ');
break;
default:
console.warn(`Unknown modifier: ${modifier}`);
logger.warn(`Unknown modifier: ${modifier}`);
}
});

View File

@@ -1,6 +1,7 @@
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import { debug, DEFAULT_HEADER, botDetected } from './utils.js';
import logger from '../logger.js';
puppeteer.use(StealthPlugin());
@@ -33,13 +34,13 @@ export default async function execute(url, waitForSelector, options) {
const statusCode = response.status();
if (botDetected(pageSource, statusCode)) {
console.warn('We have been detected as a bot :-/ Tried url: => ', url);
logger.warn('We have been detected as a bot :-/ Tried url: => ', url);
return null;
}
return await page.content();
} catch (error) {
console.error('Error executing with puppeteer executor', error);
logger.error('Error executing with puppeteer executor', error);
return null;
} finally {
if (browser != null) {

View File

@@ -1,3 +1,5 @@
import logger from '../logger.js';
let debuggingOn = false;
export const DEFAULT_HEADER = {
@@ -15,9 +17,7 @@ export const setDebug = (options) => {
export const debug = (message) => {
if (debuggingOn) {
/* eslint-disable no-console */
console.debug(message);
/* eslint-enable no-console */
logger.debug(message);
}
};

15
lib/services/logger.js Normal file
View File

@@ -0,0 +1,15 @@
import winston from 'winston';
const env = process.env.NODE_ENV || 'development';
const logger = winston.createLogger({
level: env !== 'development' ? 'info' : 'debug',
format: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf(({ timestamp, level, message }) => `[${timestamp}] ${level}: ${message}`),
),
transports: [new winston.transports.Console()],
});
export default logger;

View File

@@ -4,6 +4,7 @@ import * as listingStorage from './listingsStorage.js';
import { getDirName } from '../../utils.js';
import path from 'path';
import LowdashAdapter from './LowDashAdapter.js';
import logger from '../logger.js';
const file = path.join(getDirName(), '../', 'db/jobs.json');
const adapter = new JSONFileSync(file);
@@ -91,9 +92,7 @@ export const removeJobsByUserName = (userId) => {
.value();
db.write();
if (removedDemoJobs > 0) {
/* eslint-disable no-console */
console.log(`Removed ${removedDemoJobs} demo jobs`);
/* eslint-enable no-console */
logger.info(`Removed ${removedDemoJobs} demo jobs`);
}
};
export const getJobs = () => {

View File

@@ -5,6 +5,7 @@ import os from 'os';
import { readFileSync } from 'fs';
import { packageUp } from 'package-up';
import fetch from 'node-fetch';
import logger from '../logger.js';
const deviceId = getUniqueId() || 'N/A';
const version = await getPackageVersion();
@@ -37,7 +38,7 @@ export const trackMainEvent = async () => {
}
}
} catch (error) {
console.warn('Error sending tracking data', error);
logger.warn('Error sending tracking data', error);
}
};
@@ -52,7 +53,7 @@ export async function trackDemoAccessed() {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.warn('Error sending tracking data', error);
logger.warn('Error sending tracking data', error);
}
}
}
@@ -84,7 +85,7 @@ async function getPackageVersion() {
const json = JSON.parse(packageJson);
return json.version;
} catch (error) {
console.error('Error reading version from package.json', error);
logger.error('Error reading version from package.json', error);
}
return 'N/A';
}

View File

@@ -4,6 +4,7 @@ import { readFile } from 'fs/promises';
import { createHash } from 'crypto';
import { DEFAULT_CONFIG } from './defaultConfig.js';
import fs from 'fs';
import logger from './services/logger.js';
const RE_GT = />/g;
const RE_WEBP = /\/format\/webp/gi;
@@ -74,8 +75,7 @@ export async function refreshConfig() {
config.demoMode ??= false;
} catch (error) {
config = { ...DEFAULT_CONFIG };
/* eslint-disable no-console */
console.info('Error reading config file.', error);
logger.info('Error reading config file.', error);
}
}
@@ -84,7 +84,7 @@ export async function refreshConfig() {
*/
const checkIfConfigExistsAndWriteIfNot = () => {
if (!fs.existsSync(`${getDirName()}/../conf/config.json`)) {
console.info('Could not find config file. Will create one with default values now');
logger.info('Could not find config file. Will create one with default values now');
fs.writeFileSync(`${getDirName()}/../conf/config.json`, JSON.stringify({ ...DEFAULT_CONFIG }));
}
};