为了便于分析应用程序的运行情况和BUG诊断,一般都会搞个日志输出。

当初看过一点Log4net,觉得有些麻烦了,就动手写了个简单的。

本例子已经在 项目中使用过,拿出来分享一下,欢迎各位拍砖,呵呵。

本日志记录比较轻巧,在config文件里面配置后,把loghelper.cs 文件放到项目中即可使用。日志输出开关有四个:不输出、输出到DebugVIew、每次全新输出到文本、追加输出到文本。

输出的日志有特定的分隔符,可以放到excel里面,分割为每一列后继续进行筛选等分析。

本例子运行环境是DoNet 3.5 WPF C#,也可以扩展到别的环境使用.

 

效果预览

 

wordpress 报错日志 wpf 日志_日志输出

 

wordpress 报错日志 wpf 日志_UI_02

 

配置文件

当初想过使用ini文件或者xml文件存储配置信息,后来发现config文件用的比较多,而且config文件读取比较方便,索性就集成到Config文件里面。

在项目里面添加config文件即可。

1 <?xml version="1.0" encoding="utf-8" ?>
 2 <!-- Author      Shi Xiaokang
 3 
 4  Version     1.00    
 5  Date: 2011-1-21-->
 6 <configuration>
 7     <runtime>
 8         <generatePublisherEvidence enabled="false"/>
 9     </runtime>
