记录的最佳方法是什么?

时间:2010-10-14 15:12:26

标签: .net vb.net logging

我的(本地,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日志记录类?

或者您可能会建议另一种解决方案吗?

5 个答案:

答案 0 :(得分:14)

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

  • 多个线程是否可以同时记录事件?此功能不是线程安全的

  • 是否需要错误通知?

  • 是否存在日志文件无边界增长而没有自动修剪的风险?

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

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

  • 您的程序是在多台计算机上运行的吗?如果是这样,日志如何传达给你?

  • 工具中是否有任何需要/值来帮助分析日志文件(单独使用或查找许多日志文件中的常见错误等模式)?

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

答案 1 :(得分:13)

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

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

以下是在代码中使用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");
  }
}

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

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

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

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

  3. Hierarichal记录器。

  4. Hierarichical loggers意味着您可以配置“祖先”记录器,任何“后代”记录器都将继承这些设置。例如,假设您有一个类,其完全(名称空间)限定类型名称是Namespace1.Namespace2.Class。使用NLog / log4net,您可以为“Namespace1”配置日志记录信息(级别,目标),如果您根据Namespace1中任何类型的完全限定名称请求了记录器,它将继承Namespace1的设置。通过查看Castle implemented their TraceSource-based logging抽象的方式,您可以使用TraceSources实现与此类似的操作。特别是,请查看Initialize函数。它非常容易实现(在你自己的TraceSource包装器中),并且作为附带的好处,使得TraceSources的配置更容易一些,因为你不必单独配置每个TraceSource。请注意,如果没有找到实际的祖先,您可以通过配置名为“”的TraceSource并在Castle方案中添加一些默认为“”配置的代码,轻松添加具有“root”配置的功能。 。例如,您可以配置“*”来记录,比如Verbose,然后专门配置某些TraceSource(按类或命名空间)关闭或处于不同的级别。如果没有hierarichal记录器,要使用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
    

    所以,你可以打开“亚马逊”日志和所有亚马逊的东西日志(无需显式配置每个“子”TraceSource)和数据库的东西不会。或者,你可以关闭Amazon和Amazon.Electronics,只有Amazon.Books(和孩子们)会记录。

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

是的,您可以考虑使用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

答案 4 :(得分:0)

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

E.g。

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