Jump to content

Maxime Janvier

Members
  • Content Count

    5
  • Joined

  • Last visited

Posts posted by Maxime Janvier


  1. 5 minutes ago, Kas Ob. said:

    Well my point was about to not call SysErrorMessage in the first place, just pass the GetLastError, even more on this, if the code between Log and where actually it implemented can't modify The GetLastError, then you could use ttTraceIWithError and there you can call SysErrorMessage.

    In case you care about performance then just use a method and track the generated assembly

    image.thumb.png.f3a8767e280012982b117e2316e74b24.png

     

    And by replacing the most repeated or even the specific phrases like 'Test' and 'Exception'... with LOG_String_XX you can short and fast logging.

     

    Again food for thoughts.

    Good points!

     

    That would require a bit of work, but might worth it!

     

    Thank you very much for your time and thoughts, much appreciated! :)


  2. 29 minutes ago, Vandrovnik said:

    In a loop, I would store the result of CanLog to a local boolean variable and then use "if StoredValueOfCanLog>=..." and direct call to your Log procedure (without anonymous function).

    That's actually good!

    I think that I'll normally use the Log(LogLevel, MyString), but when obvious optimizations appear, I could add a CanLog to avoid evals in loops...

     

    In that way, I can have a proper balance between code cleanliness/ease of reading and performances.


  3. 28 minutes ago, Kas Ob. said:

    There is few ways i can think of like these 2 approaches

    
    type
      TLogLevel = (llInfo, llTrace, llError);
    
    procedure Log(LogLevel: TLogLevel; const LogText: string); overload;
    begin
    
    end;
    
    procedure Log(LogLevel: TLogLevel; const Text: array of string); overload;
    var
      Count: Integer;
    begin
      Count := Length(Text);
      case LogLevel of
        llInfo:  ;
        llTrace:
          begin
            if Count > 0 then
            begin
    
            end;
          end;
        llError:   ;
      end;
    end;
    
    procedure Log(LogLevel: TLogLevel; const LogText: string = ''; const Error: string = ''; const Additional: string = ''); overload;
    begin
    
    end;
    
    procedure Log(LogLevel: TLogLevel; const LogText: string = ''; ErrorCode: Integer = 0; const Additional: string = ''); overload;
    begin
    
    end;
    
    procedure TForm10.FormCreate(Sender: TObject);
    var
      BuildStringFromContext: string;
    begin
      Log(llTrace, ['Test', IntToStr(GetLastError), BuildStringFromContext]);
    
      Log(llError, 'Test', GetLastError, BuildStringFromContext);
    
      Log(llError, 'Simple Text', 0);
      Log(llInfo, 'Simple Text', 0, 'Additional Info');
      Log(llInfo, 'Simple Text', '');
    end;

    Just food for thoughts for you, using array of string is easy and will make you life easier, but you should remember the order, while the overloaded versions with default empty values, are more readable and harder to confuse.

     

    Each had its own shortcoming, like i had to add 0 do the ambiguity, but if you make you mind you can build them right and remove the need for these extra 0 or ''.

    It is up to your need to think of a solution that you are comfortable with.

    Thanks for these approaches!

    Unfortunately, the strings (or the functions that'll generate the strings) will still be individually evaluated, if I call Log(ttTrace, [SysErrorMessage(GetLastError)]);, the SysErrorMessage function will still be called.


  4. That would be a solution indeed.

    But performance-wise, I don't know the cost of anonymous functions.. What if that's called in a loop?

    Even if it' not called, some memory has to be dynamically allocated for the function code + the captured variables + the cost of capturing those variables...

    I might do a benchmark for that...


  5. Hi,


    I have quite a tricky problem, and can't figure out a proper solution.
    You see, I want to log debug strings in my application, so I wrote a module where the only entry point is a pure method "procedure Log(const LogLevel: TLogLevel; const Str: String);". 
    So the goal would be to only log strings if the logger is set to log at least that log level. That way, I can easily change the logger to only log error strings for example. 


    So far so good.


    Problem is, when I write things like "Log(llTrace, 'Test ' + GetLastError + BuildStringFromContext); for example, the string will be evaluated wether I log it or not, because the log filter is done inside the function.
    I was wandering if there was a way to avoid the evaluation of the string when I know I won't log it?
    Of course the obvious solution would be to write 
    "if CanLog(llTrace) then Log('Test ' + GetLastError + BuildStringFromContext);"
    But that would be tedious to write, and make the code harder to read.


    So I though of two possibilities:
    - First: Using inline function, to replace at compile time the first Log line by the if/then statement. Unfortunately, even with inline function, the arguments are fully eveluated when the function is called (tested). So it's a dead end.
    - I also though to use a preprocessor macro, to replace at compile time the fist line by the if/then statement, but Delphi doesn't support C/C++ like defines, it can only set/evaluate booleans.

     

    So do you think of a solution i could've overlooked?


    Without any solution, I'll stick to my first Log version, as I value code cleanliness over performance, but it's still a bit frustrating knowing my code will execute instructions for nothing at all if I disable my log....
    Regards,

×