Giter Club home page Giter Club logo

loggerpro's Introduction

LoggerPro for Delphi

An modern and pluggable logging framework for Delphi

Compatibility

LoggerPro is compatibile with

  • Delphi 12 Athens
  • Delphi 11 Alexandria
  • Delphi 10.4 Sydney
  • Delphi 10.3 Rio
  • Delphi 10.2 Tokyo (Added Linux compatibility)
  • Delphi 10.1 Berlin
  • Delphi 10 Seattle
  • Delphi XE8
  • Delphi XE7
  • Delphi XE6
  • Delphi XE5
  • Delphi XE4
  • Delphi XE3
  • Delphi XE2

What's new in 2.0.0 (repo version, beta)

  • Delphi 12 Athens Support
  • FIX #72
  • New LogLevel: FATAL (#80)
  • New Appender: JSONL
  • Added ILogItemRenderers (check samples)

What's new in 1.4.0 (stable version)

  • Improved VCL and FMX visual appenders
  • Appenders can be added and removed programmatically
  • Added packages for latest versions of Delphi
  • Improved algorithm used to handle slow consumers
  • Added DMSContainer's EventStreams Appender
  • Added very basic console appender that assumes is running from console in order to provide simple Linux console logging
  • FIX Issue 50
  • New filtering log file appender that allows to pick individual tags to be written into a file.
  • FIX Issue 57
  • FIX Issue 60

What's new in 1.3.2

  • Added support for Android API level 26 in mobile demo
  • Added packages for Delphi 10.3 Rio, Delphi 10.2 Tokyo, Delphi 10.1 Berlin and Delphi 10.0 Seattle.
  • Added packages for Delphi XE7 and Delphi XE8 (these packages do not contain appenders which uses System.Net.HttpClient)
  • Added support for Linux in TLoggerProFileAppender (Thank you charoit)

What's new in 1.3.0

  • Replace TThreadedList<T> with a custom implementation (TThreadSafeQueue<T>) because of a bug and this in TMonitor.
    • TThreadSafeQueue<T> is not a drop-in replacement for the TThreadedQueue<T> but can be used in other projects if you are fighting with the same bug.
  • TVCLMemoLogAppender.Create gots new parameter: aClearOnStartup which optionally clear the memo at the startup.
  • Improvement to the TLoggerProConsoleAppender (Thanks to Fulgan)
  • Improvement to the TLoggerProFileAppender; now there is a OnLogRow callback that can be used to customize log row format.
  • New overloaded Log methods. The *Fmt versions are deprecated and will be removed in a future version ISSUE #17
  • New NSQ appender (Thanks to Fulgan)
  • New logger filter decorator (Thanks to Fulgan)
  • New REST appender with support for extended information (samples for Windows and Android)
    • Extended information are supported in Windows (fully) and Android (partially)
    • In the sample folder is provided also the RESTLogCollector
  • New Elastic Search Log appender (Thanks to Salvatore Sparacino)

Getting started

program getting_started_console;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  LoggerPro.GlobalLogger; //this is the global logger, it is perfect to understand the basic operation of LoggerPro.

begin
  try
    //the global logger uses a TLoggerProFileAppender, so your logs will be written on a 
    //set of files with automatic rolling/rotating
    
    Log.Debug('Debug message', 'main'); //TLoggerProFileAppender uses the "tag" to select a different log file	
    Log.Info('Info message', 'main');
    Log.Warn('Warning message', 'main');
    Log.Error('Error message', 'errors');
    WriteLn('Check "getting_started_console.00.main.log" and "getting_started_console.00.errors.log" to see your logs');
    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

end.

The most flexible/correct approach is not much complicated than the global logger one. Check how is simple to create a custom instance of logwriter

program getting_started_console_appenders;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  LoggerPro, //LoggerPro core
  LoggerPro.FileAppender, //File appender
  LoggerPro.OutputDebugStringAppender; //OutputDebugString appender

var
  Log: ILogWriter;

begin
  Log := BuildLogWriter([TLoggerProFileAppender.Create,
    TLoggerProOutputDebugStringAppender.Create]);

  try
    Log.Debug('Debug message', 'main');
    Log.Info('Info message', 'main');
    Log.Warn('Warning message', 'main');
    Log.Error('Error message', 'errors');
    WriteLn('Check ');
    WriteLn('  "getting_started_console.00.main.log"');
    WriteLn('  "getting_started_console.00.errors.log"');

    if DebugHook <> 0 then //inform the user where his/her logs are
    begin
      WriteLn('also, you logs have been sent to the current debugger, check the Delphi''s EventLog window to see them.');
    end
    else
    begin
      WriteLn('..seems that no debugger is present. The logs can be seen using DebugView.');
      WriteLn('Download it from here https://technet.microsoft.com/en-us/sysinternals/debugview.aspx');
      WriteLn('Learn how to use http://tedgustaf.com/blog/2011/5/use-debugview-to-view-debug-output-from-asp-net-web-application/');
    end;
    ReadLn;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;

end.

Built-in log appenders

The framework contains the following built-in log appenders

  • File appender (TLoggerProFileAppender) (v1.0.0+)
  • Console appender (TLoggerProConsoleAppender) (v1.0.0+)
  • OutputDebugString appender (TLoggerProOutputDebugStringAppender) (v1.0.0+)
  • VCL Memo appender (TVCLMemoLogAppender) (v1.0.0+)
  • VCL ListView appender (TVCLMemoLogAppender) -- thanks to https://github.com/he3p94uu (v1.3.0+)
  • Redis Appender with LogsViewer(to aggregate logs from different instances on a single Redis instance) (v1.2.0+)
  • Email appender (to send email as log, very useful for fatal errors) (v1.2.0+)
  • SysLog appender RFC 5424 compliant -- thanks to https://github.com/nurettin (v1.3.0+)
  • NSQ appender (Thanks to Fulgan) (v1.3.0+)
  • Decorator appender (Thanks to Fulgan) (v1.3.0+)

Next appenders in the development pipeline

  • RESTful Appender (to send logs to a rest endpoint using a specific request format, so that you can implement log server in DelphiMVCFramework, PHP, Java, Python, Node etc)
  • Twitter Appender (to send logs to a Twitter Account)
  • Database appender (to send logs to a database table using FireDAC components -- Thank You Omar Bossoni)

The log writers and all the appenders are asycnhronous.

Check the samples to see how to use each appender or even combine different appenders.

Documentation

Documentation is available in the docs folder as HTML.

Other

You can install Delphinus package manager and install LoggerPro as a package there. (Delphinus-Support)

loggerpro's People

Contributors

androschuk avatar charoit avatar corneliusdavid avatar danieleteti avatar fastbike avatar fulgan avatar luebbe avatar nurettin avatar pawe1 avatar tommiprami avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loggerpro's Issues

Different LogLevels for one ILogWriter

Dear Daniel,

thank you for the great library loggerpro. It is awesome to work with it - I just started to play a litte with the framework. Well done! :-)

