コード例 #1
0
        override protected void Append(Mammothcode.Public.Core.Core.LoggingEvent loggingEvent) 
		{
			if (m_consoleOutputWriter != null)
			{
				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);
				}

				// 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 - 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.


				// The windows console uses ScrollConsoleScreenBuffer internally to
				// scroll the console buffer when the display buffer of the console
				// has been used up. ScrollConsoleScreenBuffer fills the area uncovered
				// by moving the current content with the background color 
				// currently specified on the console. This means that it fills the
				// whole line in front of the cursor position with the current 
				// background color.
				// This causes an issue when writing out text with a non default
				// background color. For example; We write a message with a Blue
				// background color and the scrollable area of the console is full.
				// When we write the newline at the end of the message the console
				// needs to scroll the buffer to make space available for the new line.
				// The ScrollConsoleScreenBuffer internals will fill the newly created
				// space with the current background color: Blue.
				// We then change the console color back to default (White text on a
				// Black background). We write some text to the console, the text is
				// written correctly in White with a Black background, however the
				// remainder of the line still has a Blue background.
				// 
				// This causes a disjointed appearance to the output where the background
				// colors change.
				//
				// This can be remedied by restoring the console colors before causing
				// the buffer to scroll, i.e. before writing the last newline. This does
				// assume that the rendered message will end with a newline.
				//
				// Therefore we identify a trailing newline in the message and don't
				// write this to the output, then we restore the console color and write
				// a newline. Note that we must AutoFlush before we restore the console
				// color otherwise we will have no effect.
				//
				// There will still be a slight artefact for the last line of the message
				// will have the background extended to the end of the line, however this
				// is unlikely to cause any user issues.
				//
				// Note that none of the above is visible while the console buffer is scrollable
				// within the console window viewport, the effects only arise when the actual
				// buffer is full and needs to be scrolled.

				char[] messageCharArray = strLoggingMessage.ToCharArray();
				int arrayLength = messageCharArray.Length;
				bool appendNewline = false;

				// Trim off last newline, if it exists
				if (arrayLength > 1 && messageCharArray[arrayLength-2] == '\r' && messageCharArray[arrayLength-1] == '\n')
				{
					arrayLength -= 2;
					appendNewline = true;
				}

				// Write to the output stream
				m_consoleOutputWriter.Write(messageCharArray, 0, arrayLength);

				// Restore the console back to its previous color scheme
				SetConsoleTextAttribute(consoleHandle, bufferInfo.wAttributes);

				if (appendNewline)
				{
					// Write the newline, after changing the color scheme
					m_consoleOutputWriter.Write(s_windowsNewline, 0, 2);
				}
			}
		}
コード例 #2
0
		/// <summary>
		/// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent)"/> method.
		/// </summary>
		/// <param name="loggingEvent">The event to log.</param>
		/// <remarks>
		/// <para>
		/// Writes the event to the console.
		/// </para>
		/// <para>
		/// The format of the output will depend on the appender's layout.
		/// </para>
		/// </remarks>
		override protected void Append(Mammothcode.Public.Core.Core.LoggingEvent loggingEvent) 
		{
			string loggingMessage = RenderLoggingEvent(loggingEvent);

			// see if there is a specified lookup.
			LevelColors levelColors = m_levelMapping.Lookup(loggingEvent.Level) as LevelColors;
			if (levelColors != null)
			{
				// Prepend the Ansi Color code
				loggingMessage = levelColors.CombinedColor + loggingMessage;
			}

			// on most terminals there are weird effects if we don't clear the background color
			// before the new line.  This checks to see if it ends with a newline, and if
			// so, inserts the clear codes before the newline, otherwise the clear codes
			// are inserted afterwards.
			if (loggingMessage.Length > 1)
			{
				if (loggingMessage.EndsWith("\r\n") || loggingMessage.EndsWith("\n\r")) 
				{
					loggingMessage = loggingMessage.Insert(loggingMessage.Length - 2, PostEventCodes);
				} 
				else if (loggingMessage.EndsWith("\n") || loggingMessage.EndsWith("\r")) 
				{
					loggingMessage = loggingMessage.Insert(loggingMessage.Length - 1, PostEventCodes);
				} 
				else 
				{
					loggingMessage = loggingMessage + PostEventCodes;
				}
			}
			else
			{
				if (loggingMessage[0] == '\n' || loggingMessage[0] == '\r') 
				{
					loggingMessage = PostEventCodes + loggingMessage;
				} 
				else 
				{
					loggingMessage = loggingMessage + PostEventCodes;
				}
			}

			if (m_writeToErrorStream)
			{
				// Write to the error stream
				Console.Error.Write(loggingMessage);
			}
			else
			{
				// Write to the output stream
				Console.Write(loggingMessage);
			}
		
		}