web: clean up logging usage, parameterize with ENV vars.

This commit is contained in:
Jonathan Bernard 2019-04-10 10:53:12 -05:00
parent 3154d97dd1
commit cc23676f9b
10 changed files with 75 additions and 25 deletions

View File

@ -4,6 +4,8 @@ import { logService, LogLevel, ApiLogAppender, ConsoleLogAppender } from '@/serv
import { authStore } from '@/store';
import { User } from '@/models';
const logger = logService.getLogger('/app');
@Component({
components: {
NavBar
@ -11,25 +13,12 @@ import { User } from '@/models';
})
export default class App extends Vue {
private consoleLogAppender: ConsoleLogAppender;
private apiLogAppender: ApiLogAppender;
private apiLogAppender!: ApiLogAppender;
private consoleLogAppender!: ConsoleLogAppender;
constructor() {
super();
// Setup application logging.
this.consoleLogAppender = new ConsoleLogAppender(LogLevel.ALL);
this.apiLogAppender = new ApiLogAppender(
process.env.VUE_APP_PM_API_BASE + '/log/batch', '', LogLevel.WARN);
logService.ROOT_LOGGER.appenders.push(this.apiLogAppender, this.consoleLogAppender);
// TODO: prod/dev config settings for logging?
this.apiLogAppender.batchSize = 1;
this.apiLogAppender.minimumTimePassedInSec = 5;
// Check for existing session cookie.
/*tslint:disable:no-empty*/
authStore.findLocalToken().catch(() => {});
this.configureLoggers();
}
private get authToken(): string | null {
@ -38,6 +27,55 @@ export default class App extends Vue {
@Watch('authToken')
private onAuthTokenChange(val: string | undefined , oldVal: string | undefined) {
// If the user wasn't logged in initially, or their session expires, we
// want to catch the new token for our API log appender.
if (val) { this.apiLogAppender.authToken = val; }
}
private configureLoggers(): void {
let commonLevel = LogLevel.WARN;
if (LogLevel.hasOwnProperty(process.env.VUE_APP_LOG_LEVEL)) {
commonLevel = (LogLevel[process.env.VUE_APP_LOG_LEVEL] as unknown) as LogLevel;
}
// Because modules like the router will start logging messages before this
// component is initialized, the console appender is initialized and added
// in main.ts
this.consoleLogAppender = logService.ROOT_LOGGER.appenders[0];
// We create the API log appender (need credentials anyways)
this.apiLogAppender = new ApiLogAppender(
process.env.VUE_APP_PM_API_BASE + '/log/batch',
this.authToken || '', // user may already be logged in and have a token
LogLevel.WARN);
logService.ROOT_LOGGER.appenders.push(this.apiLogAppender);
if (LogLevel.hasOwnProperty(process.env.VUE_APP_API_LOG_LEVEL)) {
this.apiLogAppender.threshold = (LogLevel[process.env.VUE_APP_API_LOG_LEVEL] as unknown) as LogLevel;
} else {
this.apiLogAppender.threshold = commonLevel;
}
if (LogLevel.hasOwnProperty(process.env.VUE_APP_CONSOLE_LOG_LEVEL)) {
this.consoleLogAppender.threshold = (LogLevel[process.env.VUE_APP_CONSOLE_LOG_LEVEL] as unknown) as LogLevel;
} else {
this.consoleLogAppender.threshold = commonLevel;
}
try {
this.apiLogAppender.batchSize =
parseInt(process.env.VUE_APP_API_LOG_BATCH_SIZE, 10);
} catch {
this.apiLogAppender.batchSize = 5;
}
try {
this.apiLogAppender.minimumTimePassedInSec
= parseInt(process.env.VUE_APP_API_LOG_MIN_TIME_PASSED_IN_SEC, 10);
} catch {
this.apiLogAppender.minimumTimePassedInSec = 5;
}
}
}

View File

@ -10,11 +10,15 @@ import SmartTable from 'vuejs-smart-table';
import ApexChart from 'vue-apexcharts';
import './registerServiceWorker';
import { logService, LogLevel, ApiLogAppender, ConsoleLogAppender } from '@/services/logging';
Vue.component('fa-icon', FontAwesomeIcon);
Vue.component('apex-chart', ApexChart);
Vue.use(SmartTable);
const consoleLogAppender = new ConsoleLogAppender(LogLevel.ALL);
logService.ROOT_LOGGER.appenders.push(consoleLogAppender);
new Vue({
router,
store,

View File

@ -15,13 +15,15 @@ export class ApiLogAppender implements LogAppender {
public batchSize = 10;
public minimumTimePassedInSec = 60;
public maximumTimePassedInSec = 120;
public threshold = LogLevel.ALL;
private http = Axios.create();
private msgBuffer: ApiMessage[] = [];
private lastSent = 0;
constructor(public readonly apiEndpoint: string, public authToken?: string, public threshold?: LogLevel) {
constructor(public readonly apiEndpoint: string, public authToken?: string, threshold?: LogLevel) {
setInterval(this.checkPost, 1000);
if (threshold) { this.threshold = threshold; }
}
public appendMessage(msg: LogMessage): void {

View File

@ -4,7 +4,11 @@ import Logger from './logger';
import LogAppender from './log-appender';
export class ConsoleLogAppender implements LogAppender {
constructor(public threshold?: LogLevel) {}
public threshold = LogLevel.ALL;
constructor(threshold?: LogLevel) {
if (threshold) { this.threshold = threshold; }
}
public appendMessage(msg: LogMessage): void {
if (this.threshold && msg.level < this.threshold) { return; }

View File

@ -1,5 +1,6 @@
import { LogLevel, LogMessage } from './log-message';
import Logger from './logger';
export default interface LogAppender {
threshold: LogLevel;
appendMessage(message: LogMessage): void;
}

View File

@ -1,4 +1,4 @@
export enum LogLevel { ALL = 0, DEBUG, LOG, INFO, WARN, ERROR, FATAL }
export enum LogLevel { ALL = 0, TRACE, DEBUG, LOG, INFO, WARN, ERROR, FATAL }
export interface LogMessage {
scope: string;

View File

@ -3,9 +3,10 @@ import assign from 'lodash.assign';
import { ApiToken, LoginSubmit, Measure, MeasureConfig, Measurement, MeasurementMeta, User } from '@/models';
import { Logger, logService } from '@/services/logging';
const logger = logService.getLogger('services/pm-api-client');
export class PmApiClient {
private http: AxiosInstance;
private log: Logger;
constructor(apiBase: string) {
this.http = Axios.create({
@ -19,8 +20,7 @@ export class PmApiClient {
*/
});
this.log = logService.getLogger('services/pm-api-client');
this.log.trace('Initialized PmApiClient');
logger.trace('Initialized PmApiClient');
}
public setAuthToken(authToken: string) {

View File

@ -9,7 +9,7 @@ import api from '@/services/pm-api-client';
import { logService } from '@/services/logging';
import { ApiToken } from '@/models';
const log = logService.getLogger('/store-modules/api-tokens');
const logger = logService.getLogger('/store-modules/api-tokens');
@Module({ namespaced: true, name: 'apiToken' })
export class ApiTokenStoreModule extends VuexModule {

View File

@ -26,7 +26,7 @@ export class MeasurementStoreModule extends VuexModule {
@Action({ rawError: true })
public async fetchMeasurements(measure: Measure<MeasureConfig>) {
logger.debug('Fetching measurements for measure ' + measure.id);
logger.trace('Fetching measurements for measure ' + measure.id);
const measurements = await api.getMeasurements(measure.slug); // assumption: always returns at least []
this.context.commit('SET_MEASUREMENTS', { measure, measurements });
}

View File

@ -8,7 +8,7 @@ import api from '@/services/pm-api-client';
import { logService } from '@/services/logging';
import { authStore } from '@/store';
const log = logService.getLogger('/store-modules/user');
const logger = logService.getLogger('/store-modules/user');
@Module({ namespaced: true, name: 'user' })
export class UserStoreModule extends VuexModule {
@ -17,6 +17,7 @@ export class UserStoreModule extends VuexModule {
@MutationAction({ mutate: ['user'], rawError: true })
public async fetchUser() {
logger.trace('Fetching current user record.');
return { user: await api.getUser() };
}