tags:

views:

483

answers:

3

I am trying to create a logging solution that involves multiple processes on multiple machines. I planned on using the UDPAppender to send all log messages to a single machine that would manage them. I have a few questions about patternstrings vs patternlayouts.

Because I need to know both which machine and which process that log message came from, I want to include that in the log as well. I found %property{log4net:HostName} for hostname, and that works great. However, I don't see anything for process id in PatternLayouts. I do, of course, see something like that in the PatternString. From the FAQ:

<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
    <file type="log4net.Util.PatternString" value="log-file-[%processid].txt" />

    <layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" />
</appender>

But I am not sure if or how to mix and match the two (or even if this is the canonical way to do so).

So, my questions are:

  1. What is the difference between PatternString and PatternLayout? Why have both?

  2. I see the %processid in PatternString, how do I get the same in PatternLayout? Here is my test layout:

    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] [%property{log4net:HostName}] %-5level %logger  - %message%newline" />
    </layout>
    
  3. Finally, it makes sense to use the XML layout for the UDP appender. It looks like the XmlLayoutSchemaLog4j already adds the HostNameProperty to the XML message. If I wan't to add this new Process ID (and maybe Process Name) to the XML message, what is the best way to do this? Should I just copy src\Layouts\XmlLayoutSchemaLog4j.cs, modify it, and let log4net know that I created this new Layout (like the SampleLayoutsApp)?

Thanks for your help

+2  A: 

Apparently PatternString can only be used to create log names (ie filenames etc.) whereas layout lets you format the actual message that gets into the log. If there is no built-in pattern for process id in the process layout, then you can easily add it. It is much simpler than creating the whole layout.

Here is how to do it:

Create your own custom pattern converter (example below tries to get the name of the application no matter win or web):

internal sealed class ApplicationNamePatternConverter : PatternLayoutConverter 
{
    /// <summary>
    /// Write the event application name to the output
    override protected void Convert(TextWriter writer, LoggingEvent loggingEvent)
    {
        string name = string.Empty;
        if( System.Web.HttpContext.Current != null )
        {
            string[] applicationPath = System.Web.HttpContext.Current.Request.ApplicationPath.Split('/');
            name = applicationPath[applicationPath.Length - 1];
        }
        else
        {
            if( System.Reflection.Assembly.GetEntryAssembly() != null )
            {
                name = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
            }
        }
        writer.Write(name);
    }
}

Add the entry for your converter to the registry of PatternLayout class

static PatternLayout()
{
...
  s_globalRulesRegistry.Add("ApplicationName", typeof(ApplicationNamePatternConverter));
}

Now you can use '%ApplicationName' in the PatternLayout value to get what you need.

I'd advise not to use the XmlLayoutSchemaLog4j layout as it is very heavy and can drop performance of your app if used frequently.

Konrad
+1  A: 

You can add any properties you want to the GlobalContext. I use this context to store the process id, like this:

log4net.GlobalContext.Properties["pid"] = Process.GetCurrentProcess().Id;

Then you reference this property from your appender using a regular pattern, like this:

<layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date %property{pid} %level %logger - %message%newline" />
</layout>

You can add as many properties as you want, but because of it's global nature, it works best for properties that don't change during your application's execution.

TskTsk
A: 

You can feed a PatternString into a PatternLayout:

    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern type="log4net.Util.PatternString" value="%processid" />
    </layout>
Doug W