10     <appSettings>
11         <!--
12         ;    0 - No output
13         ;    1 - Debugger (Such as DbgView)
14         ;    2 - File (Overwrite the old file and doesn't close it until application exits)
15         ;    3 - File (Append the log at the end of file and close it after each log output)
16         ;    4 - Debugger&File (Append the log at the end of file and close it after each log output)
17 -->
18         <add key="logDestination" value="4"/>
19         <!--log file path. if value is null or string.empty, don't ouput log to file-->
20         <!--example:%LocalAppData%\log.txt-->
21         <add key="logPath" value="%LocalAppData%\log.txt"/>
22     </appSettings>
23 </configuration>
logDestination
  • 0         没有任何日志输出
  • 1         可以输出到DebugView
  • 2         每次启动应用程序后,把上次写的日志清除掉,重新写一份日志
  • 3         第一次启动应用程序后,创建日志文件,后面一直累加

logPath 文本日志的文件位置, 推荐使用 AppData里面的路径,这个是系统默认的应用程序 数据存储路径。

如果搞别的,也可以,但是要考虑只读、权限等问题,由于客户机环境复杂,所以还是放在AppData 比较省心。

 

 使用方法

在需要打印日志的地方调用方法, 大致分为:简单打印、打印变量、打印方法执行结果、打印堆栈信息、打印异常。

下面只列举了一部分,

1 // UI|2011/12/20 14:57:39 630 | Test Write Method 
 2 LogHelper.Write("Test Write Method");
 3 
 4 bool? testBool = false;
 5 /// UI|2011/12/20 14:57:48 277 | False 
 6 LogHelper.Write(testBool);
 7 
 8 Double testDouble = 0.2256;
 9 /// UI|2011/12/20 14:57:48 279 | 0.2256 
10 LogHelper.Write(testDouble);
11 
12 /// UI|2011/12/20 15:01:28 801 | current ID:115001 Name:Jackon 
13 LogHelper.Write("current ID:{0} Name:{1}", 115001, "Jackon");
14 
15 bool? ret = DoTestIsOK();
16 /// UI|2011/12/20 15:17:04 732 | Method:DoTestIsOK --> Result:Null 
17 LogHelper.WriteMethod("DoTestIsOK", ret);
18 int a = 1, b = 3;
19 int ret = DoTestAdd(a, b);
20 
21 /// UI|2011/12/20 15:17:05 316 | Method:DoTestAdd --> Result:4 -- Parms:a:1 b:3 
22 LogHelper.WriteMethod("DoTestAdd", ret, "a:{0} b:{1}", a, b);
23

原理

C# 的Trace可以打印到output里面,Realse后,也可以打印到DebugView中。

这里的实现是丰富了Trace的功能,并且将日志输出为 不同的格式,打印出来后方便分析。

通过     Trace.Listeners 可以控制输出的目的地。

话不多说,都在代码里,如下:

1     #region init
  2     /// <summary>
  3 /// init by configuration
  4 /// </summary>
  5     public static void Init()
  6     {
  7         #region define
  8         string logPathKey = "logPath", logDestinationKey = "logDestination", autoFlushKey = "autoFlush";
  9         string logPath = string.Empty, logDestination = string.Empty;
 10         FileStream stream;
 11         FileMode fileMode;
 12         #endregion
 13 
 14         #region get destination
 15         //no destination,return
 16         if (!ConfigurationManager.AppSettings.AllKeys.Contains(logDestinationKey)) return;
 17         logDestination = ConfigurationManager.AppSettings[logDestinationKey].Trim();
 18 
 19         int logType = 0;
 20         Int32.TryParse(logDestination, out logType);
 21         //if logType == 0 , don't record log
 22         isLog = (logType != 0);
 23         #endregion
 24 
 25         
 26         
 27             
 28         
 29 
 30         #region switch log type
 31         switch (logType)
 32         {
 33             case 0:
 34                 {
 35                     //0 - No output
 36                     Trace.Listeners.Clear();
 37                     return;
 38                 }
 39             case 1:
 40                 {
 41                     //1 - Debugger (Such as DbgView)
 42 //use default listener
 43                     return;
 44                 }
 45             case 2:
 46                 {
 47                     //2 - File (Overwrite the old file and doesn't close it until application exits)
 48                     Trace.Listeners.Clear();
 49                     fileMode = FileMode.Create; break;
 50                 }
 51             case 3:
 52                 {
 53                     //3 - File (Append the log at the end of file and close it after each log output)
 54                     Trace.Listeners.Clear();
 55                     fileMode = FileMode.Append; break;
 56                 }
 57             case 4:
 58                 {
 59                     //4 - Debugger&File (Append the log at the end of file and close it after each log output)
 60                     fileMode = FileMode.Append; break;
 61                 }
 62 
 63             default: return;
 64         }
 65         #endregion
 66 
 67         #region check path
 68         //path is null
 69         logPath = ConfigurationManager.AppSettings[logPathKey].Trim();
 70         if (string.IsNullOrEmpty(logPath)) return;
 71 
 72         //path has invalid char
 73         var pathCharArray = logPath.ToCharArray();
 74         if (pathCharArray.Any(o => Path.GetInvalidPathChars().Contains(o)))
 75             return;
 76 
 77         //FileName has invalid char
 78 //note : invalid file name chars count is 41, 
 79 //invalid path  chars count  is 36
 80 //and , the top 36 of invalid file name chars  are  same as invalid path chars
 81 //so,first check path invalid chars,second check filename,only filename
 82         var filenameCharArray = Path.GetFileName(logPath).ToCharArray();
 83         if (filenameCharArray.Any(o => Path.GetInvalidFileNameChars().Contains(o)))
 84             return;
 85 
 86         //EnvironmentVariables Path
 87         if (logPath.Contains('%'))
 88             logPath = Environment.ExpandEnvironmentVariables(logPath);
 89 
 90         //cheng relative path to absolute path.
 91         if (String.IsNullOrEmpty(Path.GetPathRoot(logPath)))
 92             logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logPath);
 93         #endregion
 94 
 95         #region file log
 96         //risk:directory readonly;need administrator right to createfile;and so on
 97 //use try-catch
 98         try
 99         {
100             if (!Directory.Exists(Path.GetDirectoryName(logPath)))
101                 Directory.CreateDirectory(Path.GetDirectoryName(logPath));
102 
103             stream = File.Open(logPath, fileMode, FileAccess.Write, FileShare.ReadWrite);
104             TextWriterTraceListener text = new TextWriterTraceListener(stream);
105             //text.TraceOutputOptions = TraceOptions.DateTime;
106             Trace.Listeners.Add(text);
107         }
108         catch (Exception ex)
109         {
110             Trace.Write(ex);
111         }
112         #endregion
113 
114     }
115     #endregion

结束,欢迎拍砖。