UNPKG

web-analyst

Version:

Web Analyst is a simple back-end tracking system to measure your web app performance.

475 lines (391 loc) 12.7 kB
const { getHitLogsPath, getLineStats, getHeaders, TABLE_SEPARATOR, buildStatsDirectory, } = require("./utils/core.cjs"); const {createWriteStream, writeFileSync, readFileSync, existsSync} = require("fs"); const { addIpInformationToMapper, buildIPIndexer, updateIPFile, buildTokenIndexer, updateTokenFile, addTokenInformationToMapper, getRegisteredInfoIP, getRegisteredInfoToken } = require("./builders/indexers/map-ips.cjs"); const {generateTodayChartData, saveTodayFile, updateTodayContent} = require("./builders/bars/today-chart.cjs"); const {generateWeekChartData, saveWeekFile, updateWeekContent} = require("./builders/bars/week-chart.cjs"); const {generateYearChartData, saveYearFile, updateYearContent} = require("./builders/bars/year-chart.cjs"); const {generateBrowserPopularityDataFromIndexer, saveBrowserIndexer} = require("./builders/pies/browsers-charts.cjs"); const { buildBrowserIndexer, addToBrowserIndexer, updateBrowserIndexer } = require("./builders/indexers/map-browsers.cjs"); const {buildOSIndexer, updateOSIndexer, addToOSIndexer} = require("./builders/indexers/map-oses.cjs"); const { buildLanguageIndexer, updateLanguageIndexer, addToLanguageIndexer } = require("./builders/indexers/map-languages.cjs"); const { buildReferrerIndexer, updateReferrerIndexer, addToReferrerIndexer } = require("./builders/indexers/map-referers.cjs"); const {saveOsesIndexer, generateOsesPopularityDataFromIndexer} = require("./builders/pies/oses-charts.cjs"); const { saveLanguagesIndexer, generateLanguagesPopularityDataFromIndexer } = require("./builders/pies/languages-charts.cjs"); const { buildEndpointIndexer, addToEndpointIndexer, updateEndpointIndexer } = require("./builders/indexers/map-endpoints.cjs"); const { generateEndpointPopularityDataFromIndexer, saveEndpointIndexer } = require("./builders/tables/endpoints-chart.cjs"); const {generateMoneyChartData, saveEarningFile, updateMoneyContent} = require("./builders/bars/money-chart.cjs"); const {isPagePattern} = require("./utils/patterns.cjs"); const { generateReferrerPopularityDataFromIndexer, saveReferrerIndexer } = require("./builders/tables/referers-chart.cjs"); let hitsLogStream = null; /** * * @type {string[]} */ let hits = []; /** * * @param ip * @param acceptLanguage * @param acceptLanguage * @param userAgent * @param pathname * @param search * @param referer * @param cookieData * @param clientSideData * @returns {string|null} */ const convertHitToString = function ({ip, acceptLanguage, userAgent, pathname, search, referer, cookieData, clientSideData}) { try { return getLineStats({ ip, acceptLanguage, userAgent, search, pathname, referer, cookieData, ...clientSideData }); } catch (e) { console.error({lid: "WA2117"}, e.message); } return null; }; /** * Returns lines from log file * @returns {string[]} */ const getHitLines = () => { try { const filepath = getHitLogsPath(); const content = readFileSync(filepath, {encoding: "utf8"}); return content.split("\n"); } catch (e) { console.error({lid: "WA2263"}, e.message); } return []; }; const resetHitFile = function () { try { const hitsLogPath = getHitLogsPath(); const strTitles = getHeaders(); writeFileSync(hitsLogPath, strTitles + "\n", {encoding: "utf8"}); return true; } catch (e) { console.error({lid: "WA2285"}, e.message); } return false; }; const getHitColumnNames = () => { const lines = getHitLines(); const line = lines[0]; const columnNames = line.split(TABLE_SEPARATOR); for (let i = 0; i < columnNames.length; ++i) { columnNames[i] = columnNames[i].trim(); } return columnNames; }; /** * Add new lines of information to the hit log file {@link MEANINGFUL_LOG_FILES.HITS_LOG_FILENAME} * @param {*[]} hitList * @returns {boolean} */ function addHitsToLogFile(hitList) { try { if (!hitList) { return false; } const data = hitList.join("\n").trim(); if (!data) { return true; } hitsLogStream.write(data + "\n"); // Reinitialise list hits.length = 0; return true; } catch (e) { console.error({lid: "WA2451"}, e.message); } return false; } /** * Convert the log file of hits to an array of objects * @returns {HIT_TYPE[]|null} */ const getHitList = () => { try { const titles = getHitColumnNames(); const lines = getHitLines().slice(1); const newLines = []; for (let i = 0; i < lines.length; ++i) { const obj = {}; const line = lines[i]; if (!line) { continue; } const columns = line.split(TABLE_SEPARATOR); for (let ii = 0; ii < titles.length; ++ii) { const columnName = titles[ii]; const columnValue = columns[ii] || ""; obj[columnName] = columnValue.trim(); } newLines.push(obj); } return newLines; } catch (e) { console.error({lid: "WA2845"}, e.message); } return null; }; const buildHitLogFile = function () { try { // Create hits.log const hitsLogPath = getHitLogsPath(); if (!existsSync(hitsLogPath)) { writeFileSync(hitsLogPath, "", {encoding: "utf8"}); } let content = readFileSync(hitsLogPath, {encoding: "utf8"}) || ""; const strCurrentTitles = content.split("\n")[0]; const strTitles = getHeaders(); if (strCurrentTitles !== strTitles) { if (content) { content = strTitles + "\n" + content + "\n"; } else { content = strTitles + "\n"; } writeFileSync(hitsLogPath, content, {encoding: "utf8"}); } return true; } catch (e) { console.error({lid: "WA2445"}, e.message); } return false; }; /** * Build Today data for #today div * @returns {boolean} * @param cookieData * @param clientSideData */ const updateChartFiles = function ({cookieData = null, clientSideData = null} = {}) { try { const hitList = getHitList(); for (let i = 0; i < hitList.length; ++i) { const lineObj = hitList[i]; const pathname = lineObj.pathname; if (!isPagePattern(pathname)) { continue; } let info; if (cookieData) { info = getRegisteredInfoToken(cookieData.token); } if (!info) { info = getRegisteredInfoIP(lineObj.ip); } updateTodayContent(lineObj, cookieData, info); updateWeekContent(lineObj, cookieData, info); updateYearContent(lineObj, cookieData, info); if (cookieData) { addTokenInformationToMapper(cookieData.token, lineObj.ip, clientSideData); } addIpInformationToMapper(lineObj.ip); } saveTodayFile(); saveWeekFile(); saveYearFile(); updateTokenFile(); updateIPFile(); resetHitFile(); return true; } catch (e) { console.error({lid: "WA2411"}, e.message); } return false; }; /** * Build indexer files * @returns {boolean|*[]} */ const updateIndexers = function () { try { // Create empty indexers if necessary buildBrowserIndexer(); buildOSIndexer(); buildLanguageIndexer(); buildReferrerIndexer(); buildEndpointIndexer(); const hitList = getHitList(); for (let i = 0; i < hitList.length; ++i) { const lineObj = hitList[i]; addToBrowserIndexer(lineObj.userAgent); addToOSIndexer(lineObj.userAgent); addToLanguageIndexer(lineObj.acceptLanguage); addToEndpointIndexer(lineObj.pathname); addToReferrerIndexer(lineObj.referer); } updateBrowserIndexer(); updateOSIndexer(); updateLanguageIndexer(); updateEndpointIndexer(); updateReferrerIndexer(); return true; } catch (e) { console.error({lid: "WA2411"}, e.message); } return false; }; function updatePieChartsType() { try { // Parse log entries to populate browser, os and language map files updateIndexers(); generateBrowserPopularityDataFromIndexer(); generateOsesPopularityDataFromIndexer(); generateLanguagesPopularityDataFromIndexer(); generateEndpointPopularityDataFromIndexer(); generateReferrerPopularityDataFromIndexer(); saveBrowserIndexer(); saveOsesIndexer(); saveLanguagesIndexer(); saveEndpointIndexer(); saveReferrerIndexer(); return true; } catch (e) { console.error({lid: "WA2975"}, e.message); } return false; } /** * * @param {*} cookieData * @param {*} clientSideData * @returns {boolean} */ function updateBarChartsType({cookieData = null, clientSideData = null} = {}) { try { // Create the file to reference ips buildIPIndexer(); buildTokenIndexer(); // Parse log entries to populate chart files generateTodayChartData(); generateWeekChartData(); generateYearChartData(); generateMoneyChartData(); // Update all json files updateChartFiles({cookieData, clientSideData}); return true; } catch (e) { console.error({lid: "WA2271"}, e.message); } return false; } /** * Add hit data to the hit list and the log file * @param ip * @param acceptLanguage * @param userAgent * @param pathname * @param search * @param referer * @param cookieData Cookie to help determine whether visitors are returning ones * @param clientSideData * @param options GenServe options * @returns {boolean} */ const registerHit = function ({ip, acceptLanguage, userAgent, pathname, search, referer, cookieData, clientSideData = {}, options}) { try { const lineStats = convertHitToString({ ip, acceptLanguage, userAgent, pathname, search, referer, cookieData, clientSideData }); // Register hit in array hits.push(lineStats); // Register the hit in a plain log file addHitsToLogFile(hits); if (!options.hideEarningCharts) { // Update earnings updateMoneyContent({ ip, acceptLanguage, userAgent, pathname, search, }); saveEarningFile(); } updatePieChartsType(); updateBarChartsType({cookieData, clientSideData}); return true; } catch (e) { console.error({lid: "WA2545"}, e.message); } return false; }; /** * Build Statistic Web directory and data directory * @param server * @param namespace * @param action * @returns {boolean} */ const startLogEngine = function (server, namespace, action) { try { // Create directory for server buildStatsDirectory(server, namespace); // Create the hit log file buildHitLogFile(); const hitsLogPath = getHitLogsPath(); hitsLogStream = createWriteStream(hitsLogPath, {flags: "a"}); if (action === "initialisation") { return true; } updatePieChartsType(); updateBarChartsType(); return true; } catch (e) { console.error({lid: "WA2113"}, e.message); } return false; }; module.exports.convertToHitObject = convertHitToString; module.exports.registerHit = registerHit; module.exports.startLogEngine = startLogEngine; module.exports.resetHitFile = resetHitFile;