/* ---------------------------------------------------------------------------- Question Server GitLab: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ------------------------------------------------------------------------- */ const hr = '---------------------------------------------------------------------------------' module.exports = { GetDateString: GetDateString, Log: Log, DebugLog: DebugLog, GetColor: GetColor, LogReq: LogReq, LogStat: LogStat, Load: Load, logHashed: logHashed, hr: hr, C: C, setNewLogfileName, } const DELIM = C('green') + '|' + C() const utils = require('../utils/utils.js') const vlogDir = './stats/vlogs/' const logDir = './stats/logs/' const statFile = 'stats/stats' const vStatFile = 'stats/vstats' const uStatsFile = 'stats/ustats' const uvStatsFile = 'stats/uvstats' const nologFile = './nolog' const colors = ['green', 'red', 'yellow', 'blue', 'magenta', 'cyan'] var logFileName = utils.GetDateString(true) const writeInterval = 10 const debugLevel = parseInt(process.env.NS_LOGLEVEL) || 0 let data = {} // visit data let vData = {} // visit data, but daily let uData = {} // visit data, but per user let uvData = {} // visit data, but per user and daily let writes = 0 let noLogips = [] function setNewLogfileName() { logFileName = utils.GetDateString(true) } function GetDateString() { const date = new Date() const dateString = utils.GetDateString() return GetRandomColor(date.getHours().toString()) + dateString + C() } function DebugLog(msg, name, lvl) { if (lvl <= debugLevel) { if (msg === 'hr') { msg = hr } let s = msg let header = `${C('red')}#DEBUG${lvl}#${C( 'yellow' )}${name.toUpperCase()}${C('red')}#${C()}${DELIM}${C()}` if (typeof msg !== 'object') { s = header + msg } else { Log(header + 'OBJECT:', 'yellow') s = msg } Log(s, 'yellow') } } function Log(s, c) { let log = s if (typeof s !== 'object') { let dl = DELIM + C(c) log = C(c) + GetDateString() + dl + s + C() } console.log(log) utils.AppendToFile(log, logDir + logFileName) } function LogReq(req, toFile, sc) { try { let ip = req.headers['cf-connecting-ip'] || req.connection.remoteAddress let nolog = noLogips.some((x) => { return ip.includes(x) }) if (nolog) { return } let logEntry = GetRandomColor(ip) + ip + C() let dl = DELIM if (req.url.includes('lred')) { dl += C('red') } let hostname if (req.hostname) { hostname = req.hostname.replace('www.', '').split('.')[0] } else { hostname = 'NOHOST' Log( 'req.hostname is undefined! req.hostname: ' + req.hostname, GetColor('redbg') ) } logEntry += dl + hostname + dl + req.headers['user-agent'] + dl + req.method + dl if (req.session && req.session.user) { logEntry += C('cyan') + req.session.user.id + C() + dl } else if (req.session && req.session.isException === true) { logEntry += C('cyan') + 'EX' + C() + dl } else { logEntry += C('red') + 'NOUSER' + C() + dl } logEntry += GetRandomColor(req.url.split('?')[0]) + req.url if (sc !== undefined) { logEntry += dl + sc } logEntry += C() if (!toFile) { Log(logEntry) } else { let defLogs = GetDateString() + dl + logEntry utils.AppendToFile(defLogs, vlogDir + logFileName) } } catch (err) { console.log(err) Log('Error at logging lol', GetColor('redbg'), true) } } function parseNoLogFile(newData) { noLogips = newData.split('\n') if (noLogips[noLogips.length - 1] === '') { noLogips.pop() } noLogips = noLogips.filter((x) => { return x !== '' }) Log('\tNo Log IP-s changed: ' + noLogips.join(', ')) } function setNoLogReadInterval() { utils.WatchFile(nologFile, (newData) => { parseNoLogFile(newData) }) parseNoLogFile(utils.ReadFile(nologFile)) } function Load() { Log('Loading logger...') try { uData = JSON.parse(utils.ReadFile(uStatsFile)) } catch (e) { Log('Error at loading logs! (@ first run its normal)', GetColor('redbg')) console.log(e) } try { uvData = JSON.parse(utils.ReadFile(uvStatsFile)) } catch (e) { Log('Error at loading logs! (@ first run its normal)', GetColor('redbg')) console.log(e) } try { var prevData = utils.ReadFile(statFile) data = JSON.parse(prevData) } catch (e) { Log('Error at loading logs! (@ first run its normal)', GetColor('redbg')) console.log(e) } try { var prevVData = utils.ReadFile(vStatFile) vData = JSON.parse(prevVData) } catch (e) { Log( 'Error at loading visit logs! (@ first run its normal)', GetColor('redbg') ) console.log(e) } setNoLogReadInterval() } function LogStat(url, ip, hostname, userId) { let nolog = noLogips.some((x) => { return x.includes(ip) }) if (nolog) { return } url = hostname + url.split('?')[0] Inc(url) AddUserIdStat(userId) IncUserStat(userId) AddVisitStat(url) Save() } function IncUserStat(userId) { try { if (uData[userId] === undefined) { uData[userId] = 0 } uData[userId]++ } catch (e) { Log('Error at making user ID stats!', GetColor('redbg')) console.error(e) } } function AddUserIdStat(userId) { try { var m = new Date() const now = m.getFullYear() + '-' + ('0' + (m.getMonth() + 1)).slice(-2) + '-' + ('0' + m.getDate()).slice(-2) if (uvData[now] === undefined) { uvData[now] = {} } if (uvData[now][userId] === undefined) { uvData[now][userId] = 0 } uvData[now][userId]++ } catch (e) { Log('Error at making user ID stats!', GetColor('redbg')) console.error(e) } } function Inc(value) { if (value.startsWith('/?')) { value = '/' } if (data[value] === undefined) { data[value] = 0 } data[value]++ } function AddVisitStat(name) { var m = new Date() const now = m.getFullYear() + '-' + ('0' + (m.getMonth() + 1)).slice(-2) + '-' + ('0' + m.getDate()).slice(-2) if (vData[now] === undefined) { vData[now] = {} } if (vData[now][name] === undefined) { vData[now][name] = 0 } vData[now][name]++ } function Save() { writes++ if (writes === writeInterval) { try { utils.WriteFile(JSON.stringify(uData), uStatsFile) } catch (e) { Log('Error at writing logs! (more in stderr)', GetColor('redbg')) console.error(e) } try { utils.WriteFile(JSON.stringify(uvData), uvStatsFile) } catch (e) { Log('Error at writing logs! (more in stderr)', GetColor('redbg')) console.error(e) } try { utils.WriteFile(JSON.stringify(data), statFile) // Log("Stats wrote."); } catch (e) { Log('Error at writing logs! (more in stderr)', GetColor('redbg')) console.error(e) } try { utils.WriteFile(JSON.stringify(vData), vStatFile) // Log("Stats wrote."); } catch (e) { Log('Error at writing visit logs! (more in stderr)', GetColor('redbg')) console.error(e) } writes = 0 } } function logHashed(x) { return GetRandomColor(x.toString()) + x + C() } function GetRandomColor(ip) { if (!ip) { return 'red' } let res = ip.split('').reduce((res, x) => { return res + x.charCodeAt(0) }, 0) return C(colors[res % colors.length]) } function GetColor(c) { return c } function C(c) { if (c !== undefined) { c = c.toLowerCase() } if (c === 'redbg') { return '\x1b[41m' } if (c === 'bluebg') { return '\x1b[44m' } if (c === 'green') { return '\x1b[32m' } if (c === 'red') { return '\x1b[31m' } if (c === 'yellow') { return '\x1b[33m' } if (c === 'blue') { return '\x1b[34m' } if (c === 'magenta') { return '\x1b[35m' } if (c === 'cyan') { return '\x1b[36m' } return '\x1b[0m' }