我怎样才能让 log4net 为 Parallel.Invoke 中的每个操作创建一个单独的日志文件?
How can I have log4net create a separate log file for each Action in a Parallel.Invoke?
我有一系列 Action
,我想使用 Parallel.Invoke
并行执行。但是对于每个 Action
我想要一个由 log4net 创建的单独的日志文件。在我的 log4net 配置文件中,我添加了这个:
<file type="log4net.Util.PatternString" value="3S2M3_%property{UniqueIdentifier}.log" />
如果只有一个操作可执行,则此操作正常:日志文件具有正确的文件名。
但是,如果要执行多个 Action
,所有日志条目最终都会在同一个日志文件中。
创建 Action
的代码是这样的:
Dim lstActions(4) As Action
Dim iCount As Integer = 0
For iCount = 0 To 4
Dim sUniqueIdentifier As String = iCount.ToString("D4")
Dim aOrderTask As Action = Sub()
log4net.LogicalThreadContext.Properties("UniqueIdentifier") = sUniqueIdentifier
' Some process that takes some time to complete
End Sub
lstActions(iCount) = aOrderTask
Next
Parallel.Invoke(lstActions)
创建的日志文件正在使用分配给 UniqueIdentifier
属性 的值之一。我无法弄清楚如何选择这个值:它并不总是第一个或最后一个。在上面的示例中,只创建了文件 3S2M3_0004.log
,它包含所有日志条目。
我已经尝试了 LogicalThreadContext 和 ThreadContext,但没有区别。
log4net 在加载配置时分配日志文件名,因此您需要在运行时设置自定义名称。
另一件需要注意的事情是 log4net 在记录器之间共享 appender,因此要同时记录到不同的文件,您将需要以编程方式分配 appender,并且您将必须在该过程中执行此操作,而不是在外面。
(如果你真的不想在代码中设置附加程序属性,你可以在配置中定义一个,从层次结构中获取它,并为每个任务克隆它。无论哪种方式,任务的每个实例需要它自己的记录器和一个独特的附加程序)
所以,给定这样的配置:
<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="false">
<root>
<level value="DEBUG" />
</root>
<!-- more config -->
<logger name="EmptyLogger" additivity="false">
</logger>
<!-- additivity="false" specifies not to load any appenders defined on the root logger -->
</log4net>
然后你可以有这样的代码:
Private Shared Sub ProcessThatTakesSomeTimeToComplete()
Dim sUniqueIdentifier As New String(Guid.NewGuid().ToString("N").Take(4).ToArray())
' Get a uniquely-named empty logger containing no appenders
Dim log = LogManager.GetLogger("EmptyLogger." & sUniqueIdentifier)
' Create an appender manually, setting the path as required
Dim sPath As New String(Path.Combine("c:\temp", sUniqueIdentifier & ".log"))
Dim appender = New FileAppender() With { _
.Layout = New PatternLayout("%date [%thread] %message"), _
.File = sPath, _
.AppendToFile = True _
}
appender.ActivateOptions()
' Add the appender to the logger
DirectCast(log.Logger, Logger).AddAppender(appender)
' And off we go.
log.Debug("Hello from thread " + Thread.CurrentThread.ManagedThreadId)
Thread.Sleep(100)
End Sub
进口:
Imports System.IO
Imports System.Threading
Imports log4net
Imports log4net.Appender
Imports log4net.Layout
Imports log4net.Repository.Hierarchy
我有一系列 Action
,我想使用 Parallel.Invoke
并行执行。但是对于每个 Action
我想要一个由 log4net 创建的单独的日志文件。在我的 log4net 配置文件中,我添加了这个:
<file type="log4net.Util.PatternString" value="3S2M3_%property{UniqueIdentifier}.log" />
如果只有一个操作可执行,则此操作正常:日志文件具有正确的文件名。
但是,如果要执行多个 Action
,所有日志条目最终都会在同一个日志文件中。
创建 Action
的代码是这样的:
Dim lstActions(4) As Action
Dim iCount As Integer = 0
For iCount = 0 To 4
Dim sUniqueIdentifier As String = iCount.ToString("D4")
Dim aOrderTask As Action = Sub()
log4net.LogicalThreadContext.Properties("UniqueIdentifier") = sUniqueIdentifier
' Some process that takes some time to complete
End Sub
lstActions(iCount) = aOrderTask
Next
Parallel.Invoke(lstActions)
创建的日志文件正在使用分配给 UniqueIdentifier
属性 的值之一。我无法弄清楚如何选择这个值:它并不总是第一个或最后一个。在上面的示例中,只创建了文件 3S2M3_0004.log
,它包含所有日志条目。
我已经尝试了 LogicalThreadContext 和 ThreadContext,但没有区别。
log4net 在加载配置时分配日志文件名,因此您需要在运行时设置自定义名称。
另一件需要注意的事情是 log4net 在记录器之间共享 appender,因此要同时记录到不同的文件,您将需要以编程方式分配 appender,并且您将必须在该过程中执行此操作,而不是在外面。
(如果你真的不想在代码中设置附加程序属性,你可以在配置中定义一个,从层次结构中获取它,并为每个任务克隆它。无论哪种方式,任务的每个实例需要它自己的记录器和一个独特的附加程序)
所以,给定这样的配置:
<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="false">
<root>
<level value="DEBUG" />
</root>
<!-- more config -->
<logger name="EmptyLogger" additivity="false">
</logger>
<!-- additivity="false" specifies not to load any appenders defined on the root logger -->
</log4net>
然后你可以有这样的代码:
Private Shared Sub ProcessThatTakesSomeTimeToComplete()
Dim sUniqueIdentifier As New String(Guid.NewGuid().ToString("N").Take(4).ToArray())
' Get a uniquely-named empty logger containing no appenders
Dim log = LogManager.GetLogger("EmptyLogger." & sUniqueIdentifier)
' Create an appender manually, setting the path as required
Dim sPath As New String(Path.Combine("c:\temp", sUniqueIdentifier & ".log"))
Dim appender = New FileAppender() With { _
.Layout = New PatternLayout("%date [%thread] %message"), _
.File = sPath, _
.AppendToFile = True _
}
appender.ActivateOptions()
' Add the appender to the logger
DirectCast(log.Logger, Logger).AddAppender(appender)
' And off we go.
log.Debug("Hello from thread " + Thread.CurrentThread.ManagedThreadId)
Thread.Sleep(100)
End Sub
进口:
Imports System.IO
Imports System.Threading
Imports log4net
Imports log4net.Appender
Imports log4net.Layout
Imports log4net.Repository.Hierarchy