USEGEAR

导航

一个能实战的delphi日志的类

  1 unit uProgLog;
  2 
  3 interface
  4 
  5 uses
  6 Windows, SysUtils, SyncObjs;
  7 
  8 const
  9 C_LOG_LEVEL_TRACE   = $00000001;
 10 C_LOG_LEVEL_WARNING = $00000002;
 11 C_LOG_LEVEL_ERROR   = $00000004;
 12 type
 13 EnumSeverity = (TraceLevel, WarningLevel, ErrorLevel, LogLevel);
 14 
 15 function SeverityDesc(severity: EnumSeverity): string;
 16 
 17 type
 18 TLogFile = class
 19 private
 20     FLogKeepDays: Integer; //日志保存时间
 21     FLogLevel: DWORD;      //日志级别
 22     FLogPath: string;      //日志保存路径,以"\"结尾
 23     FLogAppName: string;   //应用程序名(日志文件前缀)
 24 
 25     FCsWriteLogFile: TCriticalSection;
 26     FLogFile: TextFile;    //日志文件句柄
 27     FLogOpened: Boolean;   //日志文件是否打开
 28     FFileTimeStamp: TTimeStamp; //当前日志文件创建或打开时间
 29 
 30     function GetLogKeepDays(): Integer;
 31     procedure SetLogKeepDays(days: Integer);
 32     function GetLogLevel(): DWORD;
 33     procedure SetLogLevel(level: DWORD);
 34     function GetLogPath(): string;
 35     procedure SetLogPath(path: string);
 36     function GetLogAppName(): string;
 37     procedure SetLogAppName(name: string);
 38 protected
 39     function WriteLogFile(const szFormat: string; const Args: array of const): Boolean;
 40 public
 41 
 42     ////////////////////////////////////////////////////////////////////////////
 43     //Procedure/Function Name: Trace()
 44     //Describe: 记录日志到日志文件。如果日志文件路径不存在,会自动创建。如果日志文件不存在,
 45     //          则创建相应的日志文件;如果日子文件已存在,则打开相应的日志文件,并将日志添加到文件结尾。
 46     //Input   : severity: 日志级别。根据日志级别参数决定该级别日志是否需要保存,
 47     //            但LogLevel级别的日志不受日志级别参数影响,都保存到了日志文件。
 48     //          subject: 模块名称。
 49     //          desc: 日志内容。
 50     //Result : N/A
 51     //Catch Exception: No
 52     ////////////////////////////////////////////////////////////////////////////
 53     procedure Trace(severity: EnumSeverity; const subject, desc: string); overload;
 54 
 55     ////////////////////////////////////////////////////////////////////////////
 56     //Procedure/Function Name: Trace()
 57     //Describe: 记录日志到日志文件。如果日志文件路径不存在,会自动创建。如果日志文件不存在,
 58     //          则创建相应的日志文件;如果日子文件已存在,则打开相应的日志文件,并将日志添加到文件结尾。
 59     //Input   : severity: 日志级别。根据日志级别参数决定该级别日志是否需要保存,
 60     //            但LogLevel级别的日志不受日志级别参数影响,都保存到了日志文件。
 61     //          subject: 模块名称。
 62     //          descFormat: 包含格式化信息的日志内容。
 63     //          Args: 格式化参数数组。
 64     //Result : N/A
 65     //Catch Exception: No
 66     ////////////////////////////////////////////////////////////////////////////
 67     procedure Trace(severity: EnumSeverity; const subject, descFormat: string; const Args: array of const); overload;
 68 
 69     ////////////////////////////////////////////////////////////////////////////
 70     //Procedure/Function Name: DeleteLogFile()
 71     //Describe: 删除超过保存期限的日志文件。在日志文件路径中搜索超过保存期限的日志,将之删除。
 72     //          该方法只需在应用程序启动时调用一次,以删除超过保存期限的日志。
 73     //Input   : N/A
 74     //Result : Boolean 成功返回TRUE,失败返回FALSE
 75     //Catch Exception: No
 76     ////////////////////////////////////////////////////////////////////////////
 77     function DeleteLogFile(): Boolean;
 78 
 79     constructor Create();
 80     Destructor Destroy(); override;
 81 
 82     property LogKeepDays: Integer read GetLogKeepDays write SetLogKeepDays;
 83     property Level: DWORD read GetLogLevel write SetLogLevel;
 84     property LogPath: string read GetLogPath write SetLogPath;
 85     property LogAppName: string read GetLogAppName write SetLogAppName;
 86 end;
 87 
 88 function BooleanDesc(Value : Boolean): string;
 89 
 90 implementation
 91 
 92 uses Forms, SqlTimSt;
 93 
 94 function BooleanDesc(Value : Boolean): string;
 95 begin
 96 if Value then Result := 'TRUE'
 97 else Result := 'FALSE';
 98 end;
 99 
