Improve verbose mode logging

- Support passing a log message function to `logging.log` for lazy
  evaluation
- Log results (or at least lengths) of all API functions
- Log merged config during initialisation
- Log distance calculation duration
This commit is contained in:
Linus Groh
2020-03-07 00:22:56 +00:00
parent 1482833e05
commit b3fdf1eabe
6 changed files with 86 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
import { log, logLevels } from "@/logging";
import { getApiUrl } from "@/util";
import { getApiUrl, getLocationHistoryCount } from "@/util";
/**
* Fetch an API resource.
@@ -24,6 +24,7 @@ export const getVersion = async () => {
const response = await fetchApi("/api/0/version");
const json = await response.json();
const version = json.version;
log("API", () => `[getVersion] ${version}`);
return version;
};
@@ -36,6 +37,7 @@ export const getUsers = async () => {
const response = await fetchApi("/api/0/list");
const json = await response.json();
const users = json.results;
log("API", () => `[getUsers] Fetched ${users.length} users`);
return users;
};
@@ -56,6 +58,15 @@ export const getDevices = async users => {
devices[user] = userDevices;
})
);
log("API", () => {
const devicesCount = Object.keys(devices)
.map(user => devices[user].length)
.reduce((a, b) => a + b, 0);
return (
`[getDevices] Fetched ${devicesCount} ` +
`devices for ${users.length} users`
);
});
return devices;
};
@@ -76,7 +87,12 @@ export const getLastLocations = async (user, device) => {
}
const response = await fetchApi("/api/0/last", params);
const json = await response.json();
return json;
const lastLocations = json;
log(
"API",
() => `[getLastLocations] Fetched ${lastLocations.length} last locations`
);
return lastLocations;
};
/**
@@ -102,7 +118,15 @@ export const getUserDeviceLocationHistory = async (
format: "json",
});
const json = await response.json();
return json.data;
const userDeviceLocationHistory = json.data;
log(
"API",
() =>
`[getUserDeviceLocationHistory] Fetched ` +
`${userDeviceLocationHistory.length} locations for ` +
`${user}/${device} from ${start} - ${end}`
);
return userDeviceLocationHistory;
};
/**
@@ -131,6 +155,13 @@ export const getLocationHistory = async (devices, start, end) => {
);
})
);
log("API", () => {
const locationHistoryCount = getLocationHistoryCount(locationHistory);
return (
"[getLocationHistory] Fetched " +
`${locationHistoryCount} locations in total`
);
});
return locationHistory;
};

3
src/index.d.ts vendored
View File

@@ -204,6 +204,9 @@ interface QueryParams {
/** Callback for new WebSocket location messages. */
interface WebSocketLocationCallback { (): void }
/** Function for lazy evaluation of log messages. */
interface LogMessageFunction { (): string }
/** A CSS color. */
type Color = string;

View File

@@ -20,6 +20,16 @@ const logColors = {
[logLevels.ERROR]: "#ad1515",
};
/**
* Log a message to the browser's console.
*
* Convenience wrapper for `console.{info,warn,error}` doing some formatting
* and taking the `verbose` config option into account.
*
* @param {String} label Log message label, useful for filtering
* @param {String|LogMessageFunction} message Log message
* @param {String} [level] Log level, use `logLevels` constants
*/
export const log = (label, message, level = logLevels.INFO) => {
if (!Object.keys(logLevels).includes(level)) {
log("WARNING", `invalid log level: ${level}`, logLevels.WARNING);
@@ -35,5 +45,9 @@ export const log = (label, message, level = logLevels.INFO) => {
padding: 3px;
`;
const logFunc = logFunctions[level];
logFunc(`%c${label}`, css, message);
logFunc(
`%c${label}`,
css,
typeof message === "function" ? message() : message
);
};

View File

@@ -1,6 +1,7 @@
import Vue from "vue";
import App from "@/App.vue";
import config from "@/config";
import { log } from "@/logging";
import i18n from "@/i18n";
import router from "@/router";
import store from "@/store";
@@ -12,6 +13,8 @@ Vue.use(VOutsideEvents);
Vue.config.productionTip = false;
log("CONFIG", config);
Vue.prototype.$config = config;
new Vue({

View File

@@ -1,7 +1,12 @@
import * as types from "@/store/mutation-types";
import * as api from "@/api";
import config from "@/config";
import { distanceBetweenCoordinates, isIsoDateTime } from "@/util";
import { log } from "@/logging";
import {
distanceBetweenCoordinates,
isIsoDateTime,
getLocationHistoryCount,
} from "@/util";
/**
* Populate the state from URL query parameters.
@@ -118,6 +123,7 @@ const getLastLocations = async ({ commit, state }) => {
};
const _getDistanceTravelled = locationHistory => {
const start = Date.now();
let distanceTravelled = 0;
Object.keys(locationHistory).forEach(user => {
Object.keys(locationHistory[user]).forEach(device => {
@@ -143,6 +149,15 @@ const _getDistanceTravelled = locationHistory => {
});
});
});
const end = Date.now();
log("DISTANCE", () => {
const locationHistoryCount = getLocationHistoryCount(locationHistory);
const duration = (end - start) / 1000;
return (
`[_getDistanceTravelled] Took ${duration} seconds to ` +
`calculate distance of ${locationHistoryCount} locations`
);
});
return distanceTravelled;
};

View File

@@ -101,3 +101,18 @@ export const humanReadableDistance = distance => {
maximumFractionDigits: 1,
})} ${unit}`;
};
/**
* Get the total number of locations from a nested location history.
*
* @param {LocationHistory} locationHistory Location history
* @returns {Number} Total number of locations
*/
export const getLocationHistoryCount = locationHistory =>
Object.keys(locationHistory)
.map(user =>
Object.keys(locationHistory[user])
.map(device => locationHistory[user][device].length)
.reduce((a, b) => a + b, 0)
)
.reduce((a, b) => a + b, 0);