I have one question related to the handling of loglevels. Especially when it comes to different appenders in ONE logwriter. I saw the sample with multiple appenders.
What I want to understand clearer is the interoperation between ILogWriter and ILogAppender. I learned so far that one can define a loglevel for each appender. This is fine - although I would have expected a range (of loglevels) to which this appender will "forward" the logmessages fired. I solved this by adding the same appenders along with a different loglevel set I would like to have for this appender.

Now to the level of ILogWriter.LogLevel: I wonder why this is needed? Since I already set the loglevels in the appender and I assumed that when I drop a message to level 'warning" for example each added appender would receive the message if the loglevel does match.

Maybe you can help me to understand the concept and what I am missing at the moment?
Would be fine and I am looking forward to your answer.

Thank you again for the great and really useful logging framework.

Best regards,
Chris

EFileNotFoundException when log rotation is set to zero

#54 triggered my memory. During testing loggerpro, I came across the following problem: If you set the log rotation to zero, like
in LoggerPro.Config in the file appender example

_Log := BuildLogWriter([
  TLoggerProFileAppender.Create(0, 5, '..\..', [],
    TLoggerProFileAppender.DEFAULT_FILENAME_FORMAT, DEFAULT_LOG_FORMAT)
 ...

an EFileNotFoundException is raised in procedure TLoggerProFileAppenderBase.RetryMove.

The simplest solution for me would be to either assert that the value is at least one or set it to Min(1, ...) in the constructor. I consider no rotation an invalid use case :)

So either:

constructor TLoggerProFileAppenderBase.Create(...
begin
  Assert(aMaxBackupFileCount > 0, 'Log rotation must be at least one.');
  ...

or

constructor TLoggerProFileAppenderBase.Create(...
begin
  ...
  fMaxBackupFileCount:= Min(1, aMaxBackupFileCount)
  ...

能否出个说明文档?

我是个Delphi新手,想使用这个开源项目,可是不知道如何引入到自己的工程中,可以不可以出一个详细的引入说明?谢谢~

Question

Hi Daniel,

A quick question: does Loggerpro is compatible with OSX ?

Thanks,
Edward

Performance Issues

We have an ISAPI application that is quite chatty when we are writing in debug level (i.e. each request will generate about 300 log lines). We have a file appender configured.

We are now receiving about 160k web requests per day and have noticed that after a while the requests are failing with the error message "'Main logs queue is full. Hints: Are there appenders? Are these appenders fast enough considering the log item production?"

I have traced this error message back to TLogWriter.Log in the LoggerPro.pas file. It appears that either the main Log queue is filling up (i.e. log items are being added faster than the log thread can dequeue them), or that the call to FLoggerThread.LogWriterQueue.Enqueue is failing for some other reason.

We have written a simple JMeter test script to reproduce the load. With the global var DefaultLoggerProMainQueueSize set to 10k the error occurs after about 50 seconds. Increasing this queue size to 100k makes the error occur after about 5 minutes.

We really do not want to increase the queue size any more as the idea of 100k unwritten log entries in memory makes us a bit nervous.

Is there any other way we can improve the performance (apart from having separate instances of the ILogWriter) ?

Log inside windows service

Hi, this is not exactly a issue, i think i'm do not know how use correctly the LoggerPro.
I have a windows service to update database and exe on my clients and i'm using the file "LoggerProConfig" to write logs and see errors or other important messages.
But, when i use for example "Log.Error('TEST', 'TEST');" i don´t see new line in file.
There is anything i need to do to correct this problem?
Thank you since now.

DelAppender - Argument Out Of Range Exception

Deleting appender at runtime, raises Argument Out Of Range Exception.

The problem is in the DelAppender procedure:

procedure TCustomLogWriter.DelAppender(const aAppender: ILogAppender);
.......
  for i := 0 to Self.FLoggerThread.FAppendersDecorators.Count - 1 do
    if Self.FLoggerThread.FAppendersDecorators[i].FLogAppender = aAppender then
      Self.FLoggerThread.FAppendersDecorators.Delete(i);
end;

The for statement loops till i = Self.FLoggerThread.FAppendersDecorators.Count - 1 , this is a mistake beacuse if we delete some Appender contained in the list the higher limit of the loop is not re assigned. In a list of 3 items for will loop from 0 to 2 but if we delete an item the loop don't stop so trying to read/write List[2] will raise the exception.

I used a repeat .. until .. statement instead, the loop should stop after succesfull delete (appender is supposed to exists only once in the list).

Modified version of mine:

procedure TCustomLogWriter.DelAppender(const aAppender: ILogAppender);
var
  i: Integer;
  LAppenderDeleted : Boolean;
begin
  i := Self.FLogAppenders.IndexOf(aAppender);
  if i >= 0 then
  begin
    Self.FLogAppenders.Delete(i);
  end;

  if Self.FLoggerThread.FAppendersDecorators.Count = 0 then
  begin
    Exit;
  end;

  i := 0;
  LAppenderDeleted := False;

  repeat
    if Self.FLoggerThread.FAppendersDecorators[i].FLogAppender = aAppender then
    begin
      Self.FLoggerThread.FAppendersDecorators.Delete(i);
      LAppenderDeleted := True;
    end;

    Inc(i);
  until (LAppenderDeleted or (i = Self.FLoggerThread.FAppendersDecorators.Count));
end;

Plus. I removed the above code beacuse Self.FLogAppenders and Self.FLoggerThread.FAppenders are the same list:

  i := Self.FLoggerThread.FAppenders.IndexOf(aAppender);
  if i >= 0 then
    Self.FLoggerThread.FAppenders.Delete(i);

AddAppender raises AccessViolation and duplicates appenders

Adding appender to LogWriter by AddAppender procedure log twice.

procedure TCustomLogWriter.AddAppender(const aAppender: ILogAppender);
begin
   Self.FLoggerThread.FAppenders.Add(aAppender);
   Self.FLogAppenders.Add(aAppender); 
   Self.FLoggerThread.FAppendersDecorators.Add(TLoggerThread.TAppenderAdapter.Create(aAppender));
end;

Duplicate is caused by the first line of the procedure Self.FLoggerThread.FAppenders.Add(aAppender); because Self.FLogAppenders is passed to Self.FLoggerThread so both are the same List.

Access violation occurs because Self.FLoggerThread.FAppendersDecorators is nil till the first Thread Execute.

Here is the modified version:

procedure TCustomLogWriter.AddAppender(const aAppender: ILogAppender);
begin 
   Self.FLogAppenders.Add(aAppender); 
   if Assigned( Self.FLoggerThread.FAppendersDecorators) then
     Self.FLoggerThread.FAppendersDecorators.Add(TLoggerThread.TAppenderAdapter.Create(aAppender));
end;

Adding Date to fileappender filename

Hi,
I would like to see an option to add the current date to the fileappender.
Do you thinks this is helpfull?

Should I create a first implementation and add it as a pull request?
If yes, I would enhance the TLoggerProFileAppenderBase class. Maybe by adding only TFileAppenderOption.

Regards
Jens

EMonitorLockException in ThreadSafeQueueU.pas when logging from thread

Hi Daniele,

After receiving an Eurekalog crash report from a customer, I tried to analyse the problem. I could not reproduce it on my PC yet and it seems to occur randomly on the customer's computer, so it looks like a typical race condition. Here are the relevant lines of the Eurekalog report:

EMonitorLockException Object lock not owned.

|005B7380|Application.exe|ThreadSafeQueueU.pas         |{ThreadSafeQueueU}TThreadSafeQueue<LoggerPro |TLogItem>.Enqueue                |157[0]   |
|005B61B5|Application.exe|LoggerPro.pas                |TLogWriter                                   |Log                              |557[5]   |
|0110346B|Application.exe|System.Generics.Defaults.pas |                                             |                                 |39[0]    |
|010FF5A2|Application.exe|Update.Index.pas             |TUpdater                                     |WaitForCompletion                |845[4]   |
|010FF560|Application.exe|Update.Index.pas             |TUpdater                                     |WaitForCompletion                |841[0]   |

We have the following scenario: The main thread starts a background task (IFuture), which builds up an index of files for later use. Both, main and background task log their status with LoggerPro. If the main task needs the index, it calls the following routine:

function TUpdater.WaitForCompletion: boolean;
begin
  Log.Enter('Updater.WaitForCompletion', 'INDEX');
  // Waits until the IFuture task is finished and returns its status
  // The calling thread is blocked while waiting
  Result := (FTask.Value = stLoaded);
  Log.Exit('Updater.WaitForCompletion', 'INDEX');
end;

Log.Enter and Log.Exit are just two wrapper functions around Log.Debug that I have added to LoggerPro. The Exception occured on the Log.Exit call

Normally the task takes some time, so the typical log output is:

2022-04-21 15:22:13:937  [TID    16780][INFO   ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\#####
2022-04-21 15:22:13:937  [TID    16780][DEBUG  ] [INDEX ] --> Updater.StopUpdate
2022-04-21 15:22:13:937  [TID    16780][DEBUG  ] [INDEX ] <-- Updater.StopUpdate
2022-04-21 15:22:13:987  [TID    16780][INFO   ] [INDEX ] Contains 240 Files
2022-04-21 15:22:13:987  [TID    16780][INFO   ] [INDEX ] Contains 4931 Entries
2022-04-21 15:22:13:987  [TID     3280][DEBUG  ] [INDEX ] Renewing Index
2022-04-21 15:22:13:987  [TID    16780][DEBUG  ] [INDEX ] --> Updater.WaitForCompletion
2022-04-21 15:22:14:080  [TID     3280][INFO   ] [INDEX ] Remove 0 Files
2022-04-21 15:22:14:080  [TID     3280][INFO   ] [INDEX ] Check 238 xxx Files
2022-04-21 15:22:14:080  [TID     3280][INFO   ] [INDEX ] Check 2 yyy Files
2022-04-21 15:22:14:242  [TID     3280][INFO   ] [INDEX ] Contains 240 Files
2022-04-21 15:22:14:242  [TID     3280][INFO   ] [INDEX ] Contains 4931 Entries
2022-04-21 15:22:14:242  [TID     3280][DEBUG  ] [INDEX ] Updater.Status - stLoaded
2022-04-21 15:22:14:242  [TID    16780][DEBUG  ] [INDEX ] <-- Updater.WaitForCompletion
... Normal work continues here

This is the log output when there is "nothing" to do:

2022-04-21 14:18:14:972  [TID    22208][INFO   ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\#####
2022-04-21 14:18:14:972  [TID    22208][DEBUG  ] [INDEX ] --> Updater.StopUpdate
2022-04-21 14:18:14:972  [TID    22208][DEBUG  ] [INDEX ] <-- Updater.StopUpdate
2022-04-21 14:18:14:973  [TID    22208][INFO   ] [INDEX ] Contains 0 Files
2022-04-21 14:18:14:973  [TID    22208][INFO   ] [INDEX ] Contains 0 Entries
2022-04-21 14:18:14:974  [TID    14984][DEBUG  ] [INDEX ] Renewing Index
2022-04-21 14:18:14:974  [TID    14984][INFO   ] [INDEX ] Remove 0 Files
2022-04-21 14:18:14:974  [TID    14984][INFO   ] [INDEX ] Check 0 xxx Files
2022-04-21 14:18:14:974  [TID    14984][INFO   ] [INDEX ] Check 0 yyy Files
2022-04-21 14:18:14:977  [TID    14984][INFO   ] [INDEX ] Contains 0 Files
2022-04-21 14:18:14:977  [TID    14984][INFO   ] [INDEX ] Contains 0 Entries
2022-04-21 14:18:14:977  [TID    14984][DEBUG  ] [INDEX ] Updater.Status - stLoaded
2022-04-21 14:18:14:979  [TID    22208][DEBUG  ] [INDEX ] --> Updater.WaitForCompletion
2022-04-21 14:18:14:979  [TID    22208][DEBUG  ] [INDEX ] <-- Updater.WaitForCompletion
... Normal work continues here

Note that the updater was finished (stLoaded) before WaitForCompletion was called.

This is the LoggerPro output matching the bug report. The EMonitorLockException occured on the Log.Exit call in TUpdater.WaitForCompletion and this line is missing from the log:

2022-04-21 14:42:03:003  [TID    20620][INFO   ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\#####
2022-04-21 14:42:03:003  [TID    20620][DEBUG  ] [INDEX ] --> Updater.StopUpdate
2022-04-21 14:42:03:003  [TID    20620][DEBUG  ] [INDEX ] <-- Updater.StopUpdate
2022-04-21 14:42:03:004  [TID    20620][INFO   ] [INDEX ] Contains 0 Files
2022-04-21 14:42:03:004  [TID    20620][INFO   ] [INDEX ] Contains 0 Entries
2022-04-21 14:42:03:004  [TID     3312][DEBUG  ] [INDEX ] Renewing Index
2022-04-21 14:42:03:004  [TID     3312][INFO   ] [INDEX ] Remove 0 Files
2022-04-21 14:42:03:004  [TID     3312][INFO   ] [INDEX ] Check 0 xxx Files
2022-04-21 14:42:03:004  [TID     3312][INFO   ] [INDEX ] Check 0 yyy Files
2022-04-21 14:42:03:008  [TID    20620][DEBUG  ] [INDEX ] --> Updater.WaitForCompletion
2022-04-21 14:42:03:008  [TID     3312][INFO   ] [INDEX ] Contains 0 Files
2022-04-21 14:42:03:008  [TID     3312][INFO   ] [INDEX ] Contains 0 Entries
2022-04-21 14:42:03:008  [TID     3312][DEBUG  ] [INDEX ] Updater.Status - stLoaded
... Normal work continues here

Note that the updater was still working (on nothing ;-)) when WaitForCompletion was called, but it probably all happend in the same millisecond, so I assume that thread 3312 still held the lock, when exception thread 20620 called Log.Exit.

Is there something we are doing wrong or have we come across a race condition in LoggerPro?

Log for udp

Can add logger for udp to debug?
There is useful to debug for mobile.

Feature Request: Ability to support multiple log directories

We have a DMVC web server where we write log entries for each request into its own file. We do this by creating a GUID when each web request is received and passing this in as the Log Tag.

Is there any simple way to use the first two characters of the GUID to write the log file into a sub-directory that uses those characters as the directory name. E.g. with a GUID of F900E9A6-4830-48CF-840B-7EB1110CCB76, write the log file to the "logs\F9" directory. The reason for this is that the file system is struggling to keep up with the number of log files we create. We're looking to use ELK to post process (and then delete) the log files on the day after the request has been served. But we are still handling approx 160k requests each day => 160k files.

I've looked at overriding the TLoggerProFileAppenderManaged.WriteLog in a sub class but it makes calls to private methods that are no accessible to a subclass. I'd rather not have to re-implement this class.

VCLMemoLogAppender enhancement - check for valid memo handle before sending a message

I stumbled over a problem with the implementation of the logging class when I added a memo on my main panel as a log output option.

My logging class wrapper sends an ExitApplicationevent to the logger when the application terminates (in finalization part of my loggingclass wrapper)

At this point the form containing the memo is already destroyed so the FMemo.parent and FMemo.owner handles are already nil and lead to an error/exception when trying to write to the memo.

I've modified the WriteLog procedure to check if the owner of a TMemo is still valid before trying to write to it.
In this way no exception is raised and the application can shut down sending the ExitApplication messages to the remaining LogAppenders like FileAppender or SyslogAppender

procedure TVCLMemoLogAppender.WriteLog(const aLogItem: TLogItem);
var
  lText: string;
begin
  if Assigned(FMemo) then
  begin
    if FMemo.owner = nil then exit;
  end;

  lText := Format(DEFAULT_LOG_FORMAT, [datetimetostr(aLogItem.TimeStamp), aLogItem.ThreadID, aLogItem.LogTypeAsString, aLogItem.LogMessage,
    aLogItem.LogTag]);
  TThread.Queue(nil,
    procedure
    begin
      FMemo.Lines.BeginUpdate;
      try
        if FMemo.Lines.Count = FMaxLogLines then
          FMemo.Lines.Delete(0);
        FMemo.Lines.Add(lText)
      finally
        FMemo.Lines.EndUpdate;
      end;
      SendMessage(FMemo.Handle, EM_SCROLLCARET, 0, 0);
    end);
end;

Speed testing file appender

Hi,

Using the fileappender demo project, I have add the following code on a button click:

for i := 1 to 100000 do
begin
Log.Debug('Debug message #' + inttostr(i), 'TAG1');
end;

I have found the resulting file does not contain all 100000 entries. Is there a limit to the speed of writing?

Supporting DebugView

In sample you mentioned sysinternals debugview. Tryid it with no success.

Do I have to provide special settings to make loggerpro's log files readable by debugview and/or show log entries "live" with debugview?
TIA

Race condition with TThreadedQueue usage

After struggling for several weeks with random "Runtime error 217" appearing at program termination, we have found out that there is most probably a race condition with the use of TThreadQueue.

Our applications creates two log writer instances. These writers are mostly used during program startup. When leaving the application running with no special interaction (i.e. overnight on a locked desktop), it almost always end up with all the loggerpro threads (TLoggerThread and TAppenderThread) consuming all available CPU. At this point, closing the application will result in a runtime error 217 (which basically is an exception happening when system.SysUtils.pas finalization clause has alread been executed and the exception handling system terminated).

Trace captured with madExcept while the process is pegging the CPU but before termination shows that they are all locked in TMonitor.Wait: 3 of them stopped on "ResetEvent" and the last one (random) on "NewWaitObject".

The capture was performed on several occasions and with several different cases of hung process and they all look exactly the same. Trace perfromed while the process isn't using all available CPU do not exhibit that same pattern (threads are on "WaitForSingleObjects")

madTraceProcess_wineur_race_condition.zip

add LoggerPro.FMXMemoAppender.pas

can you please add FMX logger support, like below or change by compiler directive

unit LoggerPro.FMXMemoAppender;
{ <@abstract(The unit to include if you want to use the @link(TFMXMemoLogAppender))
@author(Daniele Teti) }

interface

uses
LoggerPro,
System.Classes,
FMX.StdCtrls;

type
{ @abstract(Appends formatted @link(TLogItem) to a TMemo in a VCL application) }
TFMXMemoLogAppender = class(TLoggerProAppenderBase)
private
FMemo: TMemo;
FMaxLogLines: Word;
FClearOnStartup: Boolean;
public
constructor Create(aMemo: TMemo; aMaxLogLines: Word = 100; aClearOnStartup: Boolean = False); reintroduce;
procedure Setup; override;
procedure TearDown; override;
procedure WriteLog(const aLogItem: TLogItem); override;
end;

implementation

uses
System.SysUtils,
Winapi.Windows,
Winapi.Messages;

const
DEFAULT_LOG_FORMAT = '%0:s [TID %1:-8d][%2:-10s] %3:s [%4:s]';

{ TVCLMemoLogAppender }

constructor TFMXMemoLogAppender.Create(aMemo: TMemo; aMaxLogLines: Word; aClearOnStartup: Boolean);
begin
inherited Create;
FMemo := aMemo;
FMaxLogLines := aMaxLogLines;
FClearOnStartup := aClearOnStartup;
end;

procedure TFMXMemoLogAppender.Setup;
begin
if FClearOnStartup then
begin
TThread.Synchronize(nil,
procedure
begin
FMemo.Clear;
end);
end;
end;

procedure TFMXMemoLogAppender.TearDown;
begin
// do nothing
end;

procedure TFMXMemoLogAppender.WriteLog(const aLogItem: TLogItem);
var
lText: string;
begin
lText := Format(DEFAULT_LOG_FORMAT, [datetimetostr(aLogItem.TimeStamp), aLogItem.ThreadID, aLogItem.LogTypeAsString, aLogItem.LogMessage,
aLogItem.LogTag]);
TThread.Queue(nil,
procedure
begin
FMemo.Lines.BeginUpdate;
try
if FMemo.Lines.Count = FMaxLogLines then
FMemo.Lines.Delete(0);
FMemo.Lines.Add(lText)
finally
FMemo.Lines.EndUpdate;
end;
SendMessage(FMemo.Handle, EM_SCROLLCARET, 0, 0);
end);
end;

end.

There seems to be no info about supported Delphi versions

There seems to be no info about supported Delphi versions on the main page or readme.md.

I tried compiling the code in Delphi XE2 and failed:

if FLogsFolder.IsEmpty then // <<-- this line fails in XE2

[DCC Error] LoggerPro.FileAppender.pas(126): E2018 Record, object or class type required
[DCC Fatal Error] LoggerPro.pas(230): F2063 Could not compile used unit 'LoggerPro.FileAppender.pas'

breaking compatibility with Delphi XE3

With version 1.3.0 there is a problem in ThreadSafeQueueU.pas :
E2506 Method of parametrized type declared in interface section must not use local symbol 'cRetryCount'

function is TThreadSafeQueue.Enqueue(const Item: T): Boolean;

image

XE5 support

Hi!
It seems for me, that there is no support for XE5, while the description says, there is. Am I right? I've found packages for XE7 and upper.
Thanks!

File.Appender error?

hi, in LoggerPro.FileAppender.pas in the constructor procedure

constructor TLoggerProFileAppenderBase.Create(aMaxBackupFileCount: Integer; aMaxFileSizeInKiloByte: Integer; aLogsFolder: string;
  aFileAppenderOptions: TFileAppenderOptions; aLogFileNameFormat: string; aLogFormat: string; aEncoding: TEncoding);
begin
  inherited Create(ALogFormat);
  fLogsFolder := aLogsFolder;  
  fMaxBackupFileCount:= Min(1, aMaxBackupFileCount);
  fMaxFileSizeInKiloByte := aMaxFileSizeInKiloByte;
  fLogFileNameFormat := aLogFileNameFormat;
  fFileAppenderOptions := aFileAppenderOptions;
  if Assigned(aEncoding) then
    fEncoding := aEncoding
  else
    fEncoding := TEncoding.DEFAULT;
end;

I think there is an error in the line
fMaxBackupFileCount:= Min(1, aMaxBackupFileCount);

in this case fMaxBackupFileCount can never be higher than 1.

I think it is more correct:
fMaxBackupFileCount:= Max(1, aMaxBackupFileCount);

thanks a lot for this library.

Comply with the Apache License

Hello folks,

I want to use LoggerPro in my Delphi application and first to say thank you for the fantastic work.

There is just one thing I have to know before using it. Is it enough to put the name and the copyright together with the Apache 2.0 license in a textfile which resides in the same folder as the exe file? Or do I have to include the information explicitely in my GUI?

I ask because I evaluating the use in a application which will have a very minimalistic GUI (Console Application).

Thank you!

NSQueue appender

For our project at work I have created a nsq appender for logger pro. This allow us to collect logs from many different servers in a decentralized way: no central point of failure, local caching of log items, consumers can be added for many different types of messages, etc.

Would it be worthwhile to add this write to loggerPro ?

ConsoleAppender outputs log messages time shifted

When stepping through code with a lot of debug logouts, the console window gets updated with a big time difference.
Then when continue stepping through lines of codes without debug logouts, more and more buffered logouts are appended to the console.

It sometimes happens, that the last debug logouts only appear when quitting the application.

Minor issue for old delphi - should be "TThread.CurrentThread.ThreadID"

This is an excellent logging library, in that it's easy to understand and use, supporting multi target, and allowing writing custom appender (this is a very useful feature).

Just one very minor issue report, under xe4, TThread.Current.ThreadID should be TThread.CurrentThread.ThreadID.

thanks!

MaxBackupFileCount always equal 1

Maybe must be Max?

constructor TLoggerProFileAppenderBase.Create(aMaxBackupFileCount: Integer; aMaxFileSizeInKiloByte: Integer; aLogsFolder: string;
aFileAppenderOptions: TFileAppenderOptions; aLogFileNameFormat: string; aLogFormat: string; aEncoding: TEncoding);
begin
inherited Create(ALogFormat);
fLogsFolder := aLogsFolder;
fMaxBackupFileCount:= Min(1, aMaxBackupFileCount);
fMaxFileSizeInKiloByte := aMaxFileSizeInKiloByte;
fLogFileNameFormat := aLogFileNameFormat;

Feature Request for low level Windows Event logger

The current implementation requires a TService instance to be passed to the constructor of TLoggerProWindowsEventLogAppender

This limits the use of the logger to service applications.

I've written a unit which allows the service name (or a proxy of that) to be passed as plain text and a separate instance of the low level windows event logger is created.

Happy to share this code with the project. Usage is is simple as

var SIEMLog: ILogWriter; ... SIEMLog := BuildLogWriter([TLoggerProWindowsEventLogAppenderLL.Create('TheServiceName")]); ... SIEMLog.Debug('This is a test message');

``

Is log ordered by tag?

I would like to have log ordered by datetime instead of tag:

2022-06-17 08:38:47:672  [TID 41312   ][INFO      ] [RESPONSE  ] [200 (0ms)      ] GET /turma/35102/disciplina HTTP/1.1 
2022-06-17 08:38:47:703  [TID 21272   ][INFO      ] [RESPONSE  ] [200 (0ms)      ] GET /matricula?idTurma=35102&idDisciplina=11133 HTTP/1.1 
2022-06-17 08:38:47:766  [TID 15512   ][INFO      ] [RESPONSE  ] [200 (0ms)      ] GET /horario?idTurma=35102&idDisciplina=11133&somenteDatasComTarefa=false HTTP/1.1 
2022-06-17 08:38:49:859  [TID 25364   ][INFO      ] [RESPONSE  ] [200 (0ms)      ] OPTIONS /api/v1/atendimento/conversa?id_canal=25&id_pessoa=0&id_solicitante=0&id_atendente=333671&id_professor=0&data= HTTP/1.1 
2022-06-17 08:38:51:250  [TID 11616   ][INFO      ] [RESPONSE  ] [200 (0ms)      ] GET /api/v1/atendimento/conversa?id_canal=25&id_pessoa=0&id_solicitante=0&id_atendente=333671&id_professor=0&data= HTTP/1.1 InUse: True
2022-06-17 08:34:33:270  [TID 27088   ][DEBUG     ] [SQL       ] Debug connection: ; ThreadId: 27088; InUse: True
2022-06-17 08:34:33:270  [TID 27088   ][DEBUG     ] [SQL       ] Debug connection: ; ThreadId: 27088; InUse: True
2022-06-17 08:34:33:286  [TID 27088   ][DEBUG     ] [SQL       ] Debug connection: ; ThreadId: 27088; InUse: True

GetCurrentProcessID is only for windows

function TLoggerProFileAppender.GetLogFileName
line 104: lFormat := '.PID-' + IntToStr(GetCurrentProcessID) + lFormat;
function GetCurrentProcessID is only for windows!

Database Appender

is there any news for the database appender, i don't see in the source

Bug in constructor TLoggerProUDPSyslogPacket.Create(pLogItem: TLogItem; pHostName: string; pUserName: string; pApplication: string; pVersion: string; pProcID: string; pUnixLineBreaks: Boolean; pUTF8BOM: Boolean);

constructor TLoggerProUDPSyslogPacket.Create(pLogItem: TLogItem; pHostName: string; pUserName: string;
pApplication: string; pVersion: string; pProcID: string; pUnixLineBreaks: Boolean; pUTF8BOM: Boolean);

If pUnixLineBreaks is false the logger doesn't sends the LogMessage. Currently:

if FUnixLineBreaks then
FMessageData := pLogItem.LogMessage.Replace(sLineBreak, '#10', [rfReplaceAll]);

Should be:

if FUnixLineBreaks then
FMessageData := pLogItem.LogMessage.Replace(sLineBreak, '#10', [rfReplaceAll])
else
FMessageData := pLogItem.LogMessage;

Is a log file viewer planned?

One of the best features that I'm missing from SmartInspect is the log file viewer...curious if there are plans to add a viewer here.

EInOutError in TLoggerProFileAppender

Dear Daniele.
An EInOutError occurs in procedure RotateLog if you want to write messages with different tags in one file.
The following test produces the error:

procedure TForm1.Button1Click(Sender: TObject);
var
  Lg: ILogWriter;
  i: Integer;
begin
  Lg := BuildLogWriter([TLoggerProFileAppender.Create(10, 5,
    TPath.Combine(ExtractFileDir(ParamStr(0)), 'LogDir'), [], '%s.%2.2d.log')]); // initialized to write different tags in one file
  Lg.Info('Test started V1.0!', 'Test'); // first tag 'Test'

  for i := 0 to 100 do
    Lg.Info('Test LoopCnt: %d!',[i],'Loop'); // second tag 'Loop'

  Sleep(2000);

end;

FileAppender write in the wrong position.

Hello,
i have a global ILogWriter that is called from the dpr and from a main unit.
Before the program close i have one last debug write on the dpr, when that happens it write back in the last position it had on the last write (done in the dpr), so it overwrite some of the log done while in the main unit.

Configuration via INI file

Some of the other logging frameworks I've previously used allow configuration at run time via INI configuration file settings. E.g. something like Log4D based on the Log4J / Log4Net code bases.

It is really useful when you hit a production issue and wish to increase the verbosity of logging from just Error through to Debug level.

Can this be done easily in LoggerPro ?

Add demo for Console logger in GUI app

Tried it, and allocated the Console, but did not see anything in the Console.

There must be some hoops I should jump through to get it working properly.

That would be very nice way to "debug" things on different computers (if not remote debugging possibilities), so really would like to test that and get it to working.

REST adapter

Any news on this?

I think I need this as I've built a Logary endpoint in .NET / F# for some projects. The main project however is a big Delphi app. I would like to get it logging to this end point.

I can help with it and/or test alpha/beta.

Wrong Message Priority in UDPSyslogAppender for Several Classes

When sending a message to the logger of several types, a generic Syslog Server receives the wrong priority levels.


log.error('Something', '')` => warning
log.warning('Something'. '') => notice

Info and debug are fine. The problem is in the numeric constants for the Syslog Severity

Here's the official list of syslog severity levels:

[SysLogSeverity]
7=slDebug
6=slInformational
5=slNotice
4=slWarning
3=slError
2=slCritical
1=slAlert
0=slEmergency

I have corrected lines 127 - 138 in LoggerPro.UDPSyslogAppender.pas accordingly for .Warning and .Error:

  case pLogItem.LogType of
    TLogType.Debug:
      FPriority := RFC5424Priority(1, 7);
    TLogType.Info:
      FPriority := RFC5424Priority(1, 6);
    TLogType.Warning:
      FPriority := RFC5424Priority(1, 4); // 4 = slWarning
    TLogType.Error:
      FPriority := RFC5424Priority(1, 3); // 3 = slError
  end;
  if pLogItem.LogMessage.Contains('Access Violation') then
    FPriority := RFC5424Priority(1, 2); // 2 = slCritical

now the log priority levels are sent as expected.
I also set the severity for the Access ViolationMessages to one level above error (critical = 2)

Add a custom logs folder in the TLoggerProFileAppender

Add a custom logs folder in the TLoggerProFileAppender options in the constructor

    constructor Create(
      aMaxBackupFileCount: Integer = DEFAULT_MAX_BACKUP_FILE_COUNT;
      aMaxFileSizeInKiloByte: Integer = DEFAULT_MAX_FILE_SIZE_KB;
      aLogsFolder: String = ''; //by default, it logs into the executable folder
      aFileAppenderOptions: TFileAppenderOptions = [];
      aLogFormat: String = DEFAULT_LOG_FORMAT);

Only one backup file ever used

Found a problem with the backup files it is only ever using 1 backup file regardless of what you set the MaxBackupFileCount to
In LoggerPro.FileAppender create it has
fMaxBackupFileCount:= Min(1, aMaxBackupFileCount);

Feature request for automatic unwinding of chained exceptions

Dear Daniel,

I just recently started using Delphi.
Coming from a Java background, I definitely missed a decent logging framework, so I'm very glad you created LoggerPro. Thank you for your effort!

I was wondering if LoggerPro might support (in future editions) some kind of automatic nested exception unwinding (e.g. just passing the error object instead of a message). This way chained exceptions could be traced also.

Kind regards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.