http://www.pfeng.org/archives/395
稳定轻量级的Delphi日志类
开发应用软件,有一个很重要的环节就是记录软件运行日志,delphi下有很多优秀的开源项目,如Log4D(http://sourceforge.net/projects/log4d/)等。考虑到日常应用的便捷性,自己写了一个简单的日志类,我把它命名为:Logger,支持同时显示到容器(TMemo、TListBox、TListView)和按日志级别决定是否写入文本,内部通过临界区的方法来保证线程安全,在子线程里可以安全使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
unit Logger; //======================================================================= // 日志类(TLoger) ver.1.0 // PFeng (http://www.pfeng.org / xxmc01#gmail.com) // 2012/11/08 // 日志级别约定: // 0 - Information // 1 - Notice // 2 - Warning // 3 - Error //======================================================================= interface uses Windows,Classes, SysUtils,StdCtrls,ComCtrls,ComObj,Messages; const WRITE_LOG_DIR = 'log\'; //记录日志默认目录 WRITE_LOG_MIN_LEVEL = 2 ; //记录日志的最低级别,小于此级别只显示不记录 WRITE_LOG_ADD_TIME = True ; //记录日志是否添加时间 WRITE_LOG_TIME_FORMAT = 'hh:nn:ss.zzz' ; //记录日志添加时间的格式 SHOW_LOG_ADD_TIME = True ; //日志显示容器是否添加时间 SHOW_LOG_TIME_FORMAT = 'yyyy/mm/dd hh:nn:ss.zzz' ; //日志显示添加时间的格式 SHOW_LOG_CLEAR_COUNT = 1000 ; //日志显示容器最大显示条数 type TLogger = class private FCSLock: TRTLCriticalSection; //临界区 FFileStream: TFileStream; //文件流 FLogShower: TComponent; //日志显示容器 FLogDir: AnsiString ; //日志目录 FLogName: AnsiString ; //日志名称 protected procedure ShowLog(Log: AnsiString ; const LogLevel: Integer = 0 ); public procedure WriteLog(Log: AnsiString ; const LogLevel: Integer = 0 ); overload; procedure WriteLog(Log: AnsiString ; const Args: array of const ; const LogLevel: Integer = 0 );overload; constructor Create(LogShower: TComponent;LogDir: AnsiString ); destructor Destroy; override; end ; implementation constructor TLogger . Create(LogShower: TComponent;LogDir: AnsiString ); begin InitializeCriticalSection(FCSLock); FLogShower := LogShower; if Trim(LogDir) = '' then FLogDir := ExtractFilePath(ParamStr( 0 )) + WRITE_LOG_DIR else FLogDir := LogDir; if not DirectoryExists(FLogDir) then if not ForceDirectories(FLogDir) then begin raise Exception . Create( '日志路径错误,日志类对象不能被创建' ); end ; end ; procedure TLogger . WriteLog(Log: AnsiString ; const Args: array of const ; const LogLevel: Integer = 0 ); begin WriteLog(Format(Log, args),LogLevel); end ; procedure TLogger . WriteLog(Log: AnsiString ; const LogLevel: Integer = 0 ); var logName: AnsiString ; fMode: Word ; begin EnterCriticalSection(FCSLock); try ShowLog(Log,LogLevel); //显示日志到容器 if LogLevel >= WRITE_LOG_MIN_LEVEL then begin logName := FormatDateTime( 'yyyymmdd' ,Now)+ '.log' ; if FLogName <> logName then FLogName := logName; if FileExists(FLogDir+FLogName) then //如果当天的日志文件存在 fMode := fmOpenWrite or fmShareDenyNone else fMode := fmCreate or fmShareDenyNone; if Assigned(FFileStream) then FreeAndNil(FFileStream); FFileStream := TFileStream . Create(FLogDir+FLogName,fmode); FFileStream . Position := FFileStream . Size; //追加到最后 case LogLevel of 0 : Log := '[Information] ' + Log; 1 : Log := '[Notice] ' + Log; 2 : Log := '[Warning] ' + Log; 3 : Log := '[Error] ' + Log; end ; if WRITE_LOG_ADD_TIME then Log := FormatDateTime(WRITE_LOG_TIME_FORMAT, Now) + ' ' + Log + # 13 # 10 ; FFileStream . Write ( PAnsiChar (Log)^, StrLen( PAnsiChar (Log))); end ; finally LeaveCriticalSection(FCSLock); end ; end ; procedure TLogger . ShowLog(Log: AnsiString ; const LogLevel: Integer = 0 ); var lineCount: Integer ; listItem: TListItem; begin if FLogShower = nil then Exit; if (FLogShower is TMemo) then begin if SHOW_LOG_ADD_TIME then Log := FormatDateTime(SHOW_LOG_TIME_FORMAT, Now) + ' ' + Log; lineCount := TMemo(FLogShower).Lines . Add(Log); //滚屏到最后一行 SendMessage(TMemo(FLogShower).Handle,WM_VSCROLL,SB_LINEDOWN, 0 ); if lineCount >= SHOW_LOG_CLEAR_COUNT then TMemo(FLogShower).Clear; end else if (FLogShower is TListBox) then begin if SHOW_LOG_ADD_TIME then Log := FormatDateTime(SHOW_LOG_TIME_FORMAT, Now) + ' ' + Log; lineCount := TListBox(FLogShower).Items . Add(Log); SendMessage(TListBox(FLogShower).Handle,WM_VSCROLL,SB_LINEDOWN, 0 ); if lineCount >= SHOW_LOG_CLEAR_COUNT then TListBox(FLogShower).Clear; end else if (FLogShower is TListView) then begin ListItem := TListView(FLogShower).Items . Add; if SHOW_LOG_ADD_TIME then ListItem . Caption := FormatDateTime(SHOW_LOG_TIME_FORMAT, Now); if Assigned(TListView(FLogShower).SmallImages) and (TListView(FLogShower).SmallImages . Count - 1 >= LogLevel) then ListItem . ImageIndex := LogLevel; //可以根据不同等级显示不同图片 ListItem . SubItems . Add(Log); SendMessage(TListView(FLogShower).Handle,WM_VSCROLL,SB_LINEDOWN, 0 ); if TListView(FLogShower).Items . Count >= SHOW_LOG_CLEAR_COUNT then TListView(FLogShower).Items . Clear; end else raise Exception . Create( '日志容器类型不支持:' + FLogShower . ClassName); end ; destructor TLogger . Destroy; begin DeleteCriticalSection(FCSLock); end ; end . |
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
uses Logger; //...省略 var Logger:Tlogger; //...省略 procedure TForm1 . FormCreate(Sender: TObject); begin Logger := TLogger . Create(Memo1, '' ); //使用默认路径 end ; procedure TForm1 . Button1Click(Sender: TObject); var i: Integer ; begin for i := 0 to 199 do begin Logger . WriteLog( '日志计数 %d' ,[i], 2 ); //Logger.WriteLog('日志计数 '+inttostr(i),2); end ; end ; procedure TForm1 . FormDestroy(Sender: TObject); begin Logger . Free; end ; |
转载请注明:梧桐树下 » 稳定轻量级的Delphi日志类
delphi lazarus opengl
网页操作自动化, 图像分析破解,游戏开发