You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4net-dev@logging.apache.org by ni...@apache.org on 2005/01/31 21:41:28 UTC
cvs commit: logging-log4net/src/Appender ColoredConsoleAppender.cs
nicko 2005/01/31 12:41:28
Modified: src/Appender ColoredConsoleAppender.cs
Log:
Updated to support writing more than 30,000 chars. Changed to use Stream that calls WriteFile rather than WriteConsoleW
Revision Changes Path
1.14 +126 -47 logging-log4net/src/Appender/ColoredConsoleAppender.cs
Index: ColoredConsoleAppender.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Appender/ColoredConsoleAppender.cs,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ColoredConsoleAppender.cs 17 Jan 2005 20:18:41 -0000 1.13
+++ ColoredConsoleAppender.cs 31 Jan 2005 20:41:28 -0000 1.14
@@ -64,7 +64,7 @@
/// When configuring the colored console appender, mapping should be
/// specified to map a logging level to a color. For example:
/// </para>
- /// <code lang="XML" excaped="true">
+ /// <code lang="XML" escaped="true">
/// <mapping>
/// <level value="ERROR" />
/// <foreColor value="White" />
@@ -240,7 +240,7 @@
/// <remarks>
/// <para>
/// Add a <see cref="LevelColors"/> mapping to this appender.
- /// Each mapping defines the foreground and background colours
+ /// Each mapping defines the foreground and background colors
/// for a level.
/// </para>
/// </remarks>
@@ -267,48 +267,86 @@
/// </remarks>
override protected void Append(log4net.Core.LoggingEvent loggingEvent)
{
- IntPtr consoleHandle = IntPtr.Zero;
- if (m_writeToErrorStream)
- {
- // Write to the error stream
- consoleHandle = GetStdHandle(STD_ERROR_HANDLE);
- }
- else
+ if (m_consoleOutputWriter != null)
{
- // Write to the output stream
- consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
- }
+ IntPtr consoleHandle = IntPtr.Zero;
+ if (m_writeToErrorStream)
+ {
+ // Write to the error stream
+ consoleHandle = GetStdHandle(STD_ERROR_HANDLE);
+ }
+ else
+ {
+ // Write to the output stream
+ consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ }
- // set the output parameters
- // Default to white on black
- ushort colorInfo = (ushort)Colors.White;
-
- // see if there is a specified lookup.
- LevelColors levelColors = m_levelMapping.Lookup(loggingEvent.Level) as LevelColors;
- if (levelColors != null)
- {
- colorInfo = levelColors.CombinedColor;
- }
+ // Default to white on black
+ ushort colorInfo = (ushort)Colors.White;
+
+ // see if there is a specified lookup
+ LevelColors levelColors = m_levelMapping.Lookup(loggingEvent.Level) as LevelColors;
+ if (levelColors != null)
+ {
+ colorInfo = levelColors.CombinedColor;
+ }
+
+ // Render the event to a string
+ string strLoggingMessage = RenderLoggingEvent(loggingEvent);
- // get the current console color.
- CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
- GetConsoleScreenBufferInfo(consoleHandle, out bufferInfo);
-
- // set the console.
- SetConsoleTextAttribute(consoleHandle, colorInfo);
-
- string strLoggingMessage = RenderLoggingEvent(loggingEvent);
-
- // write the output.
- UInt32 ignoreWrittenCount = 0;
- WriteConsoleW( consoleHandle,
- strLoggingMessage,
- (UInt32)strLoggingMessage.Length,
- out (UInt32)ignoreWrittenCount,
- IntPtr.Zero);
+ // get the current console color - to restore later
+ CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
+ GetConsoleScreenBufferInfo(consoleHandle, out bufferInfo);
+
+ // set the console colors
+ SetConsoleTextAttribute(consoleHandle, colorInfo);
+
+ // Using WriteConsoleW seems to be unreliable.
+ // If a large buffer is written, say 15,000 chars
+ // Followed by a larger buffer, say 20,000 chars
+ // then WriteConsoleW will fail, last error 8
+ // 'Not enough storage is available to process this command.'
+ //
+ // Although the documentation states that the buffer must
+ // be less that 64KB (i.e. 32,000 WCHARs) the longest string
+ // that I can write out a the first call to WriteConsoleW
+ // is only 30,704 chars.
+ //
+ // Unlike the WriteFile API the WriteConsoleW method does not
+ // seem to be able to partially write out from the input buffer.
+ // It does have a lpNumberOfCharsWritten parameter, but this is
+ // either the length of the input buffer if any output was written,
+ // or 0 when an error occurs.
+ //
+ // All results above were observed on Windows XP SP1 running
+ // .NET runtime 1.1 SP1.
+ //
+ // Old call to WriteConsoleW:
+ //
+ // WriteConsoleW(
+ // consoleHandle,
+ // strLoggingMessage,
+ // (UInt32)strLoggingMessage.Length,
+ // out (UInt32)ignoreWrittenCount,
+ // IntPtr.Zero);
+ //
+ // Instead of calling WriteConsoleW we use WriteFile which
+ // handles large buffers correctly. Because WriteFile does not
+ // handle the codepage conversion as WriteConsoleW does we
+ // need to use a System.IO.StreamWriter with the appropriate
+ // Encoding. The WriteFile calls are wrapped up in the
+ // System.IO.__ConsoleStream internal class obtained through
+ // the System.Console.OpenStandardOutput method.
+ //
+ // See the ActivateOptions method below for the code that
+ // retrieves and wraps the stream.
- // reset the console back to its previous color scheme.
- SetConsoleTextAttribute(consoleHandle, bufferInfo.wAttributes);
+ // Write to the output stream
+ m_consoleOutputWriter.Write(strLoggingMessage);
+
+ // Restore the console back to its previous color scheme
+ SetConsoleTextAttribute(consoleHandle, bufferInfo.wAttributes);
+ }
}
/// <summary>
@@ -337,6 +375,34 @@
{
base.ActivateOptions();
m_levelMapping.ActivateOptions();
+
+ System.IO.Stream consoleOutputStream = null;
+
+ // Use the Console methods to open a Stream over the console std handle
+ if (m_writeToErrorStream)
+ {
+ // Write to the error stream
+ consoleOutputStream = Console.OpenStandardError();
+ }
+ else
+ {
+ // Write to the output stream
+ consoleOutputStream = Console.OpenStandardOutput();
+ }
+
+ // Lookup the codepage encoding for the console
+ System.Text.Encoding consoleEncoding = System.Text.Encoding.GetEncoding(GetConsoleOutputCP());
+
+ // Create a writer around the console stream
+ m_consoleOutputWriter = new System.IO.StreamWriter(consoleOutputStream, consoleEncoding, 0x100);
+
+ m_consoleOutputWriter.AutoFlush = true;
+
+ // SuppressFinalize on m_consoleOutputWriter because all it will do is flush
+ // and close the file handle. Because we have set AutoFlush the additional flush
+ // is not required. The console file handle should not be closed, so we don't call
+ // Dispose, Close or the finalizer.
+ GC.SuppressFinalize(m_consoleOutputWriter);
}
#endregion // Override implementation of AppenderSkeleton
@@ -381,11 +447,24 @@
/// </summary>
private LevelMapping m_levelMapping = new LevelMapping();
+ /// <summary>
+ /// The console output stream writer to write to
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// This writer is not thread safe.
+ /// </para>
+ /// </remarks>
+ private System.IO.StreamWriter m_consoleOutputWriter = null;
+
#endregion // Private Instances Fields
#region Win32 Methods
[DllImport("Kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
+ private static extern int GetConsoleOutputCP();
+
+ [DllImport("Kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
private static extern bool SetConsoleTextAttribute(
IntPtr consoleHandle,
ushort attributes);
@@ -395,13 +474,13 @@
IntPtr consoleHandle,
out CONSOLE_SCREEN_BUFFER_INFO bufferInfo);
- [DllImport("Kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
- private static extern bool WriteConsoleW(
- IntPtr hConsoleHandle,
- [MarshalAs(UnmanagedType.LPWStr)] string strBuffer,
- UInt32 bufferLen,
- out UInt32 written,
- IntPtr reserved);
+// [DllImport("Kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
+// private static extern bool WriteConsoleW(
+// IntPtr hConsoleHandle,
+// [MarshalAs(UnmanagedType.LPWStr)] string strBuffer,
+// UInt32 bufferLen,
+// out UInt32 written,
+// IntPtr reserved);
//private const UInt32 STD_INPUT_HANDLE = unchecked((UInt32)(-10));
private const UInt32 STD_OUTPUT_HANDLE = unchecked((UInt32)(-11));