This is a cleaned-up version that includes a native version for Mono/Linux.
Rob >>> [EMAIL PROTECTED] 8/24/04 11:11 AM >>> I attached an implementation of a syslog log4net appender. Please review. I added a BSD license header because I used the defines from syslog.h. Is that correct? Please review the copyright and license. Thanks, Rob >>> [EMAIL PROTECTED] 8/22/04 10:16 AM >>> Rob, You may want to look at the log4j syslog implementation: http://cvs.apache.org/viewcvs.cgi/logging-log4j/src/java/org/apache/log4 j/net/SyslogAppender.java?rev=1.18&view=auto http://cvs.apache.org/viewcvs.cgi/logging-log4j/src/java/org/apache/log4 j/helpers/SyslogWriter.java?rev=1.5&view=auto http://cvs.apache.org/viewcvs.cgi/logging-log4j/src/java/org/apache/log4 j/helpers/SyslogQuietWriter.java?rev=1.5&view=auto Nicko > -----Original Message----- > From: Rob Lyon [mailto:[EMAIL PROTECTED] > Sent: 21 August 2004 16:06 > To: [email protected] > Subject: syslog log4net appender > > I need a syslog log4net appender. Has anyone started an > implementation? > Does anyone have any suggestions as I start an implementation? > > Thanks, > Rob > >
#region Copyright & License /* * Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #endregion #if MONO using System; using System.IO; using System.Net; using System.Runtime.InteropServices; using log4net.spi; namespace log4net.Appender { /// <summary> /// Logs entries to a remote syslog daemon. /// </summary> /// <author>Rob Lyon</author> public class SyslogNativeAppender : AppenderSkeleton { #region Public Instance Constructors /// <summary> /// Initializes a new instance of the <see cref="SyslogAppender" /> class. /// </summary> /// <remarks> /// The instance of the <see cref="SyslogAppender" /> class is set up to write /// to a remote syslog daemon. /// </remarks> public SyslogNativeAppender() { } #endregion Public Instance Constructors #region Public Instance Properties /// <summary> /// syslog identity /// </summary> public string Ident { get { return ident; } set { ident = value; } } /// <summary> /// syslog facility /// </summary> public Syslog.Facility Facility { get { return facility; } set { facility = value; } } /// <summary> /// syslog option /// </summary> public Syslog.Option Option { get { return option; } set { option = value; } } #endregion Public Instance Properties #region IOptionHandler Implementation /// <summary> /// Initialize the appender based on the options set. /// </summary> /// <remarks> /// <para> /// This is part of the <see cref="IOptionHandler"/> delayed object /// activation scheme. The <see cref="ActivateOptions"/> method must /// be called on this object after the configuration properties have /// been set. Until <see cref="ActivateOptions"/> is called this /// object is in an undefined state and must not be used. /// </para> /// <para> /// If any of the configuration properties are modified then /// <see cref="ActivateOptions"/> must be called again. /// </para> /// </remarks> public override void ActivateOptions() { base.ActivateOptions(); // check ident if (ident == null) { // create an ident string[] args = Environment.GetCommandLineArgs(); if ((args.Length > 0) && (args[0] != null) && (args[0].Length > 0) && !args[0].StartsWith("mono")) { ident = Path.GetFileName(args[0]); } else if ((args.Length > 1) && (args[1] != null) && (args[1].Length > 0)) { ident = Path.GetFileName(args[1]); } else { ident = ""; } } // global ident handleIdent = Marshal.StringToHGlobalAnsi(ident); // open syslog openlog(handleIdent, option, facility); } #endregion IOptionHandler Implementation #region AppenderSkeleton Implementation /// <summary> /// This method is called by the <see cref="AppenderSkeleton.DoAppend"/> method. /// </summary> /// <param name="loggingEvent">The event to log.</param> /// <remarks> /// <para> /// Writes the event to a remote syslog daemon. /// </para> /// <para> /// The format of the output will depend on the appender's layout. /// </para> /// </remarks> protected override void Append(LoggingEvent loggingEvent) { string message = RenderLoggingEvent(loggingEvent); int priority = Syslog.GeneratePriority(facility, Syslog.TranslateLevel(loggingEvent.Level)); syslog(priority, message); } /// <summary> /// On closing /// </summary> public override void OnClose() { base.OnClose(); // close syslog closelog(); // free global ident Marshal.FreeHGlobal(handleIdent); } /// <summary> /// This appender requires a <see cref="Layout"/> to be set. /// </summary> /// <value><c>true</c></value> override protected bool RequiresLayout { get { return true; } } #endregion AppenderSkeleton Implementation #region Private Instances Fields // identity string ident; // default to LOG_USER Syslog.Facility facility = Syslog.Facility.LOG_USER; // default to LOG_PID Syslog.Option option = Syslog.Option.LOG_PID; // global ident IntPtr handleIdent; #endregion Private Instances Fields #region External Members /// <summary> /// Open connection to system logger. /// </summary> [DllImport ("libc")] public static extern void openlog(IntPtr ident, Syslog.Option option, Syslog.Facility facility); /// <summary> /// Generate a log message. /// </summary> [DllImport ("libc")] public static extern void syslog(int priority, string message); /// <summary> /// Close desriptor used to write to system logger. /// </summary> [DllImport ("libc")] public static extern void closelog(); #endregion } } #endif
#region Copyright & License /* * Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)syslog.h 8.1 (Berkeley) 6/2/93 */ #endregion using System; using System.Net; using log4net; namespace log4net.Appender { /// <summary> /// Syslog constants and utilities for log4net /// </summary> /// <author>Rob Lyon</author> public class Syslog { #region Public Enums /// <summary> /// syslog levels /// </summary> [Flags] public enum Level { /// <summary> /// system is unusable /// </summary> LOG_EMERG = 0, /// <summary> /// action must be taken immediately /// </summary> LOG_ALERT = 1, /// <summary> /// critical conditions /// </summary> LOG_CRIT = 2, /// <summary> /// error conditions /// </summary> LOG_ERR = 3, /// <summary> /// warning conditions /// </summary> LOG_WARNING = 4, /// <summary> /// normal but significant condition /// </summary> LOG_NOTICE = 5, /// <summary> /// informational /// </summary> LOG_INFO = 6, /// <summary> /// debug-level messages /// </summary> LOG_DEBUG = 7 }; /// <summary> /// syslog facilities /// </summary> [Flags] public enum Facility { /// <summary> /// kernel messages /// </summary> LOG_KERN = (0 << 3), /// <summary> /// random user-level messages /// </summary> LOG_USER = (1 << 3), /// <summary> /// mail system /// </summary> LOG_MAIL = (2 << 3), /// <summary> /// system daemons /// </summary> LOG_DAEMON = (3 << 3), /// <summary> /// security/authorization messages /// </summary> LOG_AUTH = (4 << 3), /// <summary> /// messages generated internally by syslogd /// </summary> LOG_SYSLOG = (5 << 3), /// <summary> /// line printer subsystem /// </summary> LOG_LPR = (6 << 3), /// <summary> /// network news subsystem /// </summary> LOG_NEWS = (7 << 3), /// <summary> /// UUCP subsystem /// </summary> LOG_UUCP = (8 << 3), /// <summary> /// clock daemon /// </summary> LOG_CRON = (9 << 3), /// <summary> /// security/authorization messages (private) /// </summary> LOG_AUTHPRIV = (10 << 3), /// <summary> /// ftp daemon /// </summary> LOG_FTP = (11 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL0 = (16 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL1 = (17 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL2 = (18 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL3 = (19 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL4 = (20 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL5 = (21 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL6 = (22 << 3), /// <summary> /// reserved for local use /// </summary> LOG_LOCAL7 = (23 << 3) } /// <summary> /// syslog options /// </summary> [Flags] public enum Option { /// <summary> /// log the pid with each message /// </summary> LOG_PID = 0x01, /// <summary> /// log on the console if errors in sending /// </summary> LOG_CONS = 0x02, /// <summary> /// delay open until first syslog() (default) /// </summary> LOG_ODELAY = 0x04, /// <summary> /// don't delay open /// </summary> LOG_NDELAY = 0x08, /// <summary> /// don't wait for console forks: DEPRECATED /// </summary> LOG_NOWAIT = 0x10, /// <summary> /// log to stderr as well /// </summary> LOG_PERROR = 0x20 } #endregion Public Enums #region Public Static Fields /// <summary> /// syslog port /// </summary> public static int SYSLOG_PORT = 514; #endregion Public Static Fields #region Public Static Members /// <summary> /// Generate a syslog priority. /// </summary> /// <param name="facility">The syslog facility.</param> /// <param name="level">The syslog level.</param> /// <returns>A syslog priority.</returns> public static int GeneratePriority(Facility facility, Level level) { return (int)facility | (int)level; } /// <summary> /// Translates a log4net level to a syslog level. /// </summary> /// <param name="level">A log4net level.</param> /// <returns>A syslog level.</returns> public static Level TranslateLevel(log4net.spi.Level level) { Level result = Level.LOG_DEBUG; if (level == log4net.spi.Level.OFF) { result = Level.LOG_EMERG; } else if (level == log4net.spi.Level.FATAL) { result = Level.LOG_EMERG; } else if (level == log4net.spi.Level.ERROR) { result = Level.LOG_ERR; } else if (level == log4net.spi.Level.WARN) { result = Level.LOG_WARNING; } else if (level == log4net.spi.Level.INFO) { result = Level.LOG_INFO; } return result; } #endregion Public Static Members } }
#region Copyright & License /* * Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #endregion using System; using System.Net; using log4net.spi; namespace log4net.Appender { /// <summary> /// Logs entries to a remote syslog daemon. /// </summary> /// <author>Rob Lyon</author> public class SyslogAppender : UdpAppender { #region Public Instance Constructors /// <summary> /// Initializes a new instance of the <see cref="SyslogAppender" /> class. /// </summary> /// <remarks> /// The instance of the <see cref="SyslogAppender" /> class is set up to write /// to a remote syslog daemon. /// </remarks> public SyslogAppender() { // syslog udp defaults this.RemotePort = Syslog.SYSLOG_PORT; this.RemoteAddress = System.Net.IPAddress.Parse("127.0.0.1"); this.Encoding = System.Text.Encoding.ASCII; } #endregion Public Instance Constructors #region Public Instance Properties /// <summary> /// syslog facility /// </summary> public Syslog.Facility Facility { get { return facility; } set { facility = value; } } #endregion Public Instance Properties #region AppenderSkeleton Implementation /// <summary> /// This method is called by the <see cref="AppenderSkeleton.DoAppend"/> method. /// </summary> /// <param name="loggingEvent">The event to log.</param> /// <remarks> /// <para> /// Writes the event to a remote syslog daemon. /// </para> /// <para> /// The format of the output will depend on the appender's layout. /// </para> /// </remarks> protected override void Append(LoggingEvent loggingEvent) { try { string message = RenderLoggingEvent(loggingEvent); int priority = Syslog.GeneratePriority(facility, Syslog.TranslateLevel(loggingEvent.Level)); message = "<" + priority + ">" + message; Byte [] buffer = this.Encoding.GetBytes(message.ToCharArray()); this.Client.Send(buffer, buffer.Length, this.RemoteAddress.ToString(), this.RemotePort); } catch (Exception e) { ErrorHandler.Error( "Unable to send logging event to remote host " + this.RemoteAddress.ToString() + " on port " + this.RemotePort + ".", e, ErrorCodes.WriteFailure); } } #endregion AppenderSkeleton Implementation #region Private Instances Fields // default to LOG_USER Syslog.Facility facility = Syslog.Facility.LOG_USER; #endregion Private Instances Fields } }
