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
        }
}

Reply via email to