如何优雅地记录上下文信息以及每条消息 [英] How to elegantly log contextual information along with every message

查看:85
本文介绍了如何优雅地记录上下文信息以及每条消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找有关日志记录的建议.我编写了一个名为 Logger 的包装器,该包装器内部使用了 Microsoft企业库5.0 .目前,它使我们能够以这种方式登录:

I'm looking for some advice on logging. I've written a wrapper called Logger which internally uses Microsoft Enterprise Library 5.0. Currently it enables us to log in this way:

Logger.Error(LogCategory.Server, "Some message with some state {0}", state);

我面临的问题是,即使其中的某些是某种相关的,EventViewer中的每个日志似乎也不相关,例如,它们全部来自处理特定客户端的请求.

The problem I face is that every log in the EventViewer seems to be unrelated even though some of them are somehow related, for example they all come from processing a request from a particular client.

让我详细说明这个问题.假设我正在开发一项服务,该服务需要同时处理来自多个客户端的请求,每个客户端都将不同的参数集传递给服务方法.很少可以使用参数 来标识请求,例如哪个客户端正在通过 what 发出 what 种请求.em>唯一可识别的参数,等等.假设这些参数是(称为上下文信息):

Let me elaborate on the problem. Suppose I'm working on a service which needs to handle requests from multiple clients at the same time, each passing different set of parameters to the service methods. Few of the parameters can be used to identify the requests, such as which client is making what kind of request with what uniquely identifiable parameters, etc. Say these parameters are (call the contextual information):

  • ServerProfileId
  • WebProfileId
  • RequestId
  • SessionInfo

现在,该服务开始处理请求,一件又一件地做(如工作流).在此过程中,我正在记录本地 1 消息,例如找不到文件" 在数据库中找不到条目" ,但是我没有不想在每条日志中都手动记录上述信息(上下文信息),而是希望记录器在每次记录本地消息时都自动记录它们:

Now the service started processing the requests, doing one thing after another (like a workflow). In the process I'm logging local1 messages such as "file not found" or "entry not found in DB", but I don't want to manually log the above information (the contextual information) with every log, rather I want the logger to log them automatically every time I log local message:

Logger.Error(LogCategory.Server, "requested file not found");

我希望以上调用记录上下文信息以及消息未找到请求的文件" ,以便将消息与其上下文相关联.

And I want the above call to log the contextual information along with the message "requested file not found" so I can relate the message with its context.

问题是,我应该如何设计这样一种自动记录上下文的记录器包装器?我希望它足够灵活,以便我可以在服务处理请求的过程中添加更多特定上下文信息,因为所有重要信息可能不可用请求的开始!

The question is, how should I design such a logger wrapper which logs contexts automatically? I want it to be flexible enough, so that I may add more specific contextual information along the way the service processes the request, as all the important information may not be available in the beginning of the request!

我还想使其可配置,因此我可以记录本地消息而无需记录上下文信息,因为在一切正常的情况下不需要它们.:-)

I also want to make it configurable, so I can log the local messages without logging the context information, as they're not needed when everything works great. :-)

1." local "消息是指本质上更具体的消息.相比之下,我要说的是,上下文信息是 global 消息,因为它们对于处理请求的整个流程都是有意义的.

1. By local message I mean the messages which is more specific, local in nature. By contrast, I would say, the contextual informations are the global messages, as they make sense for the entire flow of processing a request.

推荐答案

这里是使用企业库的一种方法,该方法非常容易设置.您可以将活动跟踪用于存储全局上下文和用于存储本地上下文的扩展属性.

Here is one approach that uses Enterprise Library that is fairly easy to setup. You can use Activity Tracing for storing global context and Extended Properties for storing local context.

为了举例说明,我将使用不带任何包装器类的服务定位器来演示该方法.

For the sake of an example I'll use a service locator without any wrapper class to demonstrate the approach.

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}&#xA;Message: {message}&#xA;ActivityID: {activity}&#xA;Context: {category}&#xA;Priority: {priority}&#xA;EventId: {eventid}&#xA;Severity: {severity}&#xA;Title:{title}&#xA;Machine: {localMachine}&#xA;App Domain: {localAppDomain}&#xA;ProcessId: {localProcessId}&#xA;Process Name: {localProcessName}&#xA;Thread Name: {threadName}&#xA;Win32 ThreadId:{win32ThreadId}&#xA;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 &amp; 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

----------------------------------------

注意事项:

  • 由于我们正在使用跟踪,因此免费获得了.NET活动ID,该ID可用于关联活动.当然,我们也可以使用我们自己的上下文信息(自定义请求ID,客户ID等).
  • 企业库使用跟踪操作名称"作为类别,因此我们需要设置logWarningsWhenNoCategoriesMatch ="false",否则我们将收到大量警告消息.
  • 这种方法的缺点可能是性能(但我还没有衡量).

如果要禁用全局上下文(在此实现中为跟踪),那么您需要做的就是编辑配置文件并设置tracingEnabled ="false".

If you want to disable global context (which is, in this implementation, tracing) then all you need to do is edit the configuration file and set tracingEnabled="false".

这似乎是使用内置的企业库功能来实现目标的相当简单的方法.

This seems to be a fairly straight forward way to achieve your objectives using built-in Enterprise Library functionality.

要考虑的其他方法可能是潜在地使用某种拦截(自定义LogCallHandler),这种拦截可能非常优雅(但这可能取决于现有设计).

Other approaches to consider would be to potentially use some sort of interception (custom LogCallHandler) which can be quite elegant (but that might depend on the existing design).

如果要使用自定义实现来收集和管理上下文,则可以考虑使用 IExtraInformationProvider 来填充扩展属性字典(请参见

If you are going to go with a custom implementation to collect and manage context then you could consider looking at using Trace.CorrelationManager for per thread context. You could also look at creating an IExtraInformationProvider to populate the extended properties dictionary (see Enterprise Library 3.1 Logging Formatter Template - Include URL Request for an example).

这篇关于如何优雅地记录上下文信息以及每条消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