100 function SeverityDesc(severity: EnumSeverity): string;
101 begin
102 if (severity = ErrorLevel) then result := 'X'
103 else if (severity = WarningLevel) then result := '!'
104 else result := ' ';
105 end;
106 
107 { TLogFile }
108 
109 constructor TLogFile.Create;
110 begin
111 FLogOpened := False;
112 FCsWriteLogFile := TCriticalSection.Create;
113 
114 FLogKeepDays := 31;
115 FLogLevel := C_LOG_LEVEL_TRACE or C_LOG_LEVEL_WARNING or C_LOG_LEVEL_ERROR;
116 FLogPath := ExtractFilePath(Application.ExeName) + 'Log\';
117 FLogAppName := ChangeFileExt(ExtractFileName(Application.ExeName),'');
118 end;
119 
120 function TLogFile.DeleteLogFile(): Boolean;
121 var
122 rc : DWORD;
123 SearchRec: TSearchRec;
124 bResult: Boolean;
125 FileMask: string;
126 LocalFileTime: TFileTime;
127 FileTime: Integer;
128 begin
129 result := false;
130 rc := GetFileAttributes(PChar(FLogPath));
131 if (rc = $FFFFFFFF) or (FILE_ATTRIBUTE_DIRECTORY and rc = 0) then exit;
132 
133 FileMask := FLogPath + FLogAppName + '*.log';
134 bResult := FindFirst(FileMask, faAnyFile, SearchRec) = 0;
135 try
136     if bResult then
137     begin
138       repeat
139         if (SearchRec.Name[1] <> '.') and
140           (SearchRec.Attr and faVolumeID <> faVolumeID) and
141           (SearchRec.Attr and faDirectory <> faDirectory) then
142         begin
143           FileTimeToLocalFileTime(SearchRec.FindData.ftCreationTime, LocalFileTime);
144           FileTimeToDosDateTime(LocalFileTime, LongRec(FileTime).Hi, LongRec(FileTime).Lo);
145           // 按照文件创建日期删除文件
146           if FileDateToDateTime(FileTime) <= Now() - GetLogKeepDays() then
147             DeleteFile(FLogPath + SearchRec.Name);
148         end;
149       until FindNext(SearchRec) <> 0;
150     end;
151 finally
152     FindClose(SearchRec);
153 end;
154 end;
155 
156 destructor TLogFile.Destroy;
157 begin
158 if (FLogOpened) then CloseFile(FLogFile);
159 FCsWriteLogFile.Free();
160 inherited;
161 end;
162 
163 function TLogFile.GetLogAppName: string;
164 begin
165 result := FLogAppName;
166 end;
167 
168 function TLogFile.GetLogKeepDays: Integer;
169 begin
170 result := FLogKeepDays;
171 end;
172 
173 function TLogFile.GetLogLevel: DWORD;
174 begin
175 result := FLogLevel;
176 end;
177 
178 function TLogFile.GetLogPath: string;
179 begin
180 result := FLogPath;
181 end;
182 
183 procedure TLogFile.SetLogAppName(name: string);
184 begin
185 FLogAppName := ChangeFileExt(name, '');
186 end;
187 
188 procedure TLogFile.SetLogKeepDays(days: Integer);
189 begin
190 FLogKeepDays := days;
191 end;
192 
193 procedure TLogFile.SetLogLevel(level: DWORD);
194 begin
195 FLogLevel := level;
196 end;
197 
198 procedure TLogFile.SetLogPath(path: string);
199 begin
200 if Trim(path) = '' then exit;
201 if path[Length(path)] <> '\' then FLogPath := path + '\'
202 else FLogPath := path;
203 end;
204 
205 procedure TLogFile.Trace(severity: EnumSeverity; const subject, desc: string);
206 begin
207 // 根据配置的日志级别决定是否写日志
208 if ((severity = LogLevel) or
209    ((severity = ErrorLevel) and (FLogLevel and C_LOG_LEVEL_ERROR = C_LOG_LEVEL_ERROR)) or
210    ((severity = WarningLevel) and (FLogLevel and C_LOG_LEVEL_WARNING = C_LOG_LEVEL_WARNING)) or
211    ((severity = TraceLevel) and (FLogLevel and C_LOG_LEVEL_TRACE = C_LOG_LEVEL_TRACE))) then
212 begin
213    WriteLogFile('%s @@ %s @ %s $ %s', [SeverityDesc(severity), FLogAppName, subject, desc]);
214 end;
215 end;
216 
217 procedure TLogFile.Trace(severity: EnumSeverity; const subject,
218 descFormat: string; const Args: array of const);
219 var
220 desc: string;
221 begin
222 // 根据配置的日志级别决定是否写日志
223 if ((severity = LogLevel) or
224    ((severity = ErrorLevel) and (FLogLevel and C_LOG_LEVEL_ERROR = C_LOG_LEVEL_ERROR)) or
225    ((severity = WarningLevel) and (FLogLevel and C_LOG_LEVEL_WARNING = C_LOG_LEVEL_WARNING)) or
226    ((severity = TraceLevel) and (FLogLevel and C_LOG_LEVEL_TRACE = C_LOG_LEVEL_TRACE))) then
227 begin
228     desc := Format(descFormat, Args);
229    WriteLogFile('%s @@ %s @ %s $ %s', [SeverityDesc(severity), FLogAppName, subject, desc]);
230 end;
231 end;
232 
233 
234 function TLogFile.WriteLogFile(const szFormat: string;
235 const Args: array of const): Boolean;
236 var
237 fileName: string;
238 currentTime: TDateTime;
239 currentTimeStamp: TTimeStamp;
240 currentSQLTimeStamp: TSQLTimeStamp;
241 buffer: string;
242 szDate, szTime: string;
243 begin
244 result := false;
245 
246 //进入临界区,保证多线程环境下此函数能安全执行
247 FCsWriteLogFile.Enter();
248 try
249     currentTime := Now();      //注意这里得到的是local time
250     currentSQLTimeStamp := DateTimeToSQLTimeStamp(currentTime);
251     currentTimeStamp := DateTimeToTimeStamp(currentTime);
252 
253     try
254       // 1. close the current log file?
255       if (FLogOpened and
256           (currentTimeStamp.Date <> FFileTimeStamp.Date)) then
257       begin
258         CloseFile(FLogFile);
259         FLogOpened := False;
260       end;
261 
262       // 2. whether to open a new log file?
263       if (not FLogOpened) then
264       begin
265         // 2.1如果指定的日志目录不存在,则创建它
266         if not DirectoryExists(FLogPath) then
267           if not ForceDirectories(FLogPath) then exit;
268 
269         // 2.2 然后再打开当前日志文件
270         szDate := Format('%4d%2d%2d',
271               [currentSQLTimeStamp.Year, currentSQLTimeStamp.Month, currentSQLTimeStamp.Day]);
272         // Format函数不支持在宽度不足位添0,只好用replace添加
273         szDate := StringReplace(szDate, ' ', '0', [rfReplaceAll]);
274 
275         fileName := Format('%s%s%s.log', [FLogPath, FLogAppName, szDate]);
276 
277         Assignfile(FLogFile, fileName);
278         //if FileExists(fileName) then append(FLogFile)
279         //else rewrite(FLogFile);
280 
281         //$1 modify by zhajl 2005-11-30
282         // 如果无法打开日志文件,则退出
283         try
284           if FileExists(fileName) then append(FLogFile)
285           else rewrite(FLogFile);
286           FLogOpened := True;
287         except
288           // 如果无法打开日志文件
289           FLogOpened := False;
290           //这里用CloseFile会出现异常
291           //CloseFile(FLogFile);
292           exit;
293         end;
294 
295         // 更新文件创建时间。要注意这里是 local time
296         FFileTimeStamp := DateTimeToTimeStamp(currentTime);
297       end;
298 
299       // 3. 写日志内容
300       ASSERT(FLogOpened);
301       if (FLogOpened) then
302       begin
303         szDate := Format('%4d/%2d/%2d',
304               [currentSQLTimeStamp.Year, currentSQLTimeStamp.Month, currentSQLTimeStamp.Day]);
305         // Format函数不支持在宽度不足位添0,只好用replace添加
306         szDate := StringReplace(szDate, ' ', '0', [rfReplaceAll]);
307         szTime := Format('%2d:%2d:%2d',
308               [currentSQLTimeStamp.Hour, currentSQLTimeStamp.Minute, currentSQLTimeStamp.Second]);
309         szTime := StringReplace(szTime, ' ', '0', [rfReplaceAll]);
310 
311         buffer := Format('%s %s ', [szDate, szTime]); // '%4d/%2d/%2d %2d:%2d:%2d '
312         buffer := buffer + szFormat;
313         buffer := Format(buffer, Args);
314 
315         writeln(FLogFile, buffer);
316         Flush(FLogFile); // 是否考虑性能而注释之?
317       end;
318     except
319       //写日志文件操作中若有异常(如目录是只读的等),则忽略它
320     end;
321 finally
322     FCsWriteLogFile.Leave; //离开临界区
323 end;
324 result := true;
325 end;
326 
327 end.

糖炒栗子  http://www.cnblogs.com/IceKernel/articles/2534600.html

posted on 2014-04-22 18:36  USEGEAR  阅读(671)  评论(1编辑  收藏  举报