{
# Delphi 日志类(Logger Class for delphi xe)
- v1.0.3
- 2024-12-02 by gale
- https://github.com/higale/LoggerXE
## 方法:
- Debug:调试,通常在开发中会将其设置为最低的日志级别,用于输出详细的调试信息。
- Info:信息,用于输出常用的信息,使用较为频繁。
- Warn:警告,表明会出现潜在错误的情形,虽然程序不会报错,但仍需注意。
- Error:错误,记录错误和异常信息。
- Fatal:致命错误,一旦发生,程序基本上需要停止。
## 日志文件位置
可以通过设置Root来改变日志文件位置,如果不设置,日志缺省存储在
- Windows:
*程序所在目录/log/*
- MacOS
*/Users/当前用户/.程序名/log/*
## 注意
g_Logger实例已经自动创建,可以直接使用
## 使用方法:
uses
Logger;
...
g_Logger.Debug('This is a %s log',['debug'])
g_Logger.Error('发生了一些错误!');
VCL显示日志
g_Logger.OnLog := procedure(Sender: TObject; ALevel: TLogLevel; ALevelTag: string; ALog: string; ATime: TDateTime)
begin
if mmoLog.Lines.Count > 1000 then
mmoLog.Text := 'clear...';
mmoLog.Lines.Add(Format('%s%s%s', [FormatDateTime('hh:mm:ss', ATime), ALevelTag, ALog]));
end;
FMX显示日志
g_Logger.OnLog := procedure(Sender: TObject; ALevel: TLogLevel; ALevelTag: string; ALog: string; ATime: TDateTime)
begin
if mmoLog.Lines.Count > 1000 then
mmoLog.Text := 'clear...';
mmoLog.Lines.Add(Format('%s%s%s', [FormatDateTime('hh:mm:ss', ATime), ALevelTag, ALog]));
mmoLog.GoToTextEnd;
end;
}
unit Logger;
// 兼容旧版日志类,可以使用WriteLog函数输出日志
//{$DEFINE Compatible_Old_Version}
interface
uses
System.IOUtils, System.Classes, System.SysUtils, System.SyncObjs;
type
/// 日志级别
TLogLevel = (llAll, llDebug, llInfo, llWarn, llError, llFatal, llOff);
/// 日志回调事件
TOnLogerLog = reference to procedure(Sender: TObject; ALevel: TLogLevel; ALevelTag: string; ALog: string; ATime: TDateTime);
/// 日志类
TLogger = class
private
FCSLock: TCriticalSection;
FRoot: string;
FSubFormat: string;
FFilenameFormat: string;
FEncoding: TEncoding;
FLevel: TLogLevel;
FTimeFormat: string;
FTags: array [TLogLevel] of string;
FOnLog: TOnLogerLog;
procedure SetRoot(AValue: string);
procedure Log(ALog: string; const ALogLevel: TLogLevel); overload;
procedure Log(ALog: string; const Args: array of const; const LogLevel: TLogLevel); overload;
public
/// 日志目录,缺省为log,可以是相对或绝对路径
property Root: string read FRoot write SetRoot;
/// 子目录格式,缺省为yyyymm(每月一个子目录),为空不使用子目录
property SubFormat: string read FSubFormat write FSubFormat;
/// 日志文件名格式,缺省为yyyymmdd(每天一个文件)
property FilenameFormat: string read FFilenameFormat write FFilenameFormat;
/// 日志编码格式,缺省UTF8
property Encoding: TEncoding read FEncoding write FEncoding;
/// 低于此级别的日志将被忽略,缺省为llAll, llOff为全部忽略
property Level: TLogLevel read FLevel write FLevel;
/// 保存日志时间格式,缺省为 'hhnnss'
property TimeFormat: string read FTimeFormat write FTimeFormat;
/// 日志触发事件,线程安全
property OnLog: TOnLogerLog read FOnLog write FOnLog;
/// 不同日志级别对应的名称标签,缺省为 '[D]', '[I]', '[W]', '[E]', '[F]'
/// 调试日志标签
/// 信息日志标签
/// 警告日志标签
/// 错误日志标签
/// 致命错误日志标签
procedure SetTags(ADebugTag, AInfoTag, AWarnTag, AErrorTag, AFatalTag: string);
public
/// 构造函数,如无特殊需求,可以直接使用g_Logger,它已经自动初始化,不需要手动创建
constructor Create;
/// 析构函数
destructor Destroy; override;
/// 输出调试日志
/// 日志内容
procedure Debug(ALog: string); overload;
/// 输出调试日志
/// 包含格式化格式信息的日志数据
/// 用于格式化的参数
procedure Debug(ALog: string; const Args: array of const); overload;
/// 输出信息日志
/// 日志内容
procedure Info(ALog: string); overload;
/// 输出信息日志
/// 包含格式化格式信息的日志数据
/// 用于格式化的参数
procedure Info(ALog: string; const Args: array of const); overload;
/// 输出警告日志
/// 日志内容
procedure Warn(ALog: string); overload;
/// 输出警告日志
/// 包含格式化格式信息的日志数据
/// 用于格式化的参数
procedure Warn(ALog: string; const Args: array of const); overload;
/// 输出错误日志
/// 日志内容
procedure Error(ALog: string); overload;
/// 输出错误日志
/// 包含格式化格式信息的日志数据
/// 用于格式化的参数
procedure Error(ALog: string; const Args: array of const); overload;
/// 输出致命错误日志
/// 日志内容
procedure Fatal(ALog: string); overload;
/// 输出致命错误日志
/// 包含格式化格式信息的日志数据
/// 用于格式化的参数
procedure Fatal(ALog: string; const Args: array of const); overload;
{$IFDEF Compatible_Old_Version}
/// 输出日志 【警告】不建议使用此函数! 此函数仅为兼容旧版本程序
/// 日志内容
/// 日志级别 0:信息 1,2:警告 other:错误
procedure WriteLog(ALog: String; const ALogLevel: integer = 0); overload;
deprecated '函数 WriteLog 已不建议使用,请直接使用语义更清晰的 Debug、Info、Warn、Error或Fatal 函数输出日志';
/// 输出日志 【警告】不建议使用此函数! 此函数仅为兼容旧版本程序
/// 包含格式化格式信息的日志数据
/// 用于格式化的参数
/// 日志级别 0:信息 1,2:警告 other:错误
procedure WriteLog(ALog: String; const Args: array of const; const ALogLevel: integer = 0); overload;
deprecated '函数 WriteLog 已不建议使用,请直接使用语义更清晰的 Debug、Info、Warn、Error或Fatal 函数输出日志';
{$ENDIF}
end;
var
g_Logger: TLogger;
implementation
{ ------------------------------------------------------------------------------
名称: TLogger.Create
说明: 构造函数
------------------------------------------------------------------------------ } constructor TLogger.Create;
begin
inherited Create;
FCSLock := TCriticalSection.Create;
{$IFDEF MACOS}
FRoot := ExtractFilePath(TPath.GetDocumentsPath) + '.' + ExtractFileName(ParamStr(0)) + PathDelim + 'log' + PathDelim;
{$ELSE}
FRoot := ExtractFilePath(ParamStr(0)) + 'log' + PathDelim;
{$ENDIF}
FSubFormat := 'yyyymm';
FFilenameFormat := 'yyyymmdd';
FEncoding := TEncoding.UTF8;
FLevel := llAll;
FTimeFormat := 'hhnnss';
SetTags('[D]', '[I]', '[W]', '[E]', '[F]');
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Destroy
说明: 析构函数
------------------------------------------------------------------------------ }
destructor TLogger.Destroy;
begin
FCSLock.Free;
inherited;
end;
{ ------------------------------------------------------------------------------
名称: TLogger.SetRoot
说明: LogDir属性设置函数
参数: AValue
------------------------------------------------------------------------------ }
procedure TLogger.SetRoot(AValue: string);
begin
FRoot := ExpandFileName(AValue);
if FRoot[FRoot.Length] <> PathDelim then
begin
FRoot := FRoot + PathDelim;
end;
if not ForceDirectories(FRoot) then
begin
raise Exception.Create('The log file directory cannot be created: ' + FRoot);
end;
end;
{ ------------------------------------------------------------------------------
名称: TLogger.SetLevelTags
说明: LevelTags属性设置函数
参数: ADebugTag 调试
AInfoTag 信息
AWarnTag 警告
AErrorTag 错误
------------------------------------------------------------------------------ }
procedure TLogger.SetTags(ADebugTag, AInfoTag, AWarnTag, AErrorTag, AFatalTag: string);
begin
FTags[llDebug] := ADebugTag;
FTags[llInfo] := AInfoTag;
FTags[llWarn] := AWarnTag;
FTags[llError] := AErrorTag;
FTags[llFatal] := AFatalTag;
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Log
说明: Log输出函数
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
LogLevel 日志级别
------------------------------------------------------------------------------ }
procedure TLogger.Log(ALog: string; const Args: array of const; const LogLevel: TLogLevel);
begin
Log(Format(ALog, Args), LogLevel);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Log
说明: Log输出函数
参数: ALog 日志数据
ALogLevel 日志级别
------------------------------------------------------------------------------ }
procedure TLogger.Log(ALog: string; const ALogLevel: TLogLevel);
var
FullDir, SubDir: string;
logFileName: string;
strLogAll: string;
LogLevelTag: string;
LogTime: TDateTime;
begin
if ALogLevel >= FLevel then
begin
LogTime := Now;
LogLevelTag := FTags[ALogLevel];
logFileName := FormatDateTime(FFilenameFormat, LogTime) + '.log';
FullDir := FRoot;
if FSubFormat <> '' then
begin
SubDir := FormatDateTime(FSubFormat, LogTime);
FullDir := FRoot + SubDir + PathDelim;
end;
strLogAll := Format('%s%s%s' + sLineBreak, [FormatDateTime(FTimeFormat, LogTime), LogLevelTag, ALog]);
FCSLock.Enter;
try
if not DirectoryExists(FullDir) then
begin
ForceDirectories(FullDir);
end;
try
TFile.AppendAllText(FullDir + logFileName, strLogAll, FEncoding);
except
end;
finally
FCSLock.Leave;
end;
if Assigned(FOnLog) then
begin
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
FOnLog(self, ALogLevel, FTags[ALogLevel], ALog, LogTime);
end);
end;
end;
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Debug
说明: 调试日志
参数: ALog 日志数据
------------------------------------------------------------------------------ }
procedure TLogger.Debug(ALog: string);
begin
Log(ALog, llDebug);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Debug
说明: 调试日志
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
------------------------------------------------------------------------------ }
procedure TLogger.Debug(ALog: string; const Args: array of const);
begin
Log(ALog, Args, llDebug);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Info
说明: 信息日志
参数: ALog 日志数据
------------------------------------------------------------------------------ }
procedure TLogger.Info(ALog: string);
begin
Log(ALog, llInfo);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Info
说明: 信息日志
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
------------------------------------------------------------------------------ }
procedure TLogger.Info(ALog: string; const Args: array of const);
begin
Log(ALog, Args, llInfo);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Warn
说明: 警告日志
参数: ALog 日志数据
------------------------------------------------------------------------------ }
procedure TLogger.Warn(ALog: string);
begin
Log(ALog, llWarn);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Warn
说明: 警告日志
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
------------------------------------------------------------------------------ }
procedure TLogger.Warn(ALog: string; const Args: array of const);
begin
Log(ALog, Args, llWarn);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Error
说明: 错误日志
参数: ALog 日志数据
------------------------------------------------------------------------------ }
procedure TLogger.Error(ALog: string);
begin
Log(ALog, llError);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Error
说明: 错误日志
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
------------------------------------------------------------------------------ }
procedure TLogger.Error(ALog: string; const Args: array of const);
begin
Log(ALog, Args, llError);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Fatal
说明: 致命错误日志
参数: ALog 日志数据
------------------------------------------------------------------------------ }
procedure TLogger.Fatal(ALog: string);
begin
Log(ALog, llFatal);
end;
{ ------------------------------------------------------------------------------
名称: TLogger.Fatal
说明: 致命错误日志
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
------------------------------------------------------------------------------ }
procedure TLogger.Fatal(ALog: string; const Args: array of const);
begin
Log(ALog, Args, llFatal);
end;
{$IFDEF Compatible_Old_Version}
{ -------------------------------------------------------------------------------
名称: TLogger.WriteLog
说明: 旧版本日志输出函数,为兼容保留,不建议使用
参数: ALog 日志数据
ALogLevel 日志级别
------------------------------------------------------------------------------- }
procedure TLogger.WriteLog(ALog: String; const ALogLevel: integer);
var
ALvl: TLogLevel;
begin
case ALogLevel of
0:
ALvl := llInfo;
1, 2:
ALvl := llWarn;
else
ALvl := llError;
end;
Log(ALog, ALvl);
end;
{ -------------------------------------------------------------------------------
名称: TLogger.WriteLog
说明: 旧版本日志输出函数,为兼容保留,不建议使用
参数: ALog 包含格式化格式信息的日志数据
Args 用于格式化的参数
ALogLevel 日志级别
------------------------------------------------------------------------------- }
procedure TLogger.WriteLog(ALog: String; const Args: array of const; const ALogLevel: integer);
var
ALvl: TLogLevel;
begin
case ALogLevel of
0:
ALvl := llInfo;
1, 2:
ALvl := llWarn;
else
ALvl := llError;
end;
Log(ALog, Args, ALvl);
end;
{$ENDIF}
initialization
g_Logger := TLogger.Create;
finalization
FreeAndNil(g_Logger);
end.