开发者

Log4Net - Add time with logging datetime

I developed a asp.net website where I log error information using log4net with format:

"%-5p %d - %m%n"
开发者_Python百科

It logs datetime by current machine's datetime. For example:

FATAL 2011-04-10 01:08:11,759 - message

But I want to convert datetime to another region or add additional time with it. For example I want to add 3 hours with previous example and want output as:

FATAL 2011-04-10 **04**:08:11,759 - message

Any idea on how to achieve this?


This might not answer your question, because I'm not sure exactly what you are trying to achieve. Maybe if you could provide more details on exactly why you want to do this, you might get a better answer.

If you are trying to correlate multiple log files (or other sources) that have been generated in different regions, it might help...

You could try log4net's utctime PatternLayout as described here.

This will get your log times in universal time, which might be easier for you to correlate. If you have control over the sources of timestampes (like your asp.net website), then by normalizing them to universal time, they should be easier to compare.

If you really do want to change the time to a different region or add/substract an arbitrary time span from the timestamp as it is logged, you might have to write your own custom PatternLayout or PatternLayoutConverter. That might be a little bit tricky as I think that neither the log4net DatePatternConverter nor the UtcDatePatternConverter is available for customization (i.e. they are declared internal so you can't subclass them and add your behavior).

You could write your own from scratch, using log4net's implementation from the log4net code repository, but that seems like a lot of trouble to me.

One more note, maybe it would be useful to log time again in a separate column using one of these Custom Date format specifiers: z, zz, zzz, K.

UPDATE: See this answer for another idea that might help. The question asks for a way to capture username with log4net. Ultimately, the best solution for him was to write a very small class that will return the information the he needs (username). An instance of the class can be stored in the MDC (or GlobalDiagnosticContext) and referenced in the configuration. When log4net gets the value from the MDC (i.e. the object), it calls ToString and logs the result. This approach is a lot easier, if somewhat less flexible, than writing a whole new PatternLayoutConverter.

Towards the bottom of the answer is some sample code like this:

public class HttpContextUserNameProvider 
{   
  public override string ToString()   
  {     
    HttpContext context = HttpContext.Current;       
    if (context != null && 
        context.User != null && 
        context.User.Identity.IsAuthenticated)
    {
      return context.Identity.Name;     
    }     
    return "";   
  } 
}

You would store the object in the MDC/GlobalDiagnosticContext.Properties like this:

MDC.Set("user", new HttpContextUserNameProvider()); 

You could probably write something similar to return a different time. You could use this time instead of the log4net-provided time, or you could make this "custom" time an additional column. Your "custom time" object might look like this:

public class MyLocalTimeProvider 
{   
  public override string ToString()   
  {     
    DateTime myLocalTime = GetUtcTimeInMyTimeZone(DateTime.UtcNow);
    return myLocalTime;
  } 
}

Then you could reference it like this:

MDC.Set("myLocalTime", new MyLocalTimeProvider()); 

I'm not sure if you can apply formats to items from the MDC/GlobalDiagnosticContext.Properties (I think you can) or not, but you could try it and see.

You could always use a hardcoded format or add a format property to the object like this:

public class MyLocalTimeProvider 
{   
  public MyLocalTimeProvider(string format)
  {
    Format = format;
  }

  public MyLocalTimeProvider()
    : this ("G")
  {
  }

  public string Format { get; set; }
  public override string ToString()   
  {     
    DateTime myLocalTime = GetUtcTimeInMyTimeZone(DateTime.UtcNow);
    return myLocalTime.ToString(Format);
  } 
}

You might take a look at this article for how to convert a UTC time to an arbitrary time zone.


If you need just "shift" date to your timezone, you can write your own ForwardingAppender, which will change DateTime of logged event:

namespace Olekstra
{
    using System;

    using log4net.Appender;
    using log4net.Core;

    public class TimeShiftForwardingAppender : ForwardingAppender
    {
        private TimeSpan shift;

        private TimeSpan targetOffset;

        public TimeShiftForwardingAppender()
        {
            TargetOffset = TimeZoneInfo.Local.BaseUtcOffset;
        }

        public TimeSpan TargetOffset
        {
            get
            {
                return targetOffset;
            }

            set
            {
                targetOffset = value;
                shift = targetOffset.Subtract(TimeZoneInfo.Local.BaseUtcOffset);
            }
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            var eventData = loggingEvent.GetLoggingEventData();
            eventData.TimeStamp = eventData.TimeStamp.Add(shift);
            base.Append(new LoggingEvent(eventData));
        }

        protected override void Append(LoggingEvent[] loggingEvents)
        {
            for (var i = 0; i < loggingEvents.Length; i++)
            {
                var eventData = loggingEvents[i].GetLoggingEventData();
                eventData.TimeStamp = eventData.TimeStamp.Add(shift);
                loggingEvents[i] = new LoggingEvent(eventData);
            }
            base.Append(loggingEvents);
        }
    }
}

And in .config

<log4net>
  <appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
       <!-- Your real appender here -->
  </appender>
  <appender name="TimeShiftAppender" type="Olekstra.TimeShiftForwardingAppender">
    <targetOffset>06:00:00</targetOffset> <!-- your desired (local) UTC offset value -->
    <appender-ref ref="FileAppender" /> <!-- real appender(s) -->
  </appender>
  <root>
    <level value="DEBUG" />
    <appender-ref ref="TimeShiftAppender" />
  </root>
</log4net>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