【问题标题】:What's the best approach to logging? [closed]记录日志的最佳方法是什么? [关闭]
【发布时间】:2011-04-25 11:35:01
【问题描述】:

我的(本地,windows/mono)应用程序将重要事件记录到文本文件中。在突然崩溃/失败/强制退出的情况下,任何数据都不应保持未写入状态(尽可能)。因此,我目前使用一种简单的追加到文本文件的方法:

Public Shared Sub LogAppEvent(ByVal EventData As String)
    Dim Config As ConfigHandler = ConfigHandler.GetSingleton()
    Dim AppLog As New IO.StreamWriter(Config.GetUserFilesRootDir() & ConfigOptions.AppLogName, True)
    AppLog.WriteLine(String.Format("[{0}] {1}", Date.Now.ToString(), EventData))
    AppLog.Close()
End Sub

这是非常次优的,但日志事件非常少见。您是否建议改用 System.Diagnostics 日志记录类?

或者您会建议其他解决方案吗?

【问题讨论】:

    标签: .net vb.net logging


    【解决方案1】:

    我使用公共变量和计时器将新行附加到 txt 文件。

    例如

    Public Class Form1
    
        Public WriteToLog = ""
    
        Dim LogFilePath As String = My.Application.Info.DirectoryPath & "\applog.txt"
    
    ....
    
        Public Function Log_to_txt(ByVal text As String)
    
            Dim CurDate As String
            CurDate = Format(Now, "General Date")
    
            WriteToLog = WriteToLog & "[" & CurDate & "] " & text & vbCrLf
    
            Return True
    
        End Function
    
    ...
    
    Log_to_txt("Application started...")
    
    ...
    
        Private Sub WriteToLogTimer_Tick(sender As Object, e As EventArgs) Handles WriteToLogTimer.Tick
    
            Dim CatchLog As String = WriteToLog
    
            WriteToLog = ""
    
            Try
    
                My.Computer.FileSystem.WriteAllText(LogFilePath, CatchLog, True)
    
            Catch ex As IOException
    
            End Try
    
        End Sub
    

    【讨论】:

      【解决方案2】:

      如前所述,NLog 和 log4net 都是很好的日志框架。正如 Jeff 上面提到的,System.Diagnostics 也是一个合理的选择(不仅仅是记录到 EventLog)。尝试为我的回答增加一些价值,而不仅仅是重复已经说过的话,您可以使用TraceSources 和免费的Ukadc.Diagnostics library from codeplex 来增强您的 System.Diagnostics 日志记录。

      使用 TraceSources,您可以创建“命名记录器”,类似于您在 NLog 和 log4net 中的操作方式。这些 TraceSource 可以配置为在特定级别进行日志记录(每个 TraceSource 不同),并且可以将它们发送到各种目的地(TraceListeners)。所有 TraceSource 都可以记录到同一个侦听器,或者一些可以记录到一些侦听器,而另一些则记录到其他侦听器。任何 TraceSource 也可以发送到多个 TraceListener。

      以下是在代码中使用 TraceSources 的方式(假设在 app.config 文件中已配置 TraceSource“abc”以记录“Info”和更高优先级的消息,并已配置为记录到文件“log.txt” ")。

      public class MyClass
      {
        static TraceSource ts = new TraceSource("abc"); //Common idiom for NLog and log4net, not sure if as common for TraceSource
      
        public void Func1(int x)
        {
          ts.Information("Entering Func1");
          ts.Verbose("x = {0}", x); //Won't log if "abc" is configured to log Info and HIGHER messgaes
          ts.Information("Exiting Func1");
        }
      }
      

      与“普通” TraceSources 相比,Ukadc.Diagnostics 的一个巨大优势是您可以配置 NLog/log4net 样式的输出格式,以便您可以更好地控制日志输出中显示的字段和格式。

      在 System.Diagnostics 中不可用的 NLog/log4net 中非常有用的三件事是:

      1. 能够自动记录呼叫站点信息(方法/功能)

      2. 附加日志记录上下文(GDC - 全局日志记录属性,MDC - NLog/log4net 用语中的线程日志记录属性)。 System.Diagnostics 确实有 Trace.CorrelationManager.LogicalOperationStack,类似于 NDC。

      3. 分层记录器。

      分层记录器意味着您可以配置“祖先”记录器,并且任何“后代”记录器都将继承这些设置。例如,假设您有一个类,其完全(命名空间)限定类型名称是 Namespace1.Namespace2.Class。使用 NLog/log4net,您可以为“Namespace1”配置日志信息(级别、目标),如果您请求基于 Namespace1 中任何类型的完全限定名称的记录器,它将继承 Namespace1 的设置。通过查看 Castle implemented their TraceSource-based logging 抽象的方式,您可以使用 TraceSources 实现类似的目标。特别是,查看 Initialize 函数。它很容易开始工作(在您自己的 TraceSource 周围的瘦包装器中),并且作为附带的好处,使 TraceSource 的配置更容易一些,因为您不必单独配置每个 TraceSource。请注意,如果没有找到实际的祖先,您可以通过配置名为“”的 TraceSource 并在 Castle 方案中添加一些代码以默认为“”配置来轻松添加具有“根”配置的功能.例如,您可以将“*”配置为登录,例如 Verbose,然后专门将某些 TraceSource(按类或按命名空间)配置为关闭或处于不同级别。如果没有分层记录器,要使用 TraceSources 执行相同的操作,您需要将每个 TraceSource 配置为以“详细”记录,而您想要详细记录。

      虽然我谈了很多关于类和命名空间的记录器,但 NLog、log4net 和 TraceSources 都允许您将记录器名称定义为任意字符串。因此,您可以通过功能区域而不是命名空间/类来冷定义记录器层次结构:

      Database
      Database.Connect
      Database.Query
      Database.Update
      Database.SQL
      Amazon
      Amazon.Books
      Amazon.Books.Fiction
      Amazon.Books.Nonfiction
      Amazon.Electronics
      Amazon.Electronics.Video
      Amazon.Electronics.Music
      Amazon.Electronics.Computer
      

      因此,您可以打开“Amazon”日志记录和所有 Amazon 内容日志(无需显式配置每个“子”TraceSource),而数据库内容则不会。或者,您可以打开 Amazon 并关闭 Amazon.Electronics,然后只有 Amazon.Books(和儿童)会登录。

      最后,如果你使用 NLog 或 log4net,值得一提的是,NLog 刚刚发布了一个新版本,NLog 2.0,(测试版)。

      【讨论】:

      • 感谢您的详尽回答 =) 但是,如果我开始使用 NLog,我的应用程序大小几乎会乘以 5 :) 这是一个非常轻量级的应用程序,所以它真的不需要 那个 高级日志记录。然而,感谢您的出色回答,我将用于另一个项目。
      • 很好的答案。非常彻底,并且有一个代码示例。太棒了!这些信息正是我想要的。
      【解决方案3】:

      是的,您可以考虑 System.Diagnostics。只要您不编写大量事件,Windows 事件日志的优势就是管理员可以在一个地方查找来自所有应用程序的所有事件。

      如果您决定走这条路,这里有一些 VB.NET 代码可以帮助您:

      Imports System.Diagnostics
      
      Public Function WriteToEventLog(ByVal Entry As String, _
         Optional ByVal AppName As String = "VB.NET Application", _
         Optional ByVal EventType As _
         EventLogEntryType =  EventLogEntryType.Information, _
         Optional ByVal LogName As String = "Application") As Boolean
      
      '*************************************************************
       'PURPOSE: Write Entry to Event Log using VB.NET
       'PARAMETERS: Entry - Value to Write
       '            AppName - Name of Client Application. Needed 
       '              because before writing to event log, you must 
       '              have a named EventLog source. 
       '            EventType - Entry Type, from EventLogEntryType 
       '              Structure e.g., EventLogEntryType.Warning, 
       '              EventLogEntryType.Error
       '            LogName: Name of Log (System, Application; 
       '              Security is read-only) If you 
       '              specify a non-existent log, the log will be
       '              created
      
       'RETURNS:   True if successful, false if not
      
       'EXAMPLES: 
       '1. Simple Example, Accepting All Defaults
       '    WriteToEventLog "Hello Event Log"
      
       '2.  Specify EventSource, EventType, and LogName
       '    WriteToEventLog("Danger, Danger, Danger", "MyVbApp", _
       '                      EventLogEntryType.Warning, "System")
       '
       'NOTE:     EventSources are tightly tied to their log. 
       '          So don't use the same source name for different 
       '          logs, and vice versa
              '******************************************************
      
              Dim objEventLog As New EventLog()
      
              Try
                  'Register the App as an Event Source
                  If Not objEventLog.SourceExists(AppName) Then
      
                      objEventLog.CreateEventSource(AppName, LogName)
                  End If
      
                  objEventLog.Source = AppName
      
                  'WriteEntry is overloaded; this is one
                  'of 10 ways to call it
                  objEventLog.WriteEntry(Entry, EventType)
                  Return True
              Catch Ex As Exception
                  Return False
      
              End Try
      
          End Function
      

      【讨论】:

      • 感谢您提供详细的帮助。我会考虑将其包含在我的应用中。
      • System.Diagnostics 可以写入事件日志以外的其他地方。
      【解决方案4】:

      如果像这样的超级基本方法在功能上足以满足您的需求,您可以坚持下去。但是,您可能会问自己几个问题以确保:

      • 是否可以由多个线程同时记录事件?这个函数不是线程安全的

      • 是否需要错误通知?

      • 如果没有自动修剪,是否存在日志文件无限增长的风险?

      • 您是否会从更广泛的日志记录中受益,从而获得有关导致错误的事件的更多信息?

      • 您是否会受益于有关错误的更多详细信息(堆栈跟踪、异常详细信息等)

      • 您的程序是否可以在多台计算机上运行?如果是这样,日志如何发送给您?

      • 工具是否有任何需要/价值来帮助分析日志文件(单独分析或查找模式,例如跨多个日志文件的常见错误)?

      如果您确定自己有其他要求,有许多免费的日志框架,例如 NLog or log4net,可以帮助记录更详细的日志,还有一些商业产品,例如 GIBRALTARSmartInspect可以帮助进行日志管理和分析。

      【讨论】:

      • +1 表示线程安全点,尽管只有主线程推送日志事件。感谢您的全面回答。
      【解决方案5】:

      Nloglog4Net 是登录 .net 项目的热门选择。

      【讨论】:

      • 两者都是很好的建议。我喜欢他们的配置。
      猜你喜欢
      • 2011-06-23
      • 2013-11-19
      • 1970-01-01
      • 2010-10-08
      • 1970-01-01
      • 2015-08-05
      • 2017-11-17
      • 2010-09-07
      • 1970-01-01
      相关资源
      最近更新 更多