@@ -11,11 +11,22 @@ namespace Microsoft.PowerShell.EditorServices.Utility
1111 /// </summary>
1212 public class PsesLogger : ILogger
1313 {
14+ /// <summary>
15+ /// The standard log template for all log entries.
16+ /// </summary>
17+ private static readonly string s_logMessageTemplate =
18+ "[{LogLevelName:l}] tid:{ThreadId} in '{CallerName:l}' {CallerSourceFile:l} (line {CallerLineNumber}):{IndentedLogMsg:l}" ;
19+
1420 /// <summary>
1521 /// The name of the ERROR log level.
1622 /// </summary>
1723 private static readonly string ErrorLevelName = LogLevel . Error . ToString ( ) . ToUpper ( ) ;
1824
25+ /// <summary>
26+ /// The name of the WARNING log level.
27+ /// </summary>
28+ private static readonly string WarningLevelName = LogLevel . Warning . ToString ( ) . ToUpper ( ) ;
29+
1930 /// <summary>
2031 /// The internal Serilog logger to log to.
2132 /// </summary>
@@ -51,31 +62,46 @@ public void Write(
5162 [ CallerMemberName ] string callerName = null ,
5263 [ CallerFilePath ] string callerSourceFile = null ,
5364 [ CallerLineNumber ] int callerLineNumber = 0 )
65+ {
66+ Write ( logLevel , new StringBuilder ( logMessage ) , callerName , callerSourceFile , callerLineNumber ) ;
67+ }
68+
69+ /// <summary>
70+ /// Write a message with the given severity to the logs. Takes a StringBuilder to allow for minimal allocation.
71+ /// </summary>
72+ /// <param name="logLevel">The severity level of the log message.</param>
73+ /// <param name="logMessage">The log message itself in StringBuilder form for manipulation.</param>
74+ /// <param name="callerName">The name of the calling method.</param>
75+ /// <param name="callerSourceFile">The name of the source file of the caller.</param>
76+ /// <param name="callerLineNumber">The line number where the log is being called.</param>
77+ private void Write (
78+ LogLevel logLevel ,
79+ StringBuilder logMessage ,
80+ [ CallerMemberName ] string callerName = null ,
81+ [ CallerFilePath ] string callerSourceFile = null ,
82+ [ CallerLineNumber ] int callerLineNumber = 0 )
5483 {
5584 string indentedLogMsg = IndentMsg ( logMessage ) ;
5685 string logLevelName = logLevel . ToString ( ) . ToUpper ( ) ;
5786
5887 int threadId = Thread . CurrentThread . ManagedThreadId ;
5988
60- string messageTemplate =
61- "[{LogLevelName:l}] tid:{threadId} in '{CallerName:l}' {CallerSourceFile:l}:{CallerLineNumber}:{IndentedLogMsg:l}" ;
62-
6389 switch ( logLevel )
6490 {
6591 case LogLevel . Diagnostic :
66- _logger . Verbose ( messageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
92+ _logger . Verbose ( s_logMessageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
6793 return ;
6894 case LogLevel . Verbose :
69- _logger . Debug ( messageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
95+ _logger . Debug ( s_logMessageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
7096 return ;
7197 case LogLevel . Normal :
72- _logger . Information ( messageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
98+ _logger . Information ( s_logMessageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
7399 return ;
74100 case LogLevel . Warning :
75- _logger . Warning ( messageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
101+ _logger . Warning ( s_logMessageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
76102 return ;
77103 case LogLevel . Error :
78- _logger . Error ( messageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
104+ _logger . Error ( s_logMessageTemplate , logLevelName , threadId , callerName , callerSourceFile , callerLineNumber , indentedLogMsg ) ;
79105 return ;
80106 }
81107 }
@@ -95,26 +121,63 @@ public void WriteException(
95121 [ CallerFilePath ] string callerSourceFile = null ,
96122 [ CallerLineNumber ] int callerLineNumber = 0 )
97123 {
98- string indentedException = IndentMsg ( exception . ToString ( ) ) ;
124+ StringBuilder body = FormatExceptionMessage ( "Exception" , errorMessage , exception ) ;
125+ Write ( LogLevel . Error , body , callerName , callerSourceFile , callerLineNumber ) ;
126+ }
99127
100- _logger . Error ( "[{ErrorLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}: {ErrorMessage:l}{IndentedException:l}" ,
101- ErrorLevelName , callerSourceFile , callerName , callerLineNumber , errorMessage , indentedException ) ;
128+ /// <summary>
129+ /// Log an exception that has been handled cleanly or is otherwise not expected to cause problems in the logs.
130+ /// </summary>
131+ /// <param name="errorMessage">The error message of the exception to be logged.</param>
132+ /// <param name="exception">The exception itself that has been thrown.</param>
133+ /// <param name="callerName">The name of the method in which the ILogger is being called.</param>
134+ /// <param name="callerSourceFile">The name of the source file in which the ILogger is being called.</param>
135+ /// <param name="callerLineNumber">The line number in the file where the ILogger is being called.</param>
136+ public void WriteHandledException (
137+ string errorMessage ,
138+ Exception exception ,
139+ [ CallerMemberName ] string callerName = null ,
140+ [ CallerFilePath ] string callerSourceFile = null ,
141+ [ CallerLineNumber ] int callerLineNumber = 0 )
142+ {
143+ StringBuilder body = FormatExceptionMessage ( "Handled exception" , errorMessage , exception ) ;
144+ Write ( LogLevel . Warning , body , callerName , callerSourceFile , callerLineNumber ) ;
102145 }
103146
104147 /// <summary>
105148 /// Utility function to indent a log message by one level.
106149 /// </summary>
107- /// <param name="logMessage">The log message to indent .</param>
150+ /// <param name="logMessageBuilder">Log message string builder to transform .</param>
108151 /// <returns>The indented log message string.</returns>
109- private static string IndentMsg ( string logMessage )
152+ private static string IndentMsg ( StringBuilder logMessageBuilder )
110153 {
111- return new StringBuilder ( logMessage )
154+ return logMessageBuilder
112155 . Replace ( Environment . NewLine , s_indentedPrefix )
113156 . Insert ( 0 , s_indentedPrefix )
114157 . AppendLine ( )
115158 . ToString ( ) ;
116159 }
117160
161+ /// <summary>
162+ /// Creates a prettified log message from an exception.
163+ /// </summary>
164+ /// <param name="messagePrelude">The user-readable tag for this exception entry.</param>
165+ /// <param name="errorMessage">The user-readable short description of the error.</param>
166+ /// <param name="exception">The exception object itself. Must not be null.</param>
167+ /// <returns>An indented, formatted string of the body.</returns>
168+ private static StringBuilder FormatExceptionMessage (
169+ string messagePrelude ,
170+ string errorMessage ,
171+ Exception exception )
172+ {
173+ var sb = new StringBuilder ( )
174+ . Append ( messagePrelude ) . Append ( ": " ) . Append ( errorMessage ) . Append ( Environment . NewLine )
175+ . Append ( Environment . NewLine )
176+ . Append ( exception . ToString ( ) ) ;
177+
178+ return sb ;
179+ }
180+
118181 /// <summary>
119182 /// A newline followed by a single indentation prefix.
120183 /// </summary>
0 commit comments