Search code examples
delphilogging

Problem with creating log files in Delphi


What I want to do basically is to write log files for my VCL app. Logging procedure has to create text file on given location with name that will contain current date of writing, example is "BSSGLog 20231106.txt". In order to make it easier to go through the log files if needed I wanted to limit the entries to 1000 lines of text. If there is overflow on that current date then it has to create new file with added extension, example "BSSGLog 20231106_1.txt" etc. It works fine until it reaches extension "_9", after that it creates file with extension "_10" but it only writes one line of text and creates "_11". It keeps creating files with only one line of text until it reaches "_89". After that it works fine again. I know that the problem lies in procedure SearchFiles because it keeps checking the file with extension "_9" over and over again. This is the code to make it more easier to understand what I wanted to do.

function SearchFiles(SearchDir, SearchFile: string):String;
var
  SearchRec: TSearchRec;
begin
  if FindFirst(SearchDir + SearchFile, faAnyfile, SearchRec) = 0 then
  begin
    repeat
      Result := SearchRec.Name
    until (FindNext(SearchRec)<>0);
  end;
  FindClose(SearchRec);
end;

procedure Log(s: string);
var
  FileCont: TStringList;
  FileName, LogEntry: String;
  fs: Tformatsettings;
  i: Integer;
begin
  DeleteFilesOlderThan30Days;
  if not DirectoryExists(TPath.GetHomePath() + '\test') then
    CreateDir(TPath.GetHomePath() + '\test');
  if not DirectoryExists(TPath.GetHomePath() + '\test\Logs') then
    CreateDir(TPath.GetHomePath() + '\test\Logs');
  FileCont := TStringList.Create;
  try
    fs.ShortDateFormat := 'YYYYMMDD';
    fs.TimeSeparator := ':';
    if SearchFiles(TPath.GetHomePath() + '\test\Logs\', 'BSSGLog ' + DateToStr(now,fs) + '.txt') = '' then // I believe the problem lies here
      begin
        Filename := TPath.GetHomePath() + '\test\Logs\BSSGLog ' + DateToStr(Now, fs) + '.txt';
        fileCont.SaveToFile(filename);
      end
    else
      Filename := TPath.GetHomePath() + '\test\Logs\' + SearchFiles(TPath.GetHomePath() +
                  '\test\Logs\', 'BSSGLog ' + DateToStr(now,fs) + '*.txt');
    FileCont.LoadFromFile(FileName);
    if FileCont.Count >= 1000 then
      begin
        i := GetFilesCount(TPath.GetHomePath() + '\test\Logs\', 'BSSGLog ' + DateToStr(now,fs) + '*.txt');
        Filename := TPath.GetHomePath() + '\test\Logs\BSSGLog ' + DateToStr(Now, fs) + '_' + i.ToString + '.txt';
        FileCont.Clear();
      end;
    fs.ShortDateFormat := 'DD.MM.YYYY. HH:mm:ss';
    LogEntry := DateTimeToStr(Now(), fs) + '- ' + s;
    FileCont.Add(LogEntry);
    FileCont.SaveToFile(Filename);
  finally
    FreeAndNil(FileCont);
  end;
end;

function GetFilesCount(SearchDir, SearchFile : String) : Integer;
var
  SearchRec: TSearchRec;
begin
  Result := 0;
  if FindFirst(SearchDir + SearchFile, faAnyFile xor faDirectory, SearchRec)= 0 then
  begin
    repeat
      Inc(Result);
    until (FindNext(SearchRec) <> 0);
    FindClose(SearchRec);
  end;
end;

Any advice would be highly appreciated. Maybe an idea of how to do a better job at logging. Thank you in advance!


Solution

  • You should get rid of the function SearchFiles, because of the ordering problem and you should take advantage of the FileExists function. Taking your code in account, this is how would I modify it:

    try
      fs.ShortDateFormat := 'YYYYMMDD';
      fs.TimeSeparator := ':';
      i := 0;
      Filename := TPath.GetHomePath() + '\test\Logs\BSSGLog ' + DateToStr(Now, fs) + '.txt';
      if not FileExists(Filename) then 
      begin
        fileCont.SaveToFile(filename); // doesn't exist; create it
      end
      else
      begin
        if FileExists(TPath.GetHomePath() + '\test\Logs\BSSGLog ' + DateToStr(Now, fs) + '_1.txt') then
        begin 
          i := GetFilesCount(TPath.GetHomePath() + '\test\Logs\', 'BSSGLog ' + DateToStr(now,fs) + '_*.txt');
          Filename := TPath.GetHomePath() + '\test\Logs\BSSGLog ' + DateToStr(Now, fs) + '_' + i.ToString + '.txt'; // get the last file
        end;
      end;
      FileCont.LoadFromFile(FileName);
      if FileCont.Count >= 1000 then
      begin
        Filename := TPath.GetHomePath() + '\test\Logs\BSSGLog ' + DateToStr(Now, fs) + '_' + (i+1).ToString + '.txt';  //new file
        FileCont.Clear();
      end;
      fs.ShortDateFormat := 'DD.MM.YYYY. HH:mm:ss';
      LogEntry := DateTimeToStr(Now(), fs) + '- ' + s;
      FileCont.Add(LogEntry);
      FileCont.SaveToFile(Filename);
    finally
      FreeAndNil(FileCont);
    end;
    

    I didn't tested it. Let me know if it works for you.