11// Copyright (c) Microsoft Corporation.
22// Licensed under the MIT License.
33
4- import utils = require( "./utils" ) ;
54import os = require( "os" ) ;
6- import vscode = require( "vscode" ) ;
7-
8- // NOTE: This is not a string enum because the order is used for comparison.
9- export enum LogLevel {
10- Diagnostic ,
11- Verbose ,
12- Normal ,
13- Warning ,
14- Error ,
15- None ,
16- }
5+ import { sleep , checkIfFileExists } from "./utils" ;
6+ import { LogOutputChannel , Uri , Disposable , LogLevel , window , env , commands , workspace } from "vscode" ;
177
188/** Interface for logging operations. New features should use this interface for the "type" of logger.
199 * This will allow for easy mocking of the logger during unit tests.
2010 */
2111export interface ILogger {
22- logDirectoryPath : vscode . Uri ;
23- updateLogLevel ( logLevelName : string ) : void ;
12+ logDirectoryPath : Uri ;
2413 write ( message : string , ...additionalMessages : string [ ] ) : void ;
2514 writeAndShowInformation ( message : string , ...additionalMessages : string [ ] ) : Promise < void > ;
2615 writeDiagnostic ( message : string , ...additionalMessages : string [ ] ) : void ;
@@ -35,37 +24,36 @@ export interface ILogger {
3524}
3625
3726export class Logger implements ILogger {
38- public logDirectoryPath : vscode . Uri ; // The folder for all the logs
39- private logLevel : LogLevel ;
40- private commands : vscode . Disposable [ ] ;
41- private logChannel : vscode . OutputChannel ;
42- private logFilePath : vscode . Uri ; // The client's logs
27+ public logDirectoryPath : Uri ; // The folder for all the logs
28+ private commands : Disposable [ ] ;
29+ // Log output channel handles all the verbosity management so we don't have to.
30+ private logChannel : LogOutputChannel ;
31+ private logFilePath : Uri ; // The client's logs
4332 private logDirectoryCreated = false ;
4433 private writingLog = false ;
34+ public get logLevel ( ) : LogLevel { return this . logChannel . logLevel ; }
4535
46- constructor ( logLevelName : string , globalStorageUri : vscode . Uri ) {
47- this . logLevel = Logger . logLevelNameToValue ( logLevelName ) ;
48- this . logChannel = vscode . window . createOutputChannel ( "PowerShell Extension Logs" ) ;
36+ constructor ( globalStorageUri : Uri , logChannel ?: LogOutputChannel ) {
37+ this . logChannel = logChannel ?? window . createOutputChannel ( "PowerShell" , { log : true } ) ;
4938 // We have to override the scheme because it defaults to
5039 // 'vscode-userdata' which breaks UNC paths.
51- this . logDirectoryPath = vscode . Uri . joinPath (
40+ this . logDirectoryPath = Uri . joinPath (
5241 globalStorageUri . with ( { scheme : "file" } ) ,
5342 "logs" ,
54- `${ Math . floor ( Date . now ( ) / 1000 ) } -${ vscode . env . sessionId } ` ) ;
55- this . logFilePath = vscode . Uri . joinPath ( this . logDirectoryPath , "vscode-powershell.log" ) ;
43+ `${ Math . floor ( Date . now ( ) / 1000 ) } -${ env . sessionId } ` ) ;
44+ this . logFilePath = Uri . joinPath ( this . logDirectoryPath , "vscode-powershell.log" ) ;
5645
5746 // Early logging of the log paths for debugging.
58- if ( LogLevel . Diagnostic >= this . logLevel ) {
59- const uriMessage = Logger . timestampMessage ( `Log file path: '${ this . logFilePath } '` , LogLevel . Verbose ) ;
60- this . logChannel . appendLine ( uriMessage ) ;
47+ if ( this . logLevel >= LogLevel . Trace ) {
48+ this . logChannel . trace ( `Log directory: ${ this . logDirectoryPath . fsPath } ` ) ;
6149 }
6250
6351 this . commands = [
64- vscode . commands . registerCommand (
52+ commands . registerCommand (
6553 "PowerShell.ShowLogs" ,
6654 ( ) => { this . showLogPanel ( ) ; } ) ,
6755
68- vscode . commands . registerCommand (
56+ commands . registerCommand (
6957 "PowerShell.OpenLogFolder" ,
7058 async ( ) => { await this . openLogFolder ( ) ; } ) ,
7159 ] ;
@@ -89,24 +77,24 @@ export class Logger implements ILogger {
8977 }
9078
9179 public write ( message : string , ...additionalMessages : string [ ] ) : void {
92- this . writeAtLevel ( LogLevel . Normal , message , ...additionalMessages ) ;
80+ this . writeAtLevel ( LogLevel . Info , message , ...additionalMessages ) ;
9381 }
9482
9583 public async writeAndShowInformation ( message : string , ...additionalMessages : string [ ] ) : Promise < void > {
9684 this . write ( message , ...additionalMessages ) ;
9785
98- const selection = await vscode . window . showInformationMessage ( message , "Show Logs" , "Okay" ) ;
86+ const selection = await window . showInformationMessage ( message , "Show Logs" , "Okay" ) ;
9987 if ( selection === "Show Logs" ) {
10088 this . showLogPanel ( ) ;
10189 }
10290 }
10391
10492 public writeDiagnostic ( message : string , ...additionalMessages : string [ ] ) : void {
105- this . writeAtLevel ( LogLevel . Diagnostic , message , ...additionalMessages ) ;
93+ this . writeAtLevel ( LogLevel . Trace , message , ...additionalMessages ) ;
10694 }
10795
10896 public writeVerbose ( message : string , ...additionalMessages : string [ ] ) : void {
109- this . writeAtLevel ( LogLevel . Verbose , message , ...additionalMessages ) ;
97+ this . writeAtLevel ( LogLevel . Debug , message , ...additionalMessages ) ;
11098 }
11199
112100 public writeWarning ( message : string , ...additionalMessages : string [ ] ) : void {
@@ -116,7 +104,7 @@ export class Logger implements ILogger {
116104 public async writeAndShowWarning ( message : string , ...additionalMessages : string [ ] ) : Promise < void > {
117105 this . writeWarning ( message , ...additionalMessages ) ;
118106
119- const selection = await vscode . window . showWarningMessage ( message , "Show Logs" ) ;
107+ const selection = await window . showWarningMessage ( message , "Show Logs" ) ;
120108 if ( selection !== undefined ) {
121109 this . showLogPanel ( ) ;
122110 }
@@ -129,7 +117,7 @@ export class Logger implements ILogger {
129117 public async writeAndShowError ( message : string , ...additionalMessages : string [ ] ) : Promise < void > {
130118 this . writeError ( message , ...additionalMessages ) ;
131119
132- const choice = await vscode . window . showErrorMessage ( message , "Show Logs" ) ;
120+ const choice = await window . showErrorMessage ( message , "Show Logs" ) ;
133121 if ( choice !== undefined ) {
134122 this . showLogPanel ( ) ;
135123 }
@@ -147,7 +135,7 @@ export class Logger implements ILogger {
147135
148136 const actionKeys : string [ ] = fullActions . map ( ( action ) => action . prompt ) ;
149137
150- const choice = await vscode . window . showErrorMessage ( message , ...actionKeys ) ;
138+ const choice = await window . showErrorMessage ( message , ...actionKeys ) ;
151139 if ( choice ) {
152140 for ( const action of fullActions ) {
153141 if ( choice === action . prompt && action . action !== undefined ) {
@@ -158,23 +146,6 @@ export class Logger implements ILogger {
158146 }
159147 }
160148
161- // TODO: Make the enum smarter about strings so this goes away.
162- private static logLevelNameToValue ( logLevelName : string ) : LogLevel {
163- switch ( logLevelName . trim ( ) . toLowerCase ( ) ) {
164- case "diagnostic" : return LogLevel . Diagnostic ;
165- case "verbose" : return LogLevel . Verbose ;
166- case "normal" : return LogLevel . Normal ;
167- case "warning" : return LogLevel . Warning ;
168- case "error" : return LogLevel . Error ;
169- case "none" : return LogLevel . None ;
170- default : return LogLevel . Normal ;
171- }
172- }
173-
174- public updateLogLevel ( logLevelName : string ) : void {
175- this . logLevel = Logger . logLevelNameToValue ( logLevelName ) ;
176- }
177-
178149 private showLogPanel ( ) : void {
179150 this . logChannel . show ( ) ;
180151 }
@@ -183,7 +154,7 @@ export class Logger implements ILogger {
183154 if ( this . logDirectoryCreated ) {
184155 // Open the folder in VS Code since there isn't an easy way to
185156 // open the folder in the platform's file browser
186- await vscode . commands . executeCommand ( "vscode. openFolder" , this . logDirectoryPath , true ) ;
157+ await commands . executeCommand ( "openFolder" , this . logDirectoryPath , true ) ;
187158 } else {
188159 void this . writeAndShowError ( "Cannot open PowerShell log directory as it does not exist!" ) ;
189160 }
@@ -195,26 +166,35 @@ export class Logger implements ILogger {
195166 }
196167
197168 // TODO: Should we await this function above?
198- private async writeLine ( message : string , level : LogLevel = LogLevel . Normal ) : Promise < void > {
199- const timestampedMessage = Logger . timestampMessage ( message , level ) ;
200- this . logChannel . appendLine ( timestampedMessage ) ;
201- if ( this . logLevel !== LogLevel . None ) {
169+ private async writeLine ( message : string , level : LogLevel = LogLevel . Info ) : Promise < void > {
170+ switch ( level ) {
171+ case LogLevel . Trace : this . logChannel . trace ( message ) ; break ;
172+ case LogLevel . Debug : this . logChannel . debug ( message ) ; break ;
173+ case LogLevel . Info : this . logChannel . info ( message ) ; break ;
174+ case LogLevel . Warning : this . logChannel . warn ( message ) ; break ;
175+ case LogLevel . Error : this . logChannel . error ( message ) ; break ;
176+ default : this . logChannel . appendLine ( message ) ; break ;
177+ }
178+
179+ if ( this . logLevel !== LogLevel . Off ) {
202180 // A simple lock because this function isn't re-entrant.
203181 while ( this . writingLog ) {
204- await utils . sleep ( 300 ) ;
182+ await sleep ( 300 ) ;
205183 }
206184 try {
207185 this . writingLog = true ;
208186 if ( ! this . logDirectoryCreated ) {
209187 this . writeVerbose ( `Creating log directory at: '${ this . logDirectoryPath } '` ) ;
210- await vscode . workspace . fs . createDirectory ( this . logDirectoryPath ) ;
188+ await workspace . fs . createDirectory ( this . logDirectoryPath ) ;
211189 this . logDirectoryCreated = true ;
212190 }
213191 let log = new Uint8Array ( ) ;
214- if ( await utils . checkIfFileExists ( this . logFilePath ) ) {
215- log = await vscode . workspace . fs . readFile ( this . logFilePath ) ;
192+ if ( await checkIfFileExists ( this . logFilePath ) ) {
193+ log = await workspace . fs . readFile ( this . logFilePath ) ;
216194 }
217- await vscode . workspace . fs . writeFile (
195+
196+ const timestampedMessage = Logger . timestampMessage ( message , level ) ;
197+ await workspace . fs . writeFile (
218198 this . logFilePath ,
219199 Buffer . concat ( [ log , Buffer . from ( timestampedMessage ) ] ) ) ;
220200 } catch ( err ) {
0 commit comments