3

I'm gonna use log4net in my wpf application. And I need messages in my log looks like this:

11/8/2018 10:49:38 AM   13 (5368)       properties disabled.

where 13 is processId which writes this message. So it's pretty easy. But unfortunately I can't achieve this. So I just need an appropriate pattern layout for my log4net logger.

I've found the following message in faq section of log4net official site:

The following example sets the file name for a FileAppender to include the current process id by specifying the %processid pattern in the File property.

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

So and it works but only for file name not for layout in my log file. And I need to put this %processid into my layout. And my current layout is:

<layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date{dd/MM/yyyy HH:mm:ss,fff tt} %processid (%thread) - %message%newline" />
</layout>

And my log just writes processid string to my log file.

22/11/2018 16:21:51,863 PM processid (1) - Exiting application.

I've also found a SO answer. And it works. But %processid property is initialized only once during startup. And in my app the writing proсes is often changes. So this solution is not suitable for me. And I guess it could be achieved by default log4net layout settings.

The other option is using type="log4net.Util.PatternString" as a type of my conversionPattern. But it is not suitable as well(if I use this type - type="log4net.Util.PatternString" - in conversionPattern then %threadId, %level and even %message will be printed as string constants).

23/11/2018 16:22:52,456 PM 31560 [thread] level - message

But I need both %threadId and %processid in log.

isxaker
  • 8,446
  • 12
  • 60
  • 87
  • @pfx actually it's not a duplicate.My original question had a link to that SO answer as well as explanation why it's not suitable for me. I have a bit different purpose.`%processid` has to be printed in my log file in each line. And it should be printed with the other parameter(`%threadId`, `%level` etc).So `type="log4net.Util.PatternString"` is not suitable as well(if I use this type - `type="log4net.Util.PatternString"` - in `conversionPattern` `%threadId`, `%level'`will be printed as string constants). So I need both `%threadId` and `%processid` in log(`%processid` DOES change in runtime) – isxaker Nov 26 '18 at 08:10
  • @pfx nice, thank you – isxaker Nov 26 '18 at 09:12
  • Can you make a small edit on your question? Without it, I can't remove the flag – pfx Nov 26 '18 at 09:13
  • @pfx I've just done some changes – isxaker Nov 26 '18 at 09:18
  • 1
    Can you try using `ThreadContext`instead of `GlobalContext` `log4net.ThreadContext.Properties["pid"] = Process.GetCurrentProcess().Id;` which allows to have a different property value per thread. – pfx Nov 26 '18 at 09:22
  • @pfx I definitely should try this. But do I have to observe changing the value of `Process.GetCurrentProcess()` ? I guess I have to. And from other hand `log4net` already offers an approach how to work with `%processid`. So I assume there's a default solution for it. Moreover my log4net settings allow me to write `%processid` but not with the other param values( `%threadid`, `%meesage` – isxaker Nov 26 '18 at 09:28
  • `%processid` is only defined for `PatternString`, not for a `PatternLayout`. Because of this, you need to use a `%property`, which is only a simple key-value pair. – pfx Nov 26 '18 at 09:39
  • @pfx yes, you're right. But I have to update this (`%processid`) property each time as well – isxaker 14 mins ago – isxaker Nov 26 '18 at 09:57

1 Answers1

5

You can implement a custom PatternLayoutConverter which outputs the process Id.
Doing so, you don't have to have to set and track the Id of the running process.

namespace PFX
{
    class ProcessIdPatternLayoutConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            Int32 processId = Process.GetCurrentProcess().Id;
            writer.Write(processId);
        }
    }
}

You then reference this PatternLayoutConverterin your Log4netconfig via its fully qualified assembly name as below.

<layout type="log4net.Layout.PatternLayout">                        
    <converter>
        <name value="processid" />
        <type value="PFX.ProcessIdPatternLayoutConverter, PFX.Lib" />
    </converter>            
    <conversionPattern value="%date{dd/MM/yyyy HH:mm:ss,fff tt} %processid (%thread) - %message%newline" />
</layout>
pfx
  • 20,323
  • 43
  • 37
  • 57