我正在寻找关于伐木的一些建议。我写了一个名为Logger
的包装器,它在内部使用Microsoft Enterprise Library 5.0。目前,它使我们能够以这种方式登录:
Logger.Error(LogCategory.Server, "Some message with some state {0}", state);
我面临的问题是EventViewer中的每个日志似乎都是无关的,即使其中一些以某种方式相关,例如它们都来自处理来自特定客户端的请求。
让我详细说明这个问题。假设我正在处理一个需要同时处理来自多个客户端的请求的服务,每个服务都将不同的参数集传递给服务方法。很少有参数可用于来识别请求,例如哪个客户端使用做什么 类型的请求唯一可识别的参数等。说这些参数是(调用上下文信息):
现在服务开始处理请求,一个接一个地做(比如工作流)。在这个过程中,我正在记录本地 1 消息,例如“找不到文件”或“在DB中找不到的条目,但我不知道我希望手动使用每个日志记录上述信息(上下文信息),而不是每次我记录本地消息时我都希望记录器自动记录它们:
Logger.Error(LogCategory.Server, "requested file not found");
我希望上面的调用记录上下文信息以及消息“请求的文件未找到”,这样我就可以将消息与其上下文联系起来。
问题是,我应该如何设计一个自动记录上下文的记录器包装器?我希望它足够灵活,以便我可以在服务处理请求的过程中添加更多特定的上下文信息,因为所有重要信息可能都不可用请求的开始!
我还想让它可配置,所以我可以记录本地消息而不记录上下文信息,因为当一切正常时它们不需要。 : - )
1。通过 local 消息,我的意思是更具体的消息,本质上是本地的。相比之下,我想说,上下文信息是全局消息,因为它们对处理请求的整个流程有意义。
答案 0 :(得分:4)
以下是一种使用企业库的方法,该方法相当容易设置。您可以使用Activity Tracing存储全局上下文和扩展属性来存储本地上下文。
为了举例,我将使用一个没有任何包装类的服务定位器来演示该方法。
var traceManager = EnterpriseLibraryContainer.Current.GetInstance<TraceManager>();
using (var tracer1 = traceManager.StartTrace("MyRequestId=" + GetRequestId().ToString()))
using (var tracer2 = traceManager.StartTrace("ClientID=" + clientId))
{
DoSomething();
}
static void DoSomething()
{
var logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
logWriter.Write("doing something", "General");
DoSomethingElse("ABC.txt");
}
static void DoSomethingElse(string fileName)
{
var logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
// Oops need to log
LogEntry logEntry = new LogEntry()
{
Categories = new string[] { "General" },
Message = "requested file not found",
ExtendedProperties = new Dictionary<string, object>() { { "filename", fileName } }
};
logWriter.Write(logEntry);
}
配置如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<loggingConfiguration name="" tracingEnabled="true" defaultCategory="General"
logWarningsWhenNoCategoriesMatch="false">
<listeners>
<add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
fileName="trace.log" formatter="Text Formatter" traceOutputOptions="LogicalOperationStack" />
</listeners>
<formatters>
<add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
template="Timestamp: {timestamp}
Message: {message}
ActivityID: {activity}
Context: {category}
Priority: {priority}
EventId: {eventid}
Severity: {severity}
Title:{title}
Machine: {localMachine}
App Domain: {localAppDomain}
ProcessId: {localProcessId}
Process Name: {localProcessName}
Thread Name: {threadName}
Win32 ThreadId:{win32ThreadId}
Local Context: {dictionary({key} - {value}{newline})}"
name="Text Formatter" />
</formatters>
<categorySources>
<add switchValue="All" name="General">
<listeners>
<add name="Flat File Trace Listener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="All" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors & Warnings" />
</specialSources>
</loggingConfiguration>
</configuration>
这将产生如下输出:
----------------------------------------
Timestamp: 1/16/2013 3:50:11 PM
Message: doing something
ActivityID: 5b765d8c-935a-445c-b9fb-bde4db73124f
Context: General, ClientID=123456, MyRequestId=8f2828be-44bf-436c-9e24-9641963db09a
Priority: -1
EventId: 1
Severity: Information
Title:
Machine: MACHINE
App Domain: LoggingTracerNDC.exe
ProcessId: 5320
Process Name: LoggingTracerNDC.exe
Thread Name:
Win32 ThreadId:8472
Local Context:
----------------------------------------
----------------------------------------
Timestamp: 1/16/2013 3:50:11 PM
Message: requested file not found
ActivityID: 5b765d8c-935a-445c-b9fb-bde4db73124f
Context: General, ClientID=123456, MyRequestId=8f2828be-44bf-436c-9e24-9641963db09a
Priority: -1
EventId: 0
Severity: Information
Title:
Machine: MACHINE
App Domain: LoggingTracerNDC.exe
ProcessId: 5320
Process Name: LoggingTracerNDC.exe
Thread Name:
Win32 ThreadId:8472
Local Context: filename - ABC.txt
----------------------------------------
注意事项:
如果要禁用全局上下文(在此实现中是跟踪),那么您需要做的就是编辑配置文件并设置tracingEnabled =“false”。
这似乎是使用内置企业库功能实现目标的一种相当直接的方式。
其他需要考虑的方法是潜在地使用某种拦截(自定义LogCallHandler),它可以非常优雅(但这可能取决于现有的设计)。
如果您打算使用自定义实现来收集和管理上下文,那么您可以考虑针对每个线程上下文使用Trace.CorrelationManager。您还可以查看创建IExtraInformationProvider
以填充扩展属性字典(有关示例,请参阅Enterprise Library 3.1 Logging Formatter Template - Include URL Request)。
答案 1 :(得分:1)
免责声明:我不知道Microsoft技术堆栈的具体细节。
在这种情况下我会做的是:
实现Singleton(在服务器实例级别,如果您的应用程序部署到集群,它不需要是全局单例),这基本上是一种Hashmap,其中“Key”是唯一有意义的标识符。请求您正在处理。 在Java中,我使用thread-id(假设您通过从线程池调度线程来提供请求)。 如果这是不可能/在你的情况下没有意义,你必须使用请求ID(但在这种情况下,你必须让它渗透到日志管理器,而我的想法是使用本质上可用的东西线程本身)。
Hashmap的“值”将是一组数据 - 在您的情况下,ServerProfileId,WebProfileId,RequestId(除非它已经是密钥),SessionInfo - 以便logmanager可以有条件地检索这些并获取对于特定的日志事件有意义。
因此:在请求管理开始时创建一个全局可用的请求状态引用,并确保日志记录管理器可以在需要时检索请求状态 。
当然,您必须确保正确管理散列图(通过在处理请求后删除状态)。