【问题标题】:log4Net causing thread to be blockedlog4Net 导致线程被阻塞
【发布时间】:2017-07-21 16:20:01
【问题描述】:

我正在使用 log4Net 记录活动,在分析来自 perfmon 的堆栈跟踪后,我看到有如下所示的死锁场景

    ntdll!NtWaitForMultipleObjects+a
    KERNELBASE!WaitForMultipleObjectsEx+e1
    clr!WaitForMultipleObjectsEx_SO_TOLERANT+62 
    clr!Thread::DoAppropriateWaitWorker+1e4 
    clr!Thread::DoAppropriateWait+7d 
    clr!CLREventBase::WaitEx+c4
    clr!AwareLock::EnterEpilogHelper+ca
    [[GCFrame]] 
    clr!AwareLock::EnterEpilog+62 
    clr!AwareLock::Contention+2a7f4a
    clr!JITutil_MonContention+af
    [[GCFrame]] 
    [[HelperMethodFrame] (System.Threading.Monitor.Enter)] System.Threading.Monitor.Enter(System.Object) 
    log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)+47 
    log4net.Util.AppenderAttachedImpl.AppendLoopOnAppenders(log4net.Core.LoggingEvent)+a8
    log4net.Repository.Hierarchy.Logger.CallAppenders(log4net.Core.LoggingEvent)+74 
    log4net.Repository.Hierarchy.Logger.Log(System.Type, log4net.Core.Level, System.Object, System.Exception)+6a
    log4net.Core.LogImpl.InfoFormat(System.String, System.Object)+cc
    Archival.Logic.Status(Archival.ProcessArgs)+240 
    Archival.Logic.Product(Archival.ProcessArgs)+221 
    Archival.Logic.Number(Archival.ProcessArgs, System.Collections.Generic.IEnumerable`1<LenderProduct>)+2e9 
    Archival.Logic+<>c__DisplayClass3_0.<ArchiveDealsPerAsset>b__1(System.String)+b5
    mscorlib_ni!System.Threading.Tasks.Parallel+<>c__DisplayClass42_0`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].<PartitionerForEachWorker>b__1()+2bd
    mscorlib_ni!System.Threading.Tasks.Task.InnerInvokeWithArg(System.Threading.Tasks.Task)+20 
    mscorlib_ni!System.Threading.Tasks.Task+<>c__DisplayClass176_0.<ExecuteSelfReplicating>b__0(System.Object)+114 
    mscorlib_ni!System.Threading.Tasks.Task.Execute()+46 
    mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+162 
    mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+14 
    mscorlib_ni!System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)+21c
    mscorlib_ni!System.Threading.Tasks.Task.ExecuteEntry(Boolean)+73 
    mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch()+152 
    clr!CallDescrWorkerInternal+83 
    clr!CallDescrWorkerWithHandler+4e 
    clr!MethodDescCallSite::CallTargetWorker+f8
    clr!QueueUserWorkItemManagedCallback+2a
    clr!ManagedThreadBase_DispatchInner+39 
    clr!ManagedThreadBase_DispatchMiddle+6c
    clr!ManagedThreadBase_DispatchOuter+75 
    [[DebuggerU2MCatchHandlerFrame]] 
    clr!ManagedThreadBase_FullTransitionWithAD+2f 
    clr!ManagedPerAppDomainTPCount::DispatchWorkItem+a0
    clr!ThreadpoolMgr::ExecuteWorkRequest+64 
    clr!ThreadpoolMgr::WorkerThreadStart+f5
    clr!Thread::intermediateThreadProc+86 
    kernel32!BaseThreadInitThunk+22 
    ntdll!RtlUserThreadStart+34 

我初始化记录器

private static readonly ILog logger = LogManager.GetLogger(typeof(Program));

可以做些什么来避免这种情况。 我已经查看了添加每个线程日志的选项。但是,这将是一个过度杀伤,因为我每天将有 100 个日志。

以下是log4Net的配置:

<log4net>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
  <mapping>
    <level value="ERROR"/>
    <foreColor value="White"/>
    <backColor value="Red"/>
  </mapping>
  <mapping>
    <level value="WARN"/>
    <foreColor value="White"/>
    <backColor value="Yellow"/>
  </mapping>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] - %message%newline"/>
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="INFO"/>
  </filter>
</appender>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
  <file value="Logs\logfile.txt"/>
  <appendToFile value="true"/>
  <rollingStyle value="Date"/>
  <datePattern value="yyyyMMdd"/>
  <maxSizeRollBackups value="3"/>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level - %message%newline"/>
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="INFO"/>
  </filter>
</appender>
<root>
  <level value="ALL"/>
  <appender-ref ref="ColoredConsoleAppender"/>
  <appender-ref ref="RollingLogFileAppender"/>
</root>

【问题讨论】:

  • 确定您使用的是 NLog 而不是 log4net,因为 log4net 是您的堆栈跟踪的一部分?
  • @RolfKristensen 是的,我正在使用 Log4Net。改了标题
  • 你的appender配置是什么?
  • @Peter 添加配置
  • 您记录事件的速度有多快?您的 RollingLogFileAppender 未设置为使用最小锁定,这应该意味着文件在程序启动时被锁定,并且没有为每个事件锁定/解锁。所以我不认为你看到的锁与实际写入文件有关,如果是这种情况,每个线程使用不同的文件可能无法解决问题。

标签: c# log4net deadlock perfmon


【解决方案1】:

只是猜测发生了什么,由于某种原因,当您要写入文件时,Logs\logfile.txt 被锁定。第二条日志消息将等到第一条日志消息完成(您的堆栈跟踪)。最小锁定在这里对您没有帮助,因为您仍然需要锁定文件。当您要访问日志文件时,您需要先复制它,然后使用检查工具打开复制的日志文件版本。这样您就可以确定您不会阻止想要记录到日志文件的进程。

【讨论】:

  • 将为每个 logger.InfoFormat("Message to be logged") 帮助添加一个锁/监视器。这会导致性能问题吗?
  • 如果文件被锁定,您将获得相同的提升条件
  • 我怎样才能解决这种情况?任何建议
  • @user2526236 如果您添加一个可重现的示例会有所帮助。
  • @stuartd 我无法重现该问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
  • 2015-04-09
  • 2016-09-30
  • 1970-01-01
相关资源
最近更新 更多