2010-10-14 183 views
5

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

或者,也许你会建议另一种解决方案?

回答

14

如果这样的超级基本方法是适合您的需要功能足够了,你能坚持下来。但是,你可能会问自己几个问题,以确保:

  • 是否有可能要由多个线程同时记录的事件?这个功能是不是线程安全的

  • 是错误通知需要?

  • 有没有式增长,没有自动删除日志文件的风险?

  • 你会从更广泛的日志中受益,让您有关于事件导致了一个错误的详细信息?

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

  • 是否在多台计算机上的程序运行?如果是这样,日志如何做到?

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

如果您认为您有其他需求,也有一些免费的日志框架,如NLog or log4net,可以帮助记录更详细的日志,还有一些商业产品,如GIBRALTARSmartInspect可用,可以帮助与日志管理和分析。

+1

+1为线程安全点,但只有主线程推送日志事件。感谢您的全面回答。 – 2010-10-14 18:08:34

2

Nloglog4Net是在.NET项目记录流行的选择。

+0

两者都是很好的建议。我喜欢他们的配置。 – 2010-10-14 15:52:31

+0

log4Net规则! – user279521 2010-10-14 20:12:53

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 
+0

感谢您的详细帮助。我会研究在我的应用程序中包括这个。 – 2010-10-14 18:09:10

+0

System.Diagnostics可以写入除事件日志之外的其他位置。 – 2010-12-08 19:49:51

13

如前所述,NLOG和log4net的都是很好的日志框架。正如Jeff在上面提到的,System.Diagnostics也是一个合理的选择(不仅仅是记录到EventLog)。试图给我的答案增加一些价值,而不是仅仅喋喋不休地说,你可以使用TraceSources和免费的Ukadc.Diagnostics library from codeplex来增强你的System.Diagnostics日志记录。

使用TraceSources,您可以创建“命名记录器”,类似于您可以在NLog和log4net中执行的操作。这些TraceSources可以配置为在某些级别上记录(每个TraceSource都不相同),并可以将它们发送到不同的目标(TraceListeners)。所有TraceSources都可以登录到同一个监听器,或者一些可以登录到某些监听器,而其他监听器则可以登录到其他监听器。任何TraceSource也可以发送到多个TraceListeners。

这里是您如何在代码中使用TraceSources(假设TraceSource“abc”已在app.config文件中配置为记录“Info”和更高优先级的消息并且已配置为登录到文件“log”。文本”)。

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的风格输出格式,所以你可以有在什么领域在日志产出和显示更多的控制格式。

三件事情是非常有用的,从NLOG/log4net的不可用在System.Diagnostics程序是:

  1. 能够自动记录通话网站的信息(方法/功能)

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

  3. Hierarichal伐木工。

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

+0

感谢您的全面回答=)但是,如果我开始使用NLog,我的应用程序大小几乎会乘以5)这是一个非常轻的应用程序,因此它不需要*高级日志记录。但是,谢谢你的伟大答案,我将用它来做另一个项目。 – 2010-10-16 19:19:56

+1

很好的答案。非常全面,并有一个代码示例。好样的!这个信息正是我正在寻找的。 – 2010-11-29 18:04:04

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 
相关问题