Return-Path: X-Original-To: apmail-logging-commits-archive@minotaur.apache.org Delivered-To: apmail-logging-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5705BF333 for ; Wed, 27 Mar 2013 07:25:36 +0000 (UTC) Received: (qmail 51929 invoked by uid 500); 27 Mar 2013 07:25:36 -0000 Delivered-To: apmail-logging-commits-archive@logging.apache.org Received: (qmail 51864 invoked by uid 500); 27 Mar 2013 07:25:33 -0000 Mailing-List: contact commits-help@logging.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@logging.apache.org Delivered-To: mailing list commits@logging.apache.org Received: (qmail 51829 invoked by uid 99); 27 Mar 2013 07:25:33 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Mar 2013 07:25:33 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Mar 2013 07:25:31 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id AC009238890D; Wed, 27 Mar 2013 07:25:11 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1461433 - /logging/log4net/trunk/src/Appender/RemoteSyslogAppender.cs Date: Wed, 27 Mar 2013 07:25:11 -0000 To: commits@logging.apache.org From: dpsenner@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130327072511.AC009238890D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dpsenner Date: Wed Mar 27 07:25:11 2013 New Revision: 1461433 URL: http://svn.apache.org/r1461433 Log: LOG4NET-370 fix the RemoteSyslogAppender to properly handle log messages that contain newlines This patch is based on the work of Jarrod Alexander. Please note that this patch also fixes indentation issues and thus contains some portions of refactoring. Finally it is worth to note that the patch primarily focuses on making the syslog messages RFC3164 (http://www.ietf.org/rfc/rfc3164.txt) compliant. The signifant parts of the RFC are: 4.1.3 MSG Part of a syslog Packet The MSG part will fill the remainder of the syslog packet. This will usually contain some additional information of the process that generated the message, and then the text of the message. There is no ending delimiter to this part. The MSG part of the syslog packet MUST contain visible (printing) characters. The code set traditionally and most often used has also been seven-bit ASCII in an eight-bit field like that used in the PRI and HEADER parts. In this code set, the only allowable characters are the ABNF VCHAR values (%d33-126) and spaces (SP value %d32). However, no indication of the code set used within the MSG is required, nor is it expected. Other code sets MAY be used as long as the characters used in the MSG are exclusively visible characters and spaces similar to those described above. The selection of a code set used in the MSG part SHOULD be made with thoughts of the intended receiver. A message containing characters in a code set that cannot be viewed or understood by a recipient will yield no information of value to an operator or administrator looking at it. Modified: logging/log4net/trunk/src/Appender/RemoteSyslogAppender.cs Modified: logging/log4net/trunk/src/Appender/RemoteSyslogAppender.cs URL: http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/RemoteSyslogAppender.cs?rev=1461433&r1=1461432&r2=1461433&view=diff ============================================================================== --- logging/log4net/trunk/src/Appender/RemoteSyslogAppender.cs (original) +++ logging/log4net/trunk/src/Appender/RemoteSyslogAppender.cs Wed Mar 27 07:25:11 2013 @@ -24,7 +24,7 @@ using log4net.Appender; using log4net.Util; using log4net.Layout; -namespace log4net.Appender +namespace log4net.Appender { /// /// Logs events to a remote syslog daemon. @@ -66,7 +66,7 @@ namespace log4net.Appender /// /// Rob Lyon /// Nicko Cadell - public class RemoteSyslogAppender : UdpAppender + public class RemoteSyslogAppender : UdpAppender { /// /// Syslog port 514 @@ -268,7 +268,7 @@ namespace log4net.Appender /// This instance of the class is set up to write /// to a remote syslog daemon. /// - public RemoteSyslogAppender() + public RemoteSyslogAppender() { // syslog udp defaults this.RemotePort = DefaultSyslogPort; @@ -279,7 +279,7 @@ namespace log4net.Appender #endregion Public Instance Constructors #region Public Instance Properties - + /// /// Message identity /// @@ -310,7 +310,7 @@ namespace log4net.Appender get { return m_facility; } set { m_facility = value; } } - + #endregion Public Instance Properties /// @@ -341,46 +341,68 @@ namespace log4net.Appender /// The format of the output will depend on the appender's layout. /// /// - protected override void Append(LoggingEvent loggingEvent) + protected override void Append(LoggingEvent loggingEvent) { - try + try { - System.IO.StringWriter writer = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture); + using (ReusableStringWriter writer = new ReusableStringWriter(System.Globalization.CultureInfo.InvariantCulture)) + { + // Priority + int priority = GeneratePriority(m_facility, GetSeverity(loggingEvent.Level)); - // Priority - int priority = GeneratePriority(m_facility, GetSeverity(loggingEvent.Level)); - writer.Write('<'); - writer.Write(priority); - writer.Write('>'); + // Identity + string identity; - // Identity - if (m_identity != null) - { - m_identity.Format(writer, loggingEvent); - } - else - { - writer.Write(loggingEvent.Domain); - } - writer.Write(": "); + if (m_identity != null) + { + identity = m_identity.Format(loggingEvent); + } + else + { + identity = loggingEvent.Domain; + } + + // Message. The message goes after the tag/identity + string message = RenderLoggingEvent(loggingEvent); + + // Split message by line to ensure that the syslog + // message is compliant to the RFC + // http://www.ietf.org/rfc/rfc3164.txt in section 4.1.3 + string[] lines = message.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + Byte[] buffer; + + foreach (string line in lines) + { + writer.Reset(c_renderBufferMaxCapacity, c_renderBufferSize); + + // Write priority + writer.Write('<'); + writer.Write(priority); + writer.Write('>'); + + // Write identity + writer.Write(identity); + writer.Write(": "); + + // Write message line + writer.Write(line); - // Message. The message goes after the tag/identity - RenderLoggingEvent(writer, loggingEvent); + // Grab as a byte array + buffer = this.Encoding.GetBytes(writer.ToString()); - // Grab as a byte array - string fullMessage = writer.ToString(); - Byte [] buffer = this.Encoding.GetBytes(fullMessage.ToCharArray()); - - this.Client.Send(buffer, buffer.Length, this.RemoteEndPoint); - } - catch (Exception e) + this.Client.Send(buffer, buffer.Length, this.RemoteEndPoint); + } + } + } + catch (Exception e) { ErrorHandler.Error( - "Unable to send logging event to remote syslog " + - this.RemoteAddress.ToString() + - " on port " + - this.RemotePort + ".", - e, + "Unable to send logging event to remote syslog " + + this.RemoteAddress.ToString() + + " on port " + + this.RemotePort + ".", + e, ErrorCode.WriteFailure); } } @@ -425,30 +447,30 @@ namespace log4net.Appender // Fallback to sensible default values // - if (level >= Level.Alert) + if (level >= Level.Alert) { return SyslogSeverity.Alert; - } - else if (level >= Level.Critical) + } + else if (level >= Level.Critical) { return SyslogSeverity.Critical; - } - else if (level >= Level.Error) + } + else if (level >= Level.Error) { return SyslogSeverity.Error; - } - else if (level >= Level.Warn) + } + else if (level >= Level.Warn) { return SyslogSeverity.Warning; - } - else if (level >= Level.Notice) + } + else if (level >= Level.Notice) { return SyslogSeverity.Notice; - } - else if (level >= Level.Info) + } + else if (level >= Level.Info) { return SyslogSeverity.Informational; - } + } // Default setting return SyslogSeverity.Debug; } @@ -505,6 +527,16 @@ namespace log4net.Appender /// private LevelMapping m_levelMapping = new LevelMapping(); + /// + /// Initial buffer size + /// + private const int c_renderBufferSize = 256; + + /// + /// Maximum buffer size before it is recycled + /// + private const int c_renderBufferMaxCapacity = 1024; + #endregion Private Instances Fields #region LevelSeverity LevelMapping Entry