unit uLogManagerThread; interface uses System.Classes, System.SysUtils, System.Generics.Collections, System.SyncObjs; type TRollingType = (rtDaily, rtHourly); procedure InitLogger(const Folder, FilePrefix: string; RollType: TRollingType); procedure AddLog_Thread(const Msg: string); procedure StopLogger; implementation var LogQueue: TThreadedQueue; LogThread: TThread; LogFolder : string; LogFilePrefix: string; RollingType : TRollingType; StopFlag: Boolean = False; type TLogThread = class(TThread) private FCurrentFileName: string; function GetLogFileName: string; procedure WriteToFile(const S: string); protected procedure Execute; override; end; procedure InitLogger(const Folder, FilePrefix: string; RollType: TRollingType); begin LogFolder := IncludeTrailingPathDelimiter(Folder); if not DirectoryExists(LogFolder) then ForceDirectories(LogFolder); LogFilePrefix := FilePrefix; RollingType := RollType; LogQueue := TThreadedQueue.Create(1000, 1000, 1000); StopFlag := False; LogThread := TLogThread.Create(False); end; procedure StopLogger; begin StopFlag := True; if Assigned(LogThread) then begin LogThread.WaitFor; LogThread.Free; LogThread := nil; end; if Assigned(LogQueue) then begin LogQueue.Free; LogQueue := nil; end; end; procedure AddLog_Thread(const Msg: string); begin if Assigned(LogQueue) then LogQueue.PushItem(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ' ' + Msg); end; { TLogThread } function TLogThread.GetLogFileName: string; var S: string; begin case RollingType of rtDaily: S := FormatDateTime('yyyy-mm-dd', Now); rtHourly: S := FormatDateTime('yyyy-mm-dd_hh', Now); end; Result := LogFolder + LogFilePrefix + '_' + S + '.txt'; end; procedure TLogThread.WriteToFile(const S: string); var FS: TFileStream; SW: TStreamWriter; begin if FCurrentFileName <> GetLogFileName then FCurrentFileName := GetLogFileName; // Append ¸ðµå·Î ¿­±â if FileExists(FCurrentFileName) then FS := TFileStream.Create(FCurrentFileName, fmOpenWrite or fmShareDenyNone) else FS := TFileStream.Create(FCurrentFileName, fmCreate or fmShareDenyNone); try FS.Seek(0, soEnd); // UTF-8 + BOM (ÆÄÀÏ ÃÖÃÊ »ý¼º ½Ã ÀÚµ¿) SW := TStreamWriter.Create(FS, TEncoding.UTF8); try SW.WriteLine(S); SW.Flush; finally SW.Free; end; finally FS.Free; end; end; { procedure TLogThread.WriteToFile(const S: string); var F: TextFile; begin if FCurrentFileName <> GetLogFileName then FCurrentFileName := GetLogFileName; AssignFile(F, FCurrentFileName); if FileExists(FCurrentFileName) then Append(F) else Rewrite(F); try Writeln(F, S); finally CloseFile(F); end; end; } procedure TLogThread.Execute; var LogItem: string; WR: TWaitResult; begin FCurrentFileName := GetLogFileName; while not StopFlag do begin WR := LogQueue.PopItem(LogItem); // Delphi 10.4¿¡¼­ À¯ÀÏÇÏ°Ô Á¸ÀçÇÏ´Â PopItem if WR = wrSignaled then begin WriteToFile(LogItem); end else Sleep(10); // Å¥°¡ ºñ¾úÀ¸¸é Àá½Ã ½¬¾ú´Ù°¡ ´Ù½Ã È®ÀÎ end; end; end.