You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4net-user@logging.apache.org by Frode Breimo <fr...@mobitech.no> on 2005/06/24 14:08:38 UTC

Customized log4net, would like feedback/advice

Hi

I've made a couple of customizations to log4net and would like to hear 
people's opinion on my solution.

When logging I've made extensive use of properties to put data in 
specific database fields. These properties must (as far as I know) be 
placed in GlobalContext, ThreadContext or LogicalThreadContext. This can 
be a bit of a drag since the properties are still active after logging, 
this results in code like

    log4net.LogicalThreadContext.Properties["LogData"] = myData;
    log4net.LogicalThreadContext.Properties["LogException"] = e.Message;
    log.Error("An exception occured");
    log4net.LogicalThreadContext.Properties.Remove("LogData");
    log4net.LogicalThreadContext.Properties.Remove("LogException");

I got tired of this, so after picking up a few tips and tricks from 
other threads in this mailing list I decided to make an attempt at 
customizing Log4Net. I decided to make another overload for each of the 
logging methods (log.Info, log.Debug etc), an overload that (in addition 
to a message and an exception) takes in the names and values of the 
desired properties, and adds them to the logging event itself, thus 
making them unique for that perticular logging call. What I ended up 
with was the following additions to LogImpl.cs:

    virtual public void Error(object message, Exception exception, 
string[] propertyNames, string[] propertyValues)
    {
        Logger.Log(CustomLoggingEvent(m_levelError, message, exception, 
propertyNames, propertyValues));
    }


    private LoggingEvent CustomLoggingEvent(Level level, object message, 
Exception exception, string[] propertyNames, string[] propertyValues)
    {
        LogLog.Debug("Creating custom logging event.");
        log4net.Core.LoggingEvent loggingEvent = new 
log4net.Core.LoggingEvent(ThisDeclaringType, Logger.Repository, 
Logger.Name, level, message, exception);
        try
        {
            // Ignore all properties if the two arrays are of different 
lengths
            if (propertyNames.Length == propertyValues.Length)
            {
                for (int i = 0; i < propertyNames.Length; i++)
                {
                    if (propertyNames[i].Length > 0)
                    {
                        // Add the parameter to the LoggingEvent
                        loggingEvent.Properties[propertyNames[i]] = 
propertyValues[i];
                        LogLog.Debug("Property " + propertyNames[i] + " 
added to custom logging event, with a value of " + propertyValues[i]);
                    }
                }
            }
        }
        catch (Exception exc)
        {
            LogLog.Debug("Error creating custom logging event: " + 
exc.Message);
        }
        return loggingEvent;
    }


...and in ILog.cs, I added

    void Error(object message, Exception exception, string[] 
propertyNames, string[] propertyValues);


So, instead of the previous code where I added and then removed the 
properties every time I needed them, I now use the following code to log 
with properties:

    log.Error("An exception occured", e, new string[]{"LogData", 
"LogException"}, new string[]{myData, e.Message});


This makes logging with properties a lot easier to code, but is it a 
good solution? I know it's somewhat limited with the arrays being of 
type string and not Object, but I wanted to keep it simple as a start, 
and it satisfies my (current) needs. But besides that? Are there any 
other parts of Log4Net that needs to be altered because of this (it 
works fine now though), is the way I've solved it good, is the code 
good? Any advice or criticism (and even praise) would be apreciated.


Regards,
Frode



Re: Customized log4net, would like feedback/advice

Posted by Ron Grabowski <ro...@yahoo.com>.
Here's another example of extending the ILog interface to accept
additional parameters:

http://tinyurl.com/cpz5o
http://cvs.apache.org/viewcvs.cgi/logging-log4net/extensions/net/1.0/log4net.Ext.EventID/cs/src/IEventIDLog.cs?view=markup

If you made an overload like this:
 
 log.Error(string, Exception, params object[]);

You could check the object array to see if it contained an even number
of elements. Elements having an even index (0, 2, 4, etc.) would be
keys and elements having an odd index (1, 3, 5, etc.) would be values:

 log.Error("An exception occured", e, 
  "LogData", myData,
  "LogException", e.Message,
  "Hello", "World");

 // untested
 if (args % 2 == 0)
 {
  for (int i=0;i<args.Length-2;i+=2)
  {
   loggingEvent.Properties[args[i]] = args[i+1];
  }
 }

That code looks cleaner to me plus you're now able to pass in objects.

Sometimes I wonder why the MDC (or ThreadContext) doesn't support this
style of (IDisposable?) notation:

 using(log4net.MDC.Set("LogData", myData)
 using(log4net.MDC.Set("LogException", e)
 {
   log.Info("An exception occured.");
 }

That may or may not be easier to read. I believe NDC calls support that
notation. I'm sure there's some good reason why that syntax isn't
supported :-)

- Ron

--- Frode Breimo <fr...@mobitech.no> wrote:

> Hi
> 
> I've made a couple of customizations to log4net and would like to
> hear 
> people's opinion on my solution.
> 
> When logging I've made extensive use of properties to put data in 
> specific database fields. These properties must (as far as I know) be
> 
> placed in GlobalContext, ThreadContext or LogicalThreadContext. This
> can 
> be a bit of a drag since the properties are still active after
> logging, 
> this results in code like
> 
>     log4net.LogicalThreadContext.Properties["LogData"] = myData;
>     log4net.LogicalThreadContext.Properties["LogException"] =
> e.Message;
>     log.Error("An exception occured");
>     log4net.LogicalThreadContext.Properties.Remove("LogData");
>     log4net.LogicalThreadContext.Properties.Remove("LogException");
> 
> I got tired of this, so after picking up a few tips and tricks from 
> other threads in this mailing list I decided to make an attempt at 
> customizing Log4Net. I decided to make another overload for each of
> the 
> logging methods (log.Info, log.Debug etc), an overload that (in
> addition 
> to a message and an exception) takes in the names and values of the 
> desired properties, and adds them to the logging event itself, thus 
> making them unique for that perticular logging call. What I ended up 
> with was the following additions to LogImpl.cs:
> 
>     virtual public void Error(object message, Exception exception, 
> string[] propertyNames, string[] propertyValues)
>     {
>         Logger.Log(CustomLoggingEvent(m_levelError, message,
> exception, 
> propertyNames, propertyValues));
>     }
> 
> 
>     private LoggingEvent CustomLoggingEvent(Level level, object
> message, 
> Exception exception, string[] propertyNames, string[] propertyValues)
>     {
>         LogLog.Debug("Creating custom logging event.");
>         log4net.Core.LoggingEvent loggingEvent = new 
> log4net.Core.LoggingEvent(ThisDeclaringType, Logger.Repository, 
> Logger.Name, level, message, exception);
>         try
>         {
>             // Ignore all properties if the two arrays are of
> different 
> lengths
>             if (propertyNames.Length == propertyValues.Length)
>             {
>                 for (int i = 0; i < propertyNames.Length; i++)
>                 {
>                     if (propertyNames[i].Length > 0)
>                     {
>                         // Add the parameter to the LoggingEvent
>                         loggingEvent.Properties[propertyNames[i]] = 
> propertyValues[i];
>                         LogLog.Debug("Property " + propertyNames[i] +
> " 
> added to custom logging event, with a value of " +
> propertyValues[i]);
>                     }
>                 }
>             }
>         }
>         catch (Exception exc)
>         {
>             LogLog.Debug("Error creating custom logging event: " + 
> exc.Message);
>         }
>         return loggingEvent;
>     }
> 
> 
> ...and in ILog.cs, I added
> 
>     void Error(object message, Exception exception, string[] 
> propertyNames, string[] propertyValues);
> 
> 
> So, instead of the previous code where I added and then removed the 
> properties every time I needed them, I now use the following code to
> log 
> with properties:
> 
>     log.Error("An exception occured", e, new string[]{"LogData", 
> "LogException"}, new string[]{myData, e.Message});
> 
> 
> This makes logging with properties a lot easier to code, but is it a 
> good solution? I know it's somewhat limited with the arrays being of 
> type string and not Object, but I wanted to keep it simple as a
> start, 
> and it satisfies my (current) needs. But besides that? Are there any 
> other parts of Log4Net that needs to be altered because of this (it 
> works fine now though), is the way I've solved it good, is the code 
> good? Any advice or criticism (and even praise) would be apreciated.
> 
> 
> Regards,
> Frode
> 
> 
>