blob: 23d61e19e3ffb5ae19703886a3a6dd37ef6eb39c [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* The logger module encapsulates capturing information for logging activity done in the
* extension and proving uniform methods for presenting information and notifications to
* the user.
*
* There are methods for logging at the different levels, debug,info,warn,error.
*
* Currently, the only filtering that is done on is on the "Debug" level.
* These are only logged if IsDebugEnabled() === true.
* All other levels are logged all the time.
*
* There are also methods to show info,warning, and error messages to the user.
* These are separate from the log messages since it is common to have log messages
* containing more information that is reasonable to show to the user.
*/
import * as vscode from 'vscode';
import { CONFIG_DEBUG_FLAG } from './common-config';
/**
* Internal enum for tagging messages.
*/
enum LogLevel {
debug = 'DEBUG',
info = 'INFO ',
warn = 'WARN ',
error = 'ERROR'
}
/**
* Logging class.
*
* Use the exported methods from this module unless you're in a test doing ~~things~~.
*
* This exists (as opposed to a singleton output channel) because provides *readonly* view
* of the exports, so things like sinon.spy will break if we try to spy on module methods.
* Instead, we can spy on the instance of this.
*/
class Logger {
/// the output channel to which this logger writes
private output: vscode.OutputChannel;
constructor(output: vscode.OutputChannel) {
this.output = output;
}
/**
* Base to send an error of any type. The types are defined in the log functions defined
* below.
* @param type of log message = {'DEBUG', 'INFO', etc.}
* @param message data for the log message.
*/
log(type: LogLevel, message: string, category?: string, ...args: any[]) {
if (type !== LogLevel.debug || isDebugEnabled()) {
const categoryStr = category ? `(${category})` : '';
const logMessage = `${type} ${categoryStr} ${message}`;
this.output.append(logMessage);
for (let value of args) {
if (typeof value === 'string' || value instanceof String) {
this.output.append(`, ${value}`);
} else {
this.output.append(`, ${JSON.stringify(value)}`);
}
}
this.output.appendLine('');
}
}
/**
* Log a message at the LogLevel.debug.
* @param message data.
* @param category optional category for the message.
*/
debug(message: string, category?: string, ...args: any[]) {
this.log(LogLevel.debug, message, category, args);
}
/**
* Display info log. If show is true, show alert message.
* @param message data.
* @param show alert if true, default = false.
* @param category optional category for the message.
*/
info(message: string, category?: string, ...args: any[]) {
this.log(LogLevel.info, message, category, args);
}
/**
* Log warning message.
* @param message data.
* @param category optional category for the message.
*/
warn(message: string, category?: string, ...args: any[]) {
this.log(LogLevel.warn, message, category, args);
}
/**
* Log error message.
* @param message data.
* @param category optional category for the message.
*/
error(message: string, category?: string, ...args: any[]) {
this.log(LogLevel.error, message, category, args);
}
}
/**
* Logging instance.
*
* Use the exported methods from this module unless you're in a test doing ~~things~~.
*
* This exists (as opposed to a singleton output channel) because provides *readonly* view
* of the exports, so things like sinon.spy will break if we try to spy on module methods.
* Instead, we can spy on the instance of this.
*/
export let logger: Logger;
// Cached value of CONFIG_DEBUG_FLAG. A listener for configuration changes
// is install in `initLogger()`.
let debugEnabled: boolean = vscode.workspace.getConfiguration().get(CONFIG_DEBUG_FLAG, false);
/** Intializes the logger output channel to use for displaying messages to the user in the Output tab. */
export function initLogger(channel: vscode.OutputChannel) {
logger = new Logger(channel);
vscode.workspace.onDidChangeConfiguration(event => {
if (event.affectsConfiguration(CONFIG_DEBUG_FLAG)) {
debugEnabled = vscode.workspace.getConfiguration().get(CONFIG_DEBUG_FLAG, false);
}
});
}
/**
* Returns the configuration value indicating that debug logging and
* behaviors are enabled. The value is updated when the configuration changes.
* @returns true if debug is enabled.
*/
export function isDebugEnabled(): boolean {
return debugEnabled;
}
/**
* Log a message at the LogLevel.debug.
* @param message data.
* @param category optional category for the message.
*/
export function debug(message: string, category?: string, ...args: any[]) {
logger.debug(message, category, ...args);
}
/**
* Display info log. If show is true, show alert message.
* @param message data.
* @param show alert if true, default = false.
* @param category optional category for the message.
*/
export function info(message: string, category?: string, ...args: any[]) {
logger.info(message, category, ...args);
}
/**
* Log warning message.
* @param message data.
* @param category optional category for the message.
*/
export function warn(message: string, category?: string, ...args: any[]) {
logger.warn(message, category, ...args);
}
/**
* Log error message.
* @param message data.
* @param category optional category for the message.
*/
export function error(message: string, category?: string, ...args: any[]) {
logger.error(message, category, ...args);
}