Ejemplo n.º 1
0
        /// <summary>
        /// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(Mammothcode.Public.Core.Core.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)
        {
            System.IO.TextWriter writer;

            if (m_writeToErrorStream)
            {
                writer = Console.Error;
            }
            else
            {
                writer = Console.Out;
            }

            // Reset color
            Console.ResetColor();

            // see if there is a specified lookup
            LevelColors levelColors = m_levelMapping.Lookup(loggingEvent.Level) as LevelColors;

            if (levelColors != null)
            {
                // if the backColor has been explicitly set
                if (levelColors.HasBackColor)
                {
                    Console.BackgroundColor = levelColors.BackColor;
                }
                // if the foreColor has been explicitly set
                if (levelColors.HasForeColor)
                {
                    Console.ForegroundColor = levelColors.ForeColor;
                }
            }

            // Render the event to a string
            string strLoggingMessage = RenderLoggingEvent(loggingEvent);

            // and write it
            writer.Write(strLoggingMessage);

            // Reset color again
            Console.ResetColor();
        }
Ejemplo n.º 2
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);
                }
            }
        }