diff --git a/README.md b/README.md
index dd1df58..996a985 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ Aqui temos uma lista de todos os _providers_ disponíveis:
| ListBox | DataLogger.Provider.ListBox |
| ListView | DataLogger.Provider.ListView |
| [Logstach](https://www.elastic.co/pt/logstash/) | DataLogger.Provider.Logstach |
-| [MatterMost](https://mattermost.com/) | DataLogger.Provider.Mattermost |
+| [Mattermost](https://mattermost.com/) | DataLogger.Provider.Mattermost
DataLogger.Provider.Mattermost.Hooks |
| Memo | DataLogger.Provider.Memo |
| Memory | DataLogger.Provider.Memory |
| OutputDebugString | DataLogger.Provider.OutputDebugString |
diff --git a/Samples/Model5/Model5.dpr b/Samples/Model5/Model5.dpr
new file mode 100644
index 0000000..0a2ef0c
--- /dev/null
+++ b/Samples/Model5/Model5.dpr
@@ -0,0 +1,21 @@
+program Model5;
+
+uses
+ Vcl.Forms,
+ Unit2 in 'Unit2.pas' {Form2},
+ DataLogger in '..\..\src\Core\DataLogger.pas',
+ DataLogger.Provider in '..\..\src\Core\DataLogger.Provider.pas',
+ DataLogger.Types in '..\..\src\Core\DataLogger.Types.pas',
+ DataLogger.Utils in '..\..\src\Core\DataLogger.Utils.pas',
+ DataLogger.Provider.Memo in '..\..\src\Providers\DataLogger.Provider.Memo.pas';
+
+{$R *.res}
+
+begin
+ ReportMemoryLeaksOnShutdown := True;
+
+ Application.Initialize;
+ Application.MainFormOnTaskbar := True;
+ Application.CreateForm(TForm2, Form2);
+ Application.Run;
+end.
diff --git a/Samples/Model5/Model5.dproj b/Samples/Model5/Model5.dproj
new file mode 100644
index 0000000..38c7f2a
--- /dev/null
+++ b/Samples/Model5/Model5.dproj
@@ -0,0 +1,962 @@
+
+
+ {68F29AB5-BE78-429E-BAE3-DC31092F9825}
+ 19.4
+ VCL
+ True
+ Debug
+ Win32
+ 1
+ Application
+ Model5.dpr
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ .\$(Platform)\$(Config)
+ .\$(Platform)\$(Config)
+ false
+ false
+ false
+ false
+ false
+ System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+ Model5
+
+
+ vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;DataSnapNativeClient;FMXTee;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ true
+
+
+ vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;DataSnapNativeClient;FMXTee;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)
+
+
+ DEBUG;$(DCC_Define)
+ true
+ false
+ true
+ true
+ true
+ true
+ true
+
+
+ false
+ true
+ PerMonitorV2
+
+
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+ true
+ PerMonitorV2
+
+
+
+ MainSource
+
+
+
+ dfm
+
+
+
+
+
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+ Cfg_2
+ Base
+
+
+
+ Delphi.Personality.12
+ Application
+
+
+
+ Model5.dpr
+
+
+
+
+
+ Model5.exe
+ true
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ classes
+ 64
+
+
+ classes
+ 64
+
+
+
+
+ res\xml
+ 1
+
+
+ res\xml
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\armeabi
+ 1
+
+
+ library\lib\armeabi
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\mips
+ 1
+
+
+ library\lib\mips
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\values-v21
+ 1
+
+
+ res\values-v21
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-ldpi
+ 1
+
+
+ res\drawable-ldpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-small
+ 1
+
+
+ res\drawable-small
+ 1
+
+
+
+
+ res\drawable-normal
+ 1
+
+
+ res\drawable-normal
+ 1
+
+
+
+
+ res\drawable-large
+ 1
+
+
+ res\drawable-large
+ 1
+
+
+
+
+ res\drawable-xlarge
+ 1
+
+
+ res\drawable-xlarge
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ 0
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .dll;.bpl
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .bpl
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ 0
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+
+
+ 12
+
+
+
+
+
diff --git a/Samples/Model5/Unit2.dfm b/Samples/Model5/Unit2.dfm
new file mode 100644
index 0000000..da51cca
--- /dev/null
+++ b/Samples/Model5/Unit2.dfm
@@ -0,0 +1,83 @@
+object Form2: TForm2
+ Left = 0
+ Top = 0
+ Caption = 'Form2'
+ ClientHeight = 443
+ ClientWidth = 923
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -12
+ Font.Name = 'Segoe UI'
+ Font.Style = []
+ FormStyle = fsStayOnTop
+ OnCreate = FormCreate
+ TextHeight = 15
+ object btn1: TButton
+ Left = 8
+ Top = 8
+ Width = 75
+ Height = 25
+ Caption = 'Iniciar'
+ TabOrder = 0
+ OnClick = btn1Click
+ end
+ object Panel1: TPanel
+ Left = 0
+ Top = 41
+ Width = 923
+ Height = 402
+ Align = alBottom
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Caption = 'Panel1'
+ TabOrder = 1
+ ExplicitLeft = 8
+ ExplicitTop = 39
+ ExplicitWidth = 624
+ object Memo1: TMemo
+ Left = 457
+ Top = 1
+ Width = 465
+ Height = 400
+ Align = alClient
+ TabOrder = 0
+ ExplicitLeft = 311
+ ExplicitWidth = 304
+ end
+ object Memo2: TMemo
+ Left = 1
+ Top = 1
+ Width = 456
+ Height = 400
+ Align = alLeft
+ TabOrder = 1
+ end
+ end
+ object btnParar: TButton
+ Left = 89
+ Top = 8
+ Width = 75
+ Height = 25
+ Caption = 'Parar'
+ TabOrder = 2
+ OnClick = btnPararClick
+ end
+ object btnLimpar: TButton
+ Left = 378
+ Top = 15
+ Width = 75
+ Height = 25
+ Caption = 'Limpar'
+ TabOrder = 3
+ OnClick = btnLimparClick
+ end
+ object btnLimpar2: TButton
+ Left = 463
+ Top = 15
+ Width = 75
+ Height = 25
+ Caption = 'Limpar'
+ TabOrder = 4
+ OnClick = btnLimpar2Click
+ end
+end
diff --git a/Samples/Model5/Unit2.pas b/Samples/Model5/Unit2.pas
new file mode 100644
index 0000000..28d9189
--- /dev/null
+++ b/Samples/Model5/Unit2.pas
@@ -0,0 +1,110 @@
+unit Unit2;
+
+interface
+
+uses
+ Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
+ Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
+
+type
+ TForm2 = class(TForm)
+ btn1: TButton;
+ Panel1: TPanel;
+ Memo1: TMemo;
+ Memo2: TMemo;
+ btnParar: TButton;
+ btnLimpar: TButton;
+ btnLimpar2: TButton;
+ procedure btn1Click(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure btnLimparClick(Sender: TObject);
+ procedure btnLimpar2Click(Sender: TObject);
+ procedure btnPararClick(Sender: TObject);
+ private
+ { Private declarations }
+ LStop: Boolean;
+ public
+ { Public declarations }
+ end;
+
+var
+ Form2: TForm2;
+
+implementation
+
+uses
+ DataLogger,
+ DataLogger.Provider.Memo;
+
+var
+ M1: TDataLoggerProvider;
+ M2: TDataLoggerProvider;
+
+{$R *.dfm}
+
+procedure TForm2.btn1Click(Sender: TObject);
+begin
+ LStop := False;
+
+ TThread.CreateAnonymousThread(
+ procedure
+ var
+ I: Integer;
+ begin
+ for I := 1 to 100 do
+ begin
+ if LStop then
+ Break;
+
+ Sleep(100);
+
+ if (I = 5) or (I = 70) then
+ begin
+ Logger.Warn('StartTransaction');
+ Logger.StartTransaction; // 1
+ end;
+
+ try
+ Logger.Info('Teste ' + I.ToString);
+ finally
+ if I = 50 then
+ begin
+ Logger.CommitTransaction; // 1
+ Logger.Warn('CommitTransaction');
+ end;
+
+ if I = 90 then
+ begin
+ Logger.RollbackTransaction;
+ Logger.Warn('RollbackTransaction');
+ end;
+ end;
+ end;
+ end).Start;
+end;
+
+procedure TForm2.btnLimpar2Click(Sender: TObject);
+begin
+ Memo2.Clear;
+end;
+
+procedure TForm2.btnLimparClick(Sender: TObject);
+begin
+ Memo1.Clear;
+end;
+
+procedure TForm2.btnPararClick(Sender: TObject);
+begin
+ LStop := True;
+end;
+
+procedure TForm2.FormCreate(Sender: TObject);
+begin
+ M1 := TProviderMemo.Create(Memo2).UseTransaction(True);
+ M2 := TProviderMemo.Create(Memo1);
+
+ Logger.SetProvider([M1, M2]);
+ Logger.SetLogFormat(TLoggerFormat.LOG_TIMESTAMP + ': ' + TLoggerFormat.LOG_MESSAGE);
+end;
+
+end.
diff --git a/src/Core/DataLogger.Provider.pas b/src/Core/DataLogger.Provider.pas
index 726f7b0..b1a8c27 100644
--- a/src/Core/DataLogger.Provider.pas
+++ b/src/Core/DataLogger.Provider.pas
@@ -18,52 +18,51 @@ TDataLoggerProvider = class(TThread)
private
FCriticalSection: TCriticalSection;
FEvent: TEvent;
+ FListLoggerBase: TList;
+ FListTransaction: TObjectDictionary>;
FListLoggerItem: TList;
- FLogFormat: string;
- FFormatTimestamp: string;
+
FLogLevel: TLoggerType;
FDisableLogType: TLoggerTypes;
FOnlyLogType: TLoggerTypes;
- FLogException: TOnLogException;
- FMaxRetry: Integer;
+
FUseTransaction: Boolean;
+ FAutoCommit: TLoggerTypes;
+ FTypeAutoCommit: TLoggerTypeAutoCommit;
FInTransaction: Boolean;
FInitialMessage: string;
FFinalMessage: string;
function ExtractCache: TArray;
protected
+ FLogFormat: string;
+ FFormatTimestamp: string;
+ FLogException: TOnLogException;
+ FMaxRetry: Integer;
+
procedure Execute; override;
procedure Save(const ACache: TArray); virtual; abstract;
- function ValidationBeforeSave(const ALogItem: TLoggerItem): Boolean;
- function GetLogFormat: string;
- function GetFormatTimestamp: string;
- function GetLogLevel: TLoggerType;
- function GetDisableLevel: TLoggerTypes;
- function GetOnlyLogType: TLoggerTypes;
- function GetLogException: TOnLogException;
- function GetMaxRetry: Integer;
procedure Lock;
procedure UnLock;
-
- property LogException: TOnLogException read GetLogException;
public
function SetLogFormat(const ALogFormat: string): TDataLoggerProvider;
function SetFormatTimestamp(const AFormatTimestamp: string): TDataLoggerProvider;
function SetLogLevel(const ALogLevel: TLoggerType): TDataLoggerProvider;
- function SetDisableLogType(const ALogType: TLoggerTypes): TDataLoggerProvider;
- function SetOnlyLogType(const ALogType: TLoggerTypes): TDataLoggerProvider;
+ function SetDisableLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+ function SetOnlyLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
function SetLogException(const AException: TOnLogException): TDataLoggerProvider;
function SetMaxRetry(const AMaxRetry: Integer): TDataLoggerProvider;
function SetInitialMessage(const AMessage: string): TDataLoggerProvider;
function SetFinalMessage(const AMessage: string): TDataLoggerProvider;
function UseTransaction(const AUseTransaction: Boolean): TDataLoggerProvider;
- function StartTransaction: TDataLoggerProvider;
- function CommitTransaction: TDataLoggerProvider;
- function RollbackTransaction: TDataLoggerProvider;
+ function AutoCommit(const ALogTypes: TLoggerTypes; const ATypeAutoCommit: TLoggerTypeAutoCommit = tcBlock): TDataLoggerProvider;
+ function StartTransaction(const AUseLock: Boolean = True): TDataLoggerProvider;
+ function CommitTransaction(const ATypeCommit: TLoggerTypeAutoCommit = tcBlock; const AUseLock: Boolean = True): TDataLoggerProvider;
+ function RollbackTransaction(const ATypeCommit: TLoggerTypeAutoCommit = tcBlock): TDataLoggerProvider;
function InTransaction: Boolean;
+ function CountTransaction: Integer;
function Clear: TDataLoggerProvider;
function CountLogInCache: Int64;
@@ -93,7 +92,11 @@ procedure TDataLoggerProvider.AfterConstruction;
FCriticalSection := TCriticalSection.Create;
FEvent := TEvent.Create;
- FListLoggerItem := TList.Create;
+ FListLoggerBase := TList.Create;
+ FListLoggerItem := FListLoggerBase;
+ FListTransaction := TObjectDictionary < Integer, TList < TLoggerItem >>.Create([doOwnsValues]);
+
+ FInTransaction := False;
SetLogFormat(TLoggerFormat.DEFAULT_LOG_FORMAT);
SetFormatTimestamp('yyyy-mm-dd hh:nn:ss:zzz');
@@ -103,6 +106,7 @@ procedure TDataLoggerProvider.AfterConstruction;
SetLogException(nil);
SetMaxRetry(5);
UseTransaction(False);
+ AutoCommit([], tcBlock);
Start;
end;
@@ -113,8 +117,15 @@ procedure TDataLoggerProvider.BeforeDestruction;
FEvent.SetEvent;
WaitFor;
- FListLoggerItem.Free;
- FEvent.Free;
+ Lock;
+ try
+ FListTransaction.Free;
+ FListLoggerBase.Free;
+ FEvent.Free;
+ finally
+ UnLock;
+ end;
+
FCriticalSection.Free;
inherited;
@@ -155,16 +166,16 @@ function TDataLoggerProvider.SetLogLevel(const ALogLevel: TLoggerType): TDataLog
FLogLevel := ALogLevel;
end;
-function TDataLoggerProvider.SetDisableLogType(const ALogType: TLoggerTypes): TDataLoggerProvider;
+function TDataLoggerProvider.SetDisableLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
begin
Result := Self;
- FDisableLogType := ALogType;
+ FDisableLogType := ALogTypes;
end;
-function TDataLoggerProvider.SetOnlyLogType(const ALogType: TLoggerTypes): TDataLoggerProvider;
+function TDataLoggerProvider.SetOnlyLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
begin
Result := Self;
- FOnlyLogType := ALogType;
+ FOnlyLogType := ALogTypes;
end;
function TDataLoggerProvider.SetLogException(const AException: TOnLogException): TDataLoggerProvider;
@@ -210,39 +221,93 @@ function TDataLoggerProvider.UseTransaction(const AUseTransaction: Boolean): TDa
FUseTransaction := AUseTransaction;
end;
-function TDataLoggerProvider.StartTransaction: TDataLoggerProvider;
+function TDataLoggerProvider.AutoCommit(const ALogTypes: TLoggerTypes; const ATypeAutoCommit: TLoggerTypeAutoCommit = tcBlock): TDataLoggerProvider;
+begin
+ Result := Self;
+ FAutoCommit := ALogTypes;
+ FTypeAutoCommit := ATypeAutoCommit;
+end;
+
+function TDataLoggerProvider.StartTransaction(const AUseLock: Boolean = True): TDataLoggerProvider;
+var
+ LCountTransaction: Integer;
begin
Result := Self;
if not FUseTransaction then
Exit;
- Lock;
+ if AUseLock then
+ Lock;
try
- FEvent.SetEvent;
- FInTransaction := True;
+ LCountTransaction := FListTransaction.Count;
+
+ if LCountTransaction = 0 then
+ FInTransaction := True;
+
+ FListLoggerItem := TList.Create;
+ FListTransaction.Add(LCountTransaction + 1, FListLoggerItem);
finally
- UnLock;
+ if AUseLock then
+ UnLock;
end;
end;
-function TDataLoggerProvider.CommitTransaction: TDataLoggerProvider;
+function TDataLoggerProvider.CommitTransaction(const ATypeCommit: TLoggerTypeAutoCommit = tcBlock; const AUseLock: Boolean = True): TDataLoggerProvider;
+var
+ LCountTransaction: Integer;
+ LCurrent: TList;
+ LCurrentValues: TArray;
begin
Result := Self;
if not FUseTransaction then
Exit;
- Lock;
+ if AUseLock then
+ Lock;
try
- FInTransaction := False;
- FEvent.SetEvent;
+ while True do
+ begin
+ LCountTransaction := FListTransaction.Count;
+
+ if LCountTransaction = 0 then
+ Exit;
+
+ FListTransaction.TryGetValue(LCountTransaction, LCurrent);
+ LCurrentValues := LCurrent.ToArray;
+
+ if LCountTransaction > 1 then
+ begin
+ FListTransaction.TryGetValue(LCountTransaction - 1, FListLoggerItem);
+ FListLoggerItem.AddRange(LCurrentValues);
+ end;
+
+ FListTransaction.Remove(LCountTransaction);
+
+ if LCountTransaction = 1 then
+ begin
+ FListLoggerItem := FListLoggerBase;
+ FListLoggerItem.AddRange(LCurrentValues);
+ FEvent.SetEvent;
+
+ FInTransaction := False;
+
+ Break;
+ end;
+
+ if ATypeCommit = tcBlock then
+ Break;
+ end;
finally
- UnLock;
+ if AUseLock then
+ UnLock;
end;
end;
-function TDataLoggerProvider.RollbackTransaction: TDataLoggerProvider;
+function TDataLoggerProvider.RollbackTransaction(const ATypeCommit: TLoggerTypeAutoCommit = tcBlock): TDataLoggerProvider;
+var
+ LCountTransaction: Integer;
begin
Result := Self;
@@ -251,10 +316,31 @@ function TDataLoggerProvider.RollbackTransaction: TDataLoggerProvider;
Lock;
try
- FListLoggerItem.Clear;
- FListLoggerItem.TrimExcess;
+ while True do
+ begin
+ LCountTransaction := FListTransaction.Count;
+
+ if LCountTransaction = 0 then
+ Exit;
+
+ if LCountTransaction > 1 then
+ FListTransaction.TryGetValue(LCountTransaction - 1, FListLoggerItem);
+
+ FListTransaction.Remove(LCountTransaction);
+
+ if LCountTransaction = 1 then
+ begin
+ FListLoggerItem := FListLoggerBase;
+ FEvent.SetEvent;
+
+ FInTransaction := False;
+
+ Break;
+ end;
- FInTransaction := False;
+ if ATypeCommit = tcBlock then
+ Break;
+ end;
finally
UnLock;
end;
@@ -270,6 +356,16 @@ function TDataLoggerProvider.InTransaction: Boolean;
end;
end;
+function TDataLoggerProvider.CountTransaction: Integer;
+begin
+ Lock;
+ try
+ Result := FListTransaction.Count;
+ finally
+ UnLock;
+ end;
+end;
+
function TDataLoggerProvider.CountLogInCache: Int64;
begin
Lock;
@@ -292,58 +388,6 @@ function TDataLoggerProvider.NotifyEvent: TDataLoggerProvider;
end;
end;
-function TDataLoggerProvider.ValidationBeforeSave(const ALogItem: TLoggerItem): Boolean;
-begin
- Result := False;
-
- if (TLoggerType.All in GetDisableLevel) or (ALogItem.&Type in GetDisableLevel) then
- Exit;
-
- if not(TLoggerType.All in GetOnlyLogType) and not(ALogItem.&Type in GetOnlyLogType) then
- Exit;
-
- if not(ALogItem.&Type in GetOnlyLogType) then
- if Ord(GetLogLevel) > Ord(ALogItem.&Type) then
- Exit;
-
- Result := True;
-end;
-
-function TDataLoggerProvider.GetLogFormat: string;
-begin
- Result := FLogFormat;
-end;
-
-function TDataLoggerProvider.GetFormatTimestamp: string;
-begin
- Result := FFormatTimestamp;
-end;
-
-function TDataLoggerProvider.GetLogLevel: TLoggerType;
-begin
- Result := FLogLevel;
-end;
-
-function TDataLoggerProvider.GetDisableLevel: TLoggerTypes;
-begin
- Result := FDisableLogType;
-end;
-
-function TDataLoggerProvider.GetOnlyLogType: TLoggerTypes;
-begin
- Result := FOnlyLogType;
-end;
-
-function TDataLoggerProvider.GetLogException: TOnLogException;
-begin
- Result := FLogException;
-end;
-
-function TDataLoggerProvider.GetMaxRetry: Integer;
-begin
- Result := FMaxRetry;
-end;
-
procedure TDataLoggerProvider.Lock;
begin
FCriticalSection.Acquire;
@@ -356,40 +400,54 @@ procedure TDataLoggerProvider.UnLock;
function TDataLoggerProvider.AddCache(const AValues: TArray): TDataLoggerProvider;
var
- LItems: TArray;
+ I: Integer;
LItem: TLoggerItem;
LMessage: string;
- I: Integer;
begin
Result := Self;
Lock;
try
- LItems := AValues;
-
- for I := Low(AValues) to High(AValues) do
- begin
- LItem := AValues[I];
-
- LMessage := LItem.Message;
-
- if not FInitialMessage.Trim.IsEmpty then
- LMessage := FInitialMessage + LMessage;
-
- if not FFinalMessage.Trim.IsEmpty then
- LMessage := LMessage + FFinalMessage;
-
- LItem.Message := LMessage;
-
- FListLoggerItem.Add(LItem);
+ try
+ for I := Low(AValues) to High(AValues) do
+ begin
+ LItem := AValues[I];
+
+ if (TLoggerType.All in FDisableLogType) or (LItem.&Type in FDisableLogType) then
+ Continue;
+
+ if not(TLoggerType.All in FOnlyLogType) and not(LItem.&Type in FOnlyLogType) then
+ Continue;
+
+ if not(LItem.&Type in FOnlyLogType) then
+ if Ord(FLogLevel) > Ord(LItem.&Type) then
+ Continue;
+
+ LMessage := LItem.Message;
+ try
+ if not FInitialMessage.Trim.IsEmpty then
+ LMessage := FInitialMessage + LMessage;
+
+ if not FFinalMessage.Trim.IsEmpty then
+ LMessage := LMessage + FFinalMessage;
+ finally
+ LItem.Message := LMessage;
+ end;
+
+ FListLoggerItem.Add(LItem);
+
+ if FUseTransaction and FInTransaction then
+ if LItem.&Type in FAutoCommit then
+ begin
+ CommitTransaction(FTypeAutoCommit, False);
+ StartTransaction(False);
+ end;
+ end;
+ finally
+ if not FUseTransaction or not FInTransaction then
+ FEvent.SetEvent;
end;
finally
- if not FUseTransaction then
- FEvent.SetEvent
- else
- if not FInTransaction then
- FEvent.SetEvent;
-
UnLock;
end;
end;
@@ -400,20 +458,16 @@ function TDataLoggerProvider.AddCache(const AValue: TLoggerItem): TDataLoggerPro
end;
function TDataLoggerProvider.ExtractCache: TArray;
-var
- LCache: TArray;
begin
Lock;
try
- LCache := FListLoggerItem.ToArray;
+ Result := FListLoggerItem.ToArray;
FListLoggerItem.Clear;
FListLoggerItem.TrimExcess;
finally
UnLock;
end;
-
- Result := LCache;
end;
end.
diff --git a/src/Core/DataLogger.Types.pas b/src/Core/DataLogger.Types.pas
index 14c2b30..1e33ba8 100644
--- a/src/Core/DataLogger.Types.pas
+++ b/src/Core/DataLogger.Types.pas
@@ -20,6 +20,8 @@ EDataLoggerException = class(Exception)
TLoggerType = (All, Trace, Debug, Info, Success, Warn, Error, Fatal);
TLoggerTypes = set of TLoggerType;
+ TLoggerTypeAutoCommit = (tcAll, tcBlock);
+
TLoggerTypeHelper = record helper for TLoggerType
public
function ToString: string;
diff --git a/src/Core/DataLogger.pas b/src/Core/DataLogger.pas
index c573907..8d5a543 100644
--- a/src/Core/DataLogger.pas
+++ b/src/Core/DataLogger.pas
@@ -17,6 +17,7 @@ interface
TLoggerItem = DataLogger.Types.TLoggerItem;
TLoggerType = DataLogger.Types.TLoggerType;
TLoggerTypes = DataLogger.Types.TLoggerTypes;
+ TLoggerTypeAutoCommit = DataLogger.Types.TLoggerTypeAutoCommit;
TOnLogException = DataLogger.Types.TOnLogException;
TDataLoggerProvider = DataLogger.Provider.TDataLoggerProvider;
TLoggerFormat = DataLogger.Types.TLoggerFormat;
@@ -34,12 +35,14 @@ TDataLogger = class sealed(TThread)
FName: string;
constructor Create;
+ procedure Start;
+
function AddCache(const AType: TLoggerType; const AMessageString: string; const AMessageJSON: string; const ATag: string): TDataLogger; overload;
function AddCache(const AType: TLoggerType; const AMessage: string; const ATag: string): TDataLogger; overload;
function AddCache(const AType: TLoggerType; const AMessage: TJsonObject; const ATag: string): TDataLogger; overload;
function ExtractCache: TArray;
+ procedure SaveForce;
procedure CloseProvider;
- procedure CheckProviders;
function GetProviders: TArray;
procedure Lock;
procedure UnLock;
@@ -47,6 +50,7 @@ TDataLogger = class sealed(TThread)
procedure Execute; override;
public
function AddProvider(const AProvider: TDataLoggerProvider): TDataLogger;
+ function RemoveProvider(const AProvider: TDataLoggerProvider): TDataLogger;
function SetProvider(const AProviders: TArray): TDataLogger;
function Trace(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
@@ -99,8 +103,6 @@ TDataLogger = class sealed(TThread)
function Logger: TDataLogger;
-function TLogger: TDataLogger; deprecated 'Use Logger - This function will be removed in future versions';
-
implementation
var
@@ -161,14 +163,25 @@ procedure TDataLogger.BeforeDestruction;
CloseProvider;
- FListProviders.Free;
- FListLoggerItem.Free;
- FEvent.Free;
+ Lock;
+ try
+ FListProviders.Free;
+ FListLoggerItem.Free;
+ FEvent.Free;
+ finally
+ UnLock;
+ end;
+
FCriticalSection.Free;
inherited;
end;
+procedure TDataLogger.Start;
+begin
+ inherited Start;
+end;
+
procedure TDataLogger.Execute;
var
LCache: TArray;
@@ -179,13 +192,16 @@ procedure TDataLogger.Execute;
FEvent.WaitFor(INFINITE);
FEvent.ResetEvent;
+ LProviders := GetProviders;
+
+ if Length(LProviders) = 0 then
+ Continue;
+
LCache := ExtractCache;
if Length(LCache) = 0 then
Continue;
- LProviders := GetProviders;
-
- TParallel.for(Low(LProviders), High(LProviders),
+ TParallel.For(Low(LProviders), High(LProviders),
procedure(Index: Integer)
begin
LProviders[Index].AddCache(LCache);
@@ -205,6 +221,18 @@ function TDataLogger.AddProvider(const AProvider: TDataLoggerProvider): TDataLog
end;
end;
+function TDataLogger.RemoveProvider(const AProvider: TDataLoggerProvider): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FListProviders.Remove(AProvider);
+ finally
+ UnLock;
+ end;
+end;
+
function TDataLogger.SetProvider(const AProviders: TArray): TDataLogger;
var
LItem: TDataLoggerProvider;
@@ -349,11 +377,9 @@ function TDataLogger.SetLogFormat(const ALogFormat: string): TDataLogger;
begin
Result := Self;
- CheckProviders;
-
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
+ TParallel.For(Low(LProviders), High(LProviders),
procedure(Index: Integer)
begin
LProviders[Index].SetLogFormat(ALogFormat);
@@ -366,11 +392,9 @@ function TDataLogger.SetFormatTimestamp(const AFormatTimestamp: string): TDataLo
begin
Result := Self;
- CheckProviders;
-
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
+ TParallel.For(Low(LProviders), High(LProviders),
procedure(Index: Integer)
begin
LProviders[Index].SetFormatTimestamp(AFormatTimestamp);
@@ -380,19 +404,37 @@ function TDataLogger.SetFormatTimestamp(const AFormatTimestamp: string): TDataLo
function TDataLogger.SetLogLevel(const ALogLevel: TLoggerType): TDataLogger;
begin
Result := Self;
- FLogLevel := ALogLevel;
+
+ Lock;
+ try
+ FLogLevel := ALogLevel;
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.SetDisableLogType(const ALogType: TLoggerTypes): TDataLogger;
begin
Result := Self;
- FDisableLogType := ALogType;
+
+ Lock;
+ try
+ FDisableLogType := ALogType;
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.SetOnlyLogType(const ALogType: TLoggerTypes): TDataLogger;
begin
Result := Self;
- FOnlyLogType := ALogType;
+
+ Lock;
+ try
+ FOnlyLogType := ALogType;
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.SetLogException(const AException: TOnLogException): TDataLogger;
@@ -401,11 +443,9 @@ function TDataLogger.SetLogException(const AException: TOnLogException): TDataLo
begin
Result := Self;
- CheckProviders;
-
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
+ TParallel.For(Low(LProviders), High(LProviders),
procedure(Index: Integer)
begin
LProviders[Index].SetLogException(AException);
@@ -418,11 +458,9 @@ function TDataLogger.SetMaxRetry(const AMaxRetry: Integer): TDataLogger;
begin
Result := Self;
- CheckProviders;
-
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
+ TParallel.For(Low(LProviders), High(LProviders),
procedure(Index: Integer)
begin
LProviders[Index].SetMaxRetry(AMaxRetry);
@@ -432,7 +470,13 @@ function TDataLogger.SetMaxRetry(const AMaxRetry: Integer): TDataLogger;
function TDataLogger.SetName(const AName: string): TDataLogger;
begin
Result := Self;
- FName := AName;
+
+ Lock;
+ try
+ FName := AName;
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.StartTransaction: TDataLogger;
@@ -441,15 +485,20 @@ function TDataLogger.StartTransaction: TDataLogger;
begin
Result := Self;
- CheckProviders;
+ SaveForce;
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
- procedure(Index: Integer)
- begin
- LProviders[Index].StartTransaction;
- end);
+ Lock;
+ try
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].StartTransaction;
+ end);
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.CommitTransaction: TDataLogger;
@@ -458,15 +507,20 @@ function TDataLogger.CommitTransaction: TDataLogger;
begin
Result := Self;
- CheckProviders;
+ SaveForce;
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
- procedure(Index: Integer)
- begin
- LProviders[Index].CommitTransaction;
- end);
+ Lock;
+ try
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].CommitTransaction;
+ end);
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.RollbackTransaction: TDataLogger;
@@ -475,15 +529,20 @@ function TDataLogger.RollbackTransaction: TDataLogger;
begin
Result := Self;
- CheckProviders;
+ SaveForce;
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
- procedure(Index: Integer)
- begin
- LProviders[Index].RollbackTransaction;
- end);
+ Lock;
+ try
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].RollbackTransaction;
+ end);
+ finally
+ UnLock;
+ end;
end;
function TDataLogger.InTransaction: Boolean;
@@ -493,16 +552,19 @@ function TDataLogger.InTransaction: Boolean;
begin
Result := False;
- CheckProviders;
-
LProviders := GetProviders;
- for LProvider in LProviders do
- begin
- Result := LProvider.InTransaction;
+ Lock;
+ try
+ for LProvider in LProviders do
+ begin
+ Result := LProvider.InTransaction;
- if Result then
- Break;
+ if Result then
+ Break;
+ end;
+ finally
+ UnLock;
end;
end;
@@ -512,8 +574,6 @@ function TDataLogger.Clear: TDataLogger;
begin
Result := Self;
- CheckProviders;
-
Lock;
try
FListLoggerItem.Clear;
@@ -524,7 +584,7 @@ function TDataLogger.Clear: TDataLogger;
LProviders := GetProviders;
- TParallel.for(Low(LProviders), High(LProviders),
+ TParallel.For(Low(LProviders), High(LProviders),
procedure(Index: Integer)
begin
LProviders[Index].Clear;
@@ -542,22 +602,11 @@ function TDataLogger.CountLogInCache: Int64;
end;
function TDataLogger.AddCache(const AType: TLoggerType; const AMessageString: string; const AMessageJSON: string; const ATag: string): TDataLogger;
-
- procedure DefineSequence;
- begin
- if FSequence = 18446744073709551615 then
- FSequence := 0;
-
- Inc(FSequence);
- end;
-
var
LLogItem: TLoggerItem;
begin
Result := Self;
- CheckProviders;
-
Lock;
try
if (TLoggerType.All in FDisableLogType) or (AType in FDisableLogType) then
@@ -571,7 +620,11 @@ function TDataLogger.AddCache(const AType: TLoggerType; const AMessageString: st
Exit;
if not(AType = TLoggerType.All) then
- DefineSequence;
+ begin
+ if FSequence = 18446744073709551615 then
+ FSequence := 0;
+ Inc(FSequence);
+ end;
LLogItem := default (TLoggerItem);
LLogItem.Name := FName;
@@ -628,40 +681,49 @@ function TDataLogger.ExtractCache: TArray;
Result := LCache;
end;
-procedure TDataLogger.CloseProvider;
+procedure TDataLogger.SaveForce;
var
- LProviders: TArray;
+ LCount: Integer;
begin
- CheckProviders;
-
- LProviders := GetProviders;
+ Lock;
+ try
+ FEvent.SetEvent;
+ LCount := FListLoggerItem.Count;
+ finally
+ UnLock;
+ end;
- TParallel.for(Low(LProviders), High(LProviders),
- procedure(Index: Integer)
- begin
- LProviders[Index].NotifyEvent;
- end);
+ while LCount > 0 do
+ begin
+ Sleep(1);
+ LCount := CountLogInCache;
+ end;
end;
-procedure TDataLogger.CheckProviders;
+procedure TDataLogger.CloseProvider;
var
- LCount: Integer;
+ LProviders: TArray;
begin
+ LProviders := GetProviders;
+
Lock;
try
- LCount := FListProviders.Count;
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].NotifyEvent;
+ end);
finally
UnLock;
end;
-
- if LCount = 0 then
- raise EDataLoggerException.Create('Provider not defined');
end;
function TDataLogger.GetProviders: TArray;
var
LProviders: TArray;
begin
+ Result := [];
+
Lock;
try
LProviders := FListProviders.ToArray;
diff --git a/src/Core/v2/DataLogger.Provider.pas b/src/Core/v2/DataLogger.Provider.pas
new file mode 100644
index 0000000..70753db
--- /dev/null
+++ b/src/Core/v2/DataLogger.Provider.pas
@@ -0,0 +1,436 @@
+{
+ *************************************
+ Created by Danilo Lucas
+ Github - https://github.com/dliocode
+ *************************************
+}
+
+unit DataLogger.Provider;
+
+interface
+
+uses
+ DataLogger.Types,
+ System.SysUtils, System.Classes, System.SyncObjs, System.Generics.Collections;
+
+type
+ TDataLoggerProvider = class(TThread)
+ private
+ FCriticalSection: TCriticalSection;
+ FEvent: TEvent;
+ FListLoggerItem: TList;
+ FListTransaction: TDictionary;
+ FLogFormat: string;
+ FFormatTimestamp: string;
+ FLogLevel: TLoggerType;
+ FDisableLogType: TLoggerTypes;
+ FOnlyLogType: TLoggerTypes;
+ FLogException: TOnLogException;
+ FMaxRetry: Integer;
+ FUseTransaction: Boolean;
+ FAutoCommit: TLoggerTypes;
+ FInTransaction: Boolean;
+ FInitialMessage: string;
+ FFinalMessage: string;
+
+ function ExtractCache: TArray;
+ protected
+ procedure Execute; override;
+ procedure Save(const ACache: TArray); virtual; abstract;
+
+ function ValidationBeforeSave(const ALogItem: TLoggerItem): Boolean;
+ function GetLogFormat: string;
+ function GetFormatTimestamp: string;
+ function GetLogLevel: TLoggerType;
+ function GetDisableLevel: TLoggerTypes;
+ function GetOnlyLogType: TLoggerTypes;
+ function GetLogException: TOnLogException;
+ function GetMaxRetry: Integer;
+ procedure Lock;
+ procedure UnLock;
+
+ property LogException: TOnLogException read GetLogException;
+ public
+ function SetLogFormat(const ALogFormat: string): TDataLoggerProvider;
+ function SetFormatTimestamp(const AFormatTimestamp: string): TDataLoggerProvider;
+ function SetLogLevel(const ALogLevel: TLoggerType): TDataLoggerProvider;
+ function SetDisableLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+ function SetOnlyLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+ function SetLogException(const AException: TOnLogException): TDataLoggerProvider;
+ function SetMaxRetry(const AMaxRetry: Integer): TDataLoggerProvider;
+ function SetInitialMessage(const AMessage: string): TDataLoggerProvider;
+ function SetFinalMessage(const AMessage: string): TDataLoggerProvider;
+
+ function UseTransaction(const AUseTransaction: Boolean): TDataLoggerProvider;
+ function AutoCommit(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+ function StartTransaction: TDataLoggerProvider;
+ function CommitTransaction: TDataLoggerProvider;
+ function RollbackTransaction: TDataLoggerProvider;
+ function InTransaction: Boolean;
+
+ function Clear: TDataLoggerProvider;
+ function CountLogInCache: Int64;
+
+ function AddCache(const AValues: TArray): TDataLoggerProvider; overload;
+ function AddCache(const AValue: TLoggerItem): TDataLoggerProvider; overload;
+ function NotifyEvent: TDataLoggerProvider;
+
+ constructor Create;
+ procedure AfterConstruction; override; final;
+ procedure BeforeDestruction; override; final;
+ end;
+
+implementation
+
+{ TDataLoggerProvider }
+
+constructor TDataLoggerProvider.Create;
+begin
+ inherited Create(True);
+ FreeOnTerminate := False;
+end;
+
+procedure TDataLoggerProvider.AfterConstruction;
+begin
+ inherited;
+
+ FCriticalSection := TCriticalSection.Create;
+ FEvent := TEvent.Create;
+ FListLoggerItem := TList.Create;
+ FListTransaction := TDictionary.Create;
+
+ SetLogFormat(TLoggerFormat.DEFAULT_LOG_FORMAT);
+ SetFormatTimestamp('yyyy-mm-dd hh:nn:ss:zzz');
+ SetLogLevel(TLoggerType.All);
+ SetDisableLogType([]);
+ SetOnlyLogType([TLoggerType.All]);
+ SetLogException(nil);
+ SetMaxRetry(5);
+ UseTransaction(False);
+ AutoCommit([]);
+
+ Start;
+end;
+
+procedure TDataLoggerProvider.BeforeDestruction;
+begin
+ Terminate;
+ FEvent.SetEvent;
+ WaitFor;
+
+ FListTransaction.Free;
+ FListLoggerItem.Free;
+ FEvent.Free;
+ FCriticalSection.Free;
+
+ inherited;
+end;
+
+procedure TDataLoggerProvider.Execute;
+var
+ LCache: TArray;
+begin
+ while not Terminated do
+ begin
+ FEvent.WaitFor(INFINITE);
+ FEvent.ResetEvent;
+
+ LCache := ExtractCache;
+ if Length(LCache) = 0 then
+ Continue;
+
+ Save(LCache);
+ end;
+end;
+
+function TDataLoggerProvider.SetLogFormat(const ALogFormat: string): TDataLoggerProvider;
+begin
+ Result := Self;
+ FLogFormat := ALogFormat;
+end;
+
+function TDataLoggerProvider.SetFormatTimestamp(const AFormatTimestamp: string): TDataLoggerProvider;
+begin
+ Result := Self;
+ FFormatTimestamp := AFormatTimestamp;
+end;
+
+function TDataLoggerProvider.SetLogLevel(const ALogLevel: TLoggerType): TDataLoggerProvider;
+begin
+ Result := Self;
+ FLogLevel := ALogLevel;
+end;
+
+function TDataLoggerProvider.SetDisableLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+begin
+ Result := Self;
+ FDisableLogType := ALogTypes;
+end;
+
+function TDataLoggerProvider.SetOnlyLogType(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+begin
+ Result := Self;
+ FOnlyLogType := ALogTypes;
+end;
+
+function TDataLoggerProvider.SetLogException(const AException: TOnLogException): TDataLoggerProvider;
+begin
+ Result := Self;
+ FLogException := AException;
+end;
+
+function TDataLoggerProvider.SetMaxRetry(const AMaxRetry: Integer): TDataLoggerProvider;
+begin
+ Result := Self;
+ FMaxRetry := AMaxRetry;
+end;
+
+function TDataLoggerProvider.SetInitialMessage(const AMessage: string): TDataLoggerProvider;
+begin
+ Result := Self;
+ FInitialMessage := AMessage;
+end;
+
+function TDataLoggerProvider.SetFinalMessage(const AMessage: string): TDataLoggerProvider;
+begin
+ Result := Self;
+ FFinalMessage := AMessage;
+end;
+
+function TDataLoggerProvider.Clear: TDataLoggerProvider;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FListLoggerItem.Clear;
+ FListLoggerItem.TrimExcess;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.UseTransaction(const AUseTransaction: Boolean): TDataLoggerProvider;
+begin
+ Result := Self;
+ FUseTransaction := AUseTransaction;
+end;
+
+function TDataLoggerProvider.AutoCommit(const ALogTypes: TLoggerTypes): TDataLoggerProvider;
+begin
+ Result := Self;
+ FAutoCommit := ALogTypes;
+end;
+
+function TDataLoggerProvider.StartTransaction: TDataLoggerProvider;
+begin
+ Result := Self;
+
+ if not FUseTransaction then
+ Exit;
+
+ Lock;
+ try
+ if FInTransaction then
+ Exit;
+
+ FEvent.SetEvent;
+ FInTransaction := True;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.CommitTransaction: TDataLoggerProvider;
+begin
+ Result := Self;
+
+ if not FUseTransaction then
+ Exit;
+
+ Lock;
+ try
+ if not FInTransaction then
+ Exit;
+
+ FInTransaction := False;
+ FEvent.SetEvent;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.RollbackTransaction: TDataLoggerProvider;
+begin
+ Result := Self;
+
+ if not FUseTransaction then
+ Exit;
+
+ Lock;
+ try
+ FListLoggerItem.Clear;
+ FListLoggerItem.TrimExcess;
+
+ FInTransaction := False;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.InTransaction: Boolean;
+begin
+ Lock;
+ try
+ Result := FInTransaction;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.CountLogInCache: Int64;
+begin
+ Lock;
+ try
+ Result := FListLoggerItem.Count;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.NotifyEvent: TDataLoggerProvider;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FEvent.SetEvent;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.ValidationBeforeSave(const ALogItem: TLoggerItem): Boolean;
+begin
+ Result := False;
+
+ if (TLoggerType.All in GetDisableLevel) or (ALogItem.&Type in GetDisableLevel) then
+ Exit;
+
+ if not(TLoggerType.All in GetOnlyLogType) and not(ALogItem.&Type in GetOnlyLogType) then
+ Exit;
+
+ if not(ALogItem.&Type in GetOnlyLogType) then
+ if Ord(GetLogLevel) > Ord(ALogItem.&Type) then
+ Exit;
+
+ Result := True;
+end;
+
+function TDataLoggerProvider.GetLogFormat: string;
+begin
+ Result := FLogFormat;
+end;
+
+function TDataLoggerProvider.GetFormatTimestamp: string;
+begin
+ Result := FFormatTimestamp;
+end;
+
+function TDataLoggerProvider.GetLogLevel: TLoggerType;
+begin
+ Result := FLogLevel;
+end;
+
+function TDataLoggerProvider.GetDisableLevel: TLoggerTypes;
+begin
+ Result := FDisableLogType;
+end;
+
+function TDataLoggerProvider.GetOnlyLogType: TLoggerTypes;
+begin
+ Result := FOnlyLogType;
+end;
+
+function TDataLoggerProvider.GetLogException: TOnLogException;
+begin
+ Result := FLogException;
+end;
+
+function TDataLoggerProvider.GetMaxRetry: Integer;
+begin
+ Result := FMaxRetry;
+end;
+
+procedure TDataLoggerProvider.Lock;
+begin
+ FCriticalSection.Acquire;
+end;
+
+procedure TDataLoggerProvider.UnLock;
+begin
+ FCriticalSection.Release;
+end;
+
+function TDataLoggerProvider.AddCache(const AValues: TArray): TDataLoggerProvider;
+var
+ I: Integer;
+ LItem: TLoggerItem;
+ LMessage: string;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ try
+ for I := Low(AValues) to High(AValues) do
+ begin
+ LItem := AValues[I];
+
+ LMessage := LItem.Message;
+
+ if not FInitialMessage.Trim.IsEmpty then
+ LMessage := FInitialMessage + LMessage;
+
+ if not FFinalMessage.Trim.IsEmpty then
+ LMessage := LMessage + FFinalMessage;
+
+ LItem.Message := LMessage;
+
+ FListLoggerItem.Add(LItem);
+
+ if FUseTransaction and FInTransaction then
+ if LItem.&Type in FAutoCommit then
+ FEvent.SetEvent;
+ end;
+ finally
+ if not FUseTransaction then
+ FEvent.SetEvent
+ else
+ if not FInTransaction then
+ FEvent.SetEvent;
+ end;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLoggerProvider.AddCache(const AValue: TLoggerItem): TDataLoggerProvider;
+begin
+ Result := AddCache([AValue]);
+end;
+
+function TDataLoggerProvider.ExtractCache: TArray;
+begin
+ Lock;
+ try
+ Result := FListLoggerItem.ToArray;
+
+ FListLoggerItem.Clear;
+ FListLoggerItem.TrimExcess;
+ finally
+ UnLock;
+ end;
+end;
+
+end.
diff --git a/src/Core/v2/DataLogger.Types.pas b/src/Core/v2/DataLogger.Types.pas
new file mode 100644
index 0000000..14c2b30
--- /dev/null
+++ b/src/Core/v2/DataLogger.Types.pas
@@ -0,0 +1,249 @@
+{
+ *************************************
+ Created by Danilo Lucas
+ Github - https://github.com/dliocode
+ *************************************
+}
+
+unit DataLogger.Types;
+
+interface
+
+uses
+ DataLogger.Utils,
+ System.TypInfo, System.JSON, System.DateUtils, System.SysUtils, System.Generics.Collections, System.Classes;
+
+type
+ EDataLoggerException = class(Exception)
+ end;
+
+ TLoggerType = (All, Trace, Debug, Info, Success, Warn, Error, Fatal);
+ TLoggerTypes = set of TLoggerType;
+
+ TLoggerTypeHelper = record helper for TLoggerType
+ public
+ function ToString: string;
+ end;
+
+ TLoggerItem = record
+ Name: string;
+ Sequence: Int64;
+ TimeStamp: TDateTime;
+ ThreadID: Integer;
+ &Type: TLoggerType;
+ Tag: string;
+ Message: string;
+ MessageJSON: string;
+
+ AppName: string;
+ AppPath: string;
+ AppVersion: TLoggerUtils.TAppVersion;
+ AppSize: Double;
+
+ ComputerName: string;
+ Username: string;
+ OSVersion: string;
+ ProcessId: string;
+ IPLocal: string;
+ end;
+
+ TLoggerLogFormat = class
+ class function AsJsonObject(const ALogFormat: string; const AItem: TLoggerItem): TJSONObject;
+ class function AsJsonObjectToString(const ALogFormat: string; const AItem: TLoggerItem): string;
+ class function AsString(const ALogFormat: string; const AItem: TLoggerItem; const AFormatTimestamp: string): string;
+ class function AsStream(const ALogFormat: string; const AItem: TLoggerItem; const AFormatTimestamp: string): TStream;
+ class function AsStreamJsonObject(const ALogFormat: string; const AItem: TLoggerItem): TStream;
+ end;
+
+ TOnLogException = reference to procedure(const Sender: TObject; const LogItem: TLoggerItem; const E: Exception; var RetryCount: Integer);
+
+ TLoggerFormat = record
+ const
+ LOG_NAME = '${name}';
+ LOG_SEQUENCE = '${sequence}';
+ LOG_TIMESTAMP = '${timestamp}';
+ LOG_THREADID = '${thread_id}';
+ LOG_PROCESSID = '${process_id}';
+ LOG_TYPE = '${type}';
+ LOG_TAG = '${tag}';
+ LOG_MESSAGE = '${message}';
+
+ LOG_APPNAME = '${app_name}';
+ LOG_APPPATH = '${app_path}';
+ LOG_APPVERSION = '${app_version}';
+ LOG_APPSIZE = '${app_size}';
+
+ LOG_COMPUTERNAME = '${computer_name}';
+ LOG_USERNAME = '${username}';
+ LOG_OSVERSION = '${os_version}';
+ LOG_IP_LOCAL = '${ip_local}';
+
+ DEFAULT_LOG_FORMAT = LOG_TIMESTAMP + ' [TID ' + LOG_THREADID + '] [PID ' + LOG_PROCESSID + '] [SEQ ' + LOG_SEQUENCE + '] [' + LOG_TYPE + '] [' + LOG_TAG + '] ' + LOG_MESSAGE;
+ end;
+
+implementation
+
+{ TLoggerTypeHelper }
+
+function TLoggerTypeHelper.ToString: string;
+begin
+ Result := GetEnumName(TypeInfo(TLoggerType), Integer(Self));
+end;
+
+{ TLoggerLogFormat }
+
+class function TLoggerLogFormat.AsJsonObject(const ALogFormat: string; const AItem: TLoggerItem): TJSONObject;
+ procedure _Add(const ALogKey: string; const AJSONKey: string; const AJSONValue: TJSONValue);
+ begin
+ if ALogFormat.Contains(ALogKey) then
+ Result.AddPair(AJSONKey, AJSONValue)
+ else
+ AJSONValue.Free;
+ end;
+
+var
+ I: Integer;
+ LJO: TJSONObject;
+ LKey: string;
+ LValue: TJSONValue;
+begin
+ Result := TJSONObject.Create;
+
+ Result.AddPair('timestamp', TJSONString.Create(DateToISO8601(AItem.TimeStamp, False)));
+
+ _Add(TLoggerFormat.LOG_NAME, 'log_name', TJSONString.Create(AItem.Name));
+ _Add(TLoggerFormat.LOG_SEQUENCE, 'log_sequence', TJSONNumber.Create(AItem.Sequence));
+ _Add(TLoggerFormat.LOG_TIMESTAMP, 'log_datetime', TJSONString.Create(DateToISO8601(AItem.TimeStamp, False)));
+ _Add(TLoggerFormat.LOG_THREADID, 'log_thread_id', TJSONNumber.Create(AItem.ThreadID));
+ _Add(TLoggerFormat.LOG_TYPE, 'log_type', TJSONString.Create(AItem.&Type.ToString));
+ _Add(TLoggerFormat.LOG_TAG, 'log_tag', TJSONString.Create(AItem.Tag));
+
+ if not AItem.MessageJSON.Trim.IsEmpty then
+ begin
+ _Add(TLoggerFormat.LOG_MESSAGE, 'log_message', TJSONString.Create(AItem.MessageJSON.Trim));
+
+ try
+ LJO := TJSONObject.ParseJSONValue(AItem.MessageJSON.Trim) as TJSONObject;
+
+ if Assigned(LJO) then
+ try
+ for I := 0 to Pred(LJO.Count) do
+ begin
+ LKey := Format('${%s}', [LJO.Pairs[I].JsonString.Value]);
+
+ if ALogFormat.Contains(LKey) then
+ begin
+ LValue := LJO.Pairs[I].JsonValue.Clone as TJSONValue;
+ Result.AddPair(LJO.Pairs[I].JsonString.Value, LValue);
+ end;
+ end;
+ finally
+ LJO.Free;
+ end;
+ except
+ end;
+ end
+ else
+ _Add(TLoggerFormat.LOG_MESSAGE, 'log_message', TJSONString.Create(AItem.Message.Trim));
+
+ _Add(TLoggerFormat.LOG_APPNAME, 'log_app_name', TJSONString.Create(AItem.AppName));
+ _Add(TLoggerFormat.LOG_APPVERSION, 'log_app_version', TJSONString.Create(AItem.AppVersion.FileVersion));
+ _Add(TLoggerFormat.LOG_APPPATH, 'log_app_path', TJSONString.Create(AItem.AppPath));
+ _Add(TLoggerFormat.LOG_APPSIZE, 'log_app_size', TJSONString.Create(FormatFloat('#,##0.00 MB', AItem.AppSize / 1024)));
+
+ _Add(TLoggerFormat.LOG_COMPUTERNAME, 'log_computer_name', TJSONString.Create(AItem.ComputerName));
+ _Add(TLoggerFormat.LOG_USERNAME, 'log_username', TJSONString.Create(AItem.Username));
+ _Add(TLoggerFormat.LOG_OSVERSION, 'log_os_version', TJSONString.Create(AItem.OSVersion));
+ _Add(TLoggerFormat.LOG_PROCESSID, 'log_process_id', TJSONString.Create(AItem.ProcessId));
+
+ _Add(TLoggerFormat.LOG_IP_LOCAL, 'log_ip_local', TJSONString.Create(AItem.IPLocal));
+end;
+
+class function TLoggerLogFormat.AsJsonObjectToString(const ALogFormat: string; const AItem: TLoggerItem): string;
+var
+ LJO: TJSONObject;
+begin
+ LJO := AsJsonObject(ALogFormat, AItem);
+ try
+ Result := LJO.ToString;
+ finally
+ LJO.Free;
+ end;
+end;
+
+class function TLoggerLogFormat.AsString(const ALogFormat: string; const AItem: TLoggerItem; const AFormatTimestamp: string): string;
+var
+ LLog: string;
+ LJO: TJSONObject;
+ I: Integer;
+
+ function _Add(const AKey: string; const AValue: string): string;
+ begin
+ Result := LLog.Replace(AKey, AValue);
+ end;
+
+begin
+ LLog := ALogFormat;
+
+ LLog := _Add(TLoggerFormat.LOG_NAME, AItem.Name);
+ LLog := _Add(TLoggerFormat.LOG_SEQUENCE, AItem.Sequence.ToString);
+ LLog := _Add(TLoggerFormat.LOG_TIMESTAMP, FormatDateTime(AFormatTimestamp, AItem.TimeStamp));
+ LLog := _Add(TLoggerFormat.LOG_THREADID, AItem.ThreadID.ToString);
+ LLog := _Add(TLoggerFormat.LOG_TYPE, AItem.&Type.ToString);
+ LLog := _Add(TLoggerFormat.LOG_TAG, AItem.Tag.Trim);
+
+ if not AItem.MessageJSON.Trim.IsEmpty then
+ begin
+ LLog := _Add(TLoggerFormat.LOG_MESSAGE, AItem.MessageJSON.Trim);
+
+ try
+ LJO := TJSONObject.ParseJSONValue(AItem.MessageJSON.Trim) as TJSONObject;
+
+ if Assigned(LJO) then
+ try
+ for I := 0 to Pred(LJO.Count) do
+ LLog := _Add(Format('${%s}', [LJO.Pairs[I].JsonString.Value]), LJO.Pairs[I].JsonValue.Value);
+ finally
+ LJO.Free;
+ end;
+ except
+ end;
+ end
+ else
+ LLog := _Add(TLoggerFormat.LOG_MESSAGE, AItem.Message.Trim);
+
+ LLog := _Add(TLoggerFormat.LOG_APPNAME, AItem.AppName);
+ LLog := _Add(TLoggerFormat.LOG_APPPATH, AItem.AppPath);
+ LLog := _Add(TLoggerFormat.LOG_APPVERSION, AItem.AppVersion.FileVersion);
+ LLog := _Add(TLoggerFormat.LOG_APPSIZE, FormatFloat('#,##0.00 MB', AItem.AppSize / 1024));
+
+ LLog := _Add(TLoggerFormat.LOG_COMPUTERNAME, AItem.ComputerName);
+ LLog := _Add(TLoggerFormat.LOG_USERNAME, AItem.Username);
+ LLog := _Add(TLoggerFormat.LOG_OSVERSION, AItem.OSVersion);
+ LLog := _Add(TLoggerFormat.LOG_PROCESSID, AItem.ProcessId);
+ LLog := _Add(TLoggerFormat.LOG_IP_LOCAL, AItem.IPLocal);
+
+ Result := LLog;
+end;
+
+class function TLoggerLogFormat.AsStream(const ALogFormat: string; const AItem: TLoggerItem; const AFormatTimestamp: string): TStream;
+var
+ LLog: string;
+begin
+ LLog := AsString(ALogFormat, AItem, AFormatTimestamp);
+
+ Result := TStringStream.Create(LLog, TEncoding.UTF8);
+ Result.Seek(0, soFromBeginning);
+end;
+
+class function TLoggerLogFormat.AsStreamJsonObject(const ALogFormat: string; const AItem: TLoggerItem): TStream;
+var
+ LLog: string;
+begin
+ LLog := AsJsonObjectToString(ALogFormat, AItem);
+
+ Result := TStringStream.Create(LLog, TEncoding.UTF8);
+ Result.Seek(0, soFromBeginning);
+end;
+
+end.
diff --git a/src/Core/v2/DataLogger.Utils.pas b/src/Core/v2/DataLogger.Utils.pas
new file mode 100644
index 0000000..137d34c
--- /dev/null
+++ b/src/Core/v2/DataLogger.Utils.pas
@@ -0,0 +1,323 @@
+{
+ *************************************
+ Created by Danilo Lucas
+ Github - https://github.com/dliocode
+ *************************************
+}
+unit DataLogger.Utils;
+
+interface
+
+uses
+{$IF DEFINED(MSWINDOWS)}
+ Winapi.Windows,
+{$ELSEIF DEFINED(LINUX)}
+ Posix.SysUtsname, Posix.Unistd,
+{$ELSEIF DEFINED(MACOS)}
+ Macapi.Helpers, Macapi.CoreFoundation, Macapi.ObjectiveC, Macapi.ObjCRuntime,
+{$ELSEIF DEFINED(IOS)}
+ IOSApi.Foundation, IOSApi.Helpers,
+{$ELSEIF DEFINED(ANDROID)}
+ Androidapi.Helpers, Androidapi.JNI.OS, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.JavaTypes, Androidapi.JNI.App, Androidapi.JNI.Provider,
+{$ENDIF}
+ IdStack,
+ System.IOUtils, System.SysUtils, System.Types;
+
+type
+ TLoggerUtils = class
+ type
+ TAppVersion = record
+ Comments: string;
+ CompanyName: string;
+ FileDescription: string;
+ FileVersion: string;
+ InternalName: string;
+ LegalCopyright: string;
+ LegalTrademarks: string;
+ OriginalFilename: string;
+ ProductName: string;
+ ProductVersion: string;
+ end;
+ public
+ class function AppName: string;
+ class function AppPath: string;
+ class function AppVersion: TAppVersion;
+ class function AppSize: Double;
+ class function ComputerName: string;
+ class function Username: string;
+ class function OS: string;
+ class function ProcessId: Integer;
+ class function IPLocal: string;
+ end;
+
+implementation
+
+{ TLoggerUtils }
+class function TLoggerUtils.AppName: string;
+{$IF DEFINED(ANDROID)}
+var
+ LPackageManager: JPackageManager;
+ LPackageName: JString;
+begin
+ LPackageManager := TAndroidHelper.Activity.getPackageManager;
+ LPackageName := TAndroidHelper.Context.getPackageName;
+ Result := JStringToString(LPackageManager.getPackageInfo(LPackageName, 0).applicationInfo.loadLabel(LPackageManager).toString);
+end;
+{$ELSEIF DEFINED(IOS)}
+
+begin
+ Result := TNSString.Wrap(CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle, KCFBundleIdentifierKey)).UTF8String;
+end;
+{$ELSE}
+
+var
+ LAppPathFull: string;
+begin
+ if IsLibrary then
+ LAppPathFull := GetModuleName(0)
+ else
+ LAppPathFull := ParamStr(0);
+ Result := TPath.GetFileNameWithoutExtension(LAppPathFull);
+end;
+{$ENDIF}
+
+
+class function TLoggerUtils.AppPath: string;
+{$IF DEFINED(ANDROID) OR DEFINED(IOS)}
+begin
+ Result := TPath.GetDocumentsPath;
+end;
+{$ELSE}
+
+var
+ LAppPathFull: string;
+begin
+ if IsLibrary then
+ LAppPathFull := GetModuleName(0)
+ else
+ LAppPathFull := ParamStr(0);
+
+ Result := TPath.GetDirectoryName(LAppPathFull);
+end;
+{$ENDIF}
+
+
+class function TLoggerUtils.AppVersion: TAppVersion;
+{$IF DEFINED(ANDROID)}
+var
+ LPackageInfo: JPackageInfo;
+begin
+ LPackageInfo := TAndroidHelper.Activity.getPackageManager.getPackageInfo(TAndroidHelper.Context.getPackageName(), TJPackageManager.JavaClass.GET_ACTIVITIES);
+ Result.FileVersion := IntToStr(LPackageInfo.VersionCode);
+ Result.FileDescription := JStringToString(LPackageInfo.versionName);
+end;
+{$ELSEIF DEFINED(IOS)}
+
+var
+ AppKey: Pointer;
+ AppBundle: NSBundle;
+ BuildStr: NSString;
+begin
+ try
+ AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
+ AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
+ BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
+
+ Result.FileVersion := UTF8ToString(BuildStr.UTF8String);
+ except
+ Result.FileVersion := TNSString.Wrap(CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle, kCFBundleVersionKey)).UTF8String;
+ end;
+end;
+{$ELSEIF DEFINED(MSWINDOWS)}
+
+var
+ LAppPathFull: string;
+ LInfoSize: DWORD;
+ LDummy: DWORD;
+ LInfo: array of Char;
+ LBuffer: PChar;
+ LKey: string;
+ LP: Pointer;
+ LLen: cardinal;
+begin
+ Result := Default (TAppVersion);
+
+ try
+ if IsLibrary then
+ LAppPathFull := GetModuleName(0)
+ else
+ LAppPathFull := ParamStr(0);
+
+ LInfoSize := GetFileVersionInfoSize(pWideChar(LAppPathFull), LDummy);
+ if LInfoSize = 0 then
+ Exit;
+
+ SetLength(LInfo, LInfoSize);
+ GetFileVersionInfo(pWideChar(LAppPathFull), 0, LInfoSize, LInfo);
+ VerQueryValue(LInfo, '\VarFileInfo\Translation', LP, LLen);
+
+ if Assigned(LP) then
+ begin
+ LKey := Format('\StringFileInfo\%4.4x%4.4x', [LoWord(Longint(LP^)), HiWord(Longint(LP^))]);
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'Comments'])), Pointer(LBuffer), LInfoSize) then
+ Result.Comments := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'CompanyName'])), Pointer(LBuffer), LInfoSize) then
+ Result.CompanyName := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'FileDescription'])), Pointer(LBuffer), LInfoSize) then
+ Result.FileDescription := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'FileVersion'])), Pointer(LBuffer), LInfoSize) then
+ Result.FileVersion := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'InternalName'])), Pointer(LBuffer), LInfoSize) then
+ Result.InternalName := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'LegalCopyright'])), Pointer(LBuffer), LInfoSize) then
+ Result.LegalCopyright := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'OriginalFilename'])), Pointer(LBuffer), LInfoSize) then
+ Result.OriginalFilename := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'ProductName'])), Pointer(LBuffer), LInfoSize) then
+ Result.ProductName := LBuffer;
+
+ if VerQueryValue(LInfo, PChar(Format('%s\%s', [LKey, 'ProductVersion'])), Pointer(LBuffer), LInfoSize) then
+ Result.ProductVersion := LBuffer;
+ end;
+ except
+ end;
+end;
+{$ELSE}
+
+begin
+ Result := default (TAppVersion);
+end;
+{$ENDIF}
+
+
+class function TLoggerUtils.AppSize: Double;
+var
+ LSearchRec: TSearchRec;
+ LAppPathFull: string;
+begin
+ Result := 0;
+
+ try
+ if IsLibrary then
+ LAppPathFull := GetModuleName(0)
+ else
+ LAppPathFull := ParamStr(0);
+
+ Result := 0;
+
+ if FindFirst(LAppPathFull, faAnyFile, LSearchRec) = 0 then
+ Result := LSearchRec.Size / 1024; // Kb
+
+ FindClose(LSearchRec);
+ except
+ end;
+end;
+
+class function TLoggerUtils.ComputerName: string;
+{$IF DEFINED(ANDROID)}
+begin
+ Result := JStringToString(TJBuild.JavaClass.MODEL);
+ if Result.Trim.IsEmpty then
+ Result := Format('%s %s', [JStringToString(TJBuild.JavaClass.MANUFACTURER), JStringToString(TJBuild.JavaClass.PRODUCT)]);
+end;
+{$ELSEIF DEFINED(IOS)}
+
+begin
+ Result := '';
+end;
+{$ELSEIF DEFINED(LINUX)}
+
+var
+ LName: utsname;
+begin
+ uname(LName);
+ Result := string(AnsiString(LName.nodename));
+end;
+{$ELSEIF DEFINED(MSWINDOWS)}
+
+var
+ LBuffer: array [0 .. MAX_COMPUTERNAME_LENGTH + 1] of Char;
+ LSize: cardinal;
+begin
+ LSize := High(LBuffer);
+
+ if GetComputerName(LBuffer, LSize) then
+ Result := string(LBuffer)
+ else
+ Result := EmptyStr;
+end;
+{$ELSE}
+
+begin
+ Result := EmptyStr;
+end;
+{$ENDIF}
+
+
+// {$IFDEF MACOS}
+// function NSUserName: Pointer; cdecl; external '/System/Library/Frameworks/Foundation.framework/Foundation' name '_NSUserName';
+// {$ENDIF}
+//
+class function TLoggerUtils.Username: string;
+{$IF DEFINED(MSWINDOWS)}
+var
+ Buf: array [0 .. 2 * MAX_COMPUTERNAME_LENGTH + 1] of Char;
+ Len: cardinal;
+begin
+ Len := high(Buf);
+ if GetUserName(Buf, Len) then
+ Result := string(Buf)
+ else
+ Result := EmptyStr;
+end;
+// {$IFDEF MACOS}
+// begin
+// Result := TNSString.Wrap(NSUserName).UTF8String;
+// end;
+{$ELSE}
+
+begin
+ Result := '';
+end;
+{$ENDIF}
+
+
+class function TLoggerUtils.OS: string;
+begin
+ Result := TOSVersion.toString;
+end;
+
+class function TLoggerUtils.ProcessId: Integer;
+begin
+{$IF DEFINED(MSWINDOWS)}
+ Result := GetCurrentProcessId;
+{$ELSEIF DEFINED(LINUX)}
+ Result := getpid;
+{$ELSE}
+ Result := 0;
+{$ENDIF}
+end;
+
+class function TLoggerUtils.IPLocal: string;
+begin
+ Result := 'INVALID';
+
+ try
+ TIdStack.IncUsage;
+ try
+ Result := GStack.LocalAddress;
+ finally
+ TIdStack.DecUsage;
+ end;
+ except
+ end;
+end;
+
+end.
diff --git a/src/Core/v2/DataLogger.pas b/src/Core/v2/DataLogger.pas
new file mode 100644
index 0000000..6f40bf4
--- /dev/null
+++ b/src/Core/v2/DataLogger.pas
@@ -0,0 +1,705 @@
+{
+ *************************************
+ Created by Danilo Lucas
+ Github - https://github.com/dliocode
+ *************************************
+}
+
+unit DataLogger;
+
+interface
+
+uses
+ DataLogger.Provider, DataLogger.Types, DataLogger.Utils, System.Classes,
+ System.SyncObjs, System.Generics.Collections, System.SysUtils, System.Threading, System.JSON;
+
+type
+ TLoggerItem = DataLogger.Types.TLoggerItem;
+ TLoggerType = DataLogger.Types.TLoggerType;
+ TLoggerTypes = DataLogger.Types.TLoggerTypes;
+ TOnLogException = DataLogger.Types.TOnLogException;
+ TDataLoggerProvider = DataLogger.Provider.TDataLoggerProvider;
+ TLoggerFormat = DataLogger.Types.TLoggerFormat;
+
+ TDataLogger = class sealed(TThread)
+ strict private
+ FCriticalSection: TCriticalSection;
+ FEvent: TEvent;
+ FListLoggerItem: TList;
+ FListProviders: TObjectList;
+ FLogLevel: TLoggerType;
+ FDisableLogType: TLoggerTypes;
+ FOnlyLogType: TLoggerTypes;
+ FSequence: UInt64;
+ FName: string;
+
+ constructor Create;
+ procedure Start;
+
+ function AddCache(const AType: TLoggerType; const AMessageString: string; const AMessageJSON: string; const ATag: string): TDataLogger; overload;
+ function AddCache(const AType: TLoggerType; const AMessage: string; const ATag: string): TDataLogger; overload;
+ function AddCache(const AType: TLoggerType; const AMessage: TJsonObject; const ATag: string): TDataLogger; overload;
+ function ExtractCache: TArray;
+ procedure CloseProvider;
+ function GetProviders: TArray;
+ procedure Lock;
+ procedure UnLock;
+ protected
+ procedure Execute; override;
+ public
+ function AddProvider(const AProvider: TDataLoggerProvider): TDataLogger;
+ function RemoveProvider(const AProvider: TDataLoggerProvider): TDataLogger;
+ function SetProvider(const AProviders: TArray): TDataLogger;
+
+ function Trace(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Trace(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Trace(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function Debug(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Debug(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Debug(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function Info(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Info(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Info(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function Success(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Success(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Success(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function Warn(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Warn(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Warn(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function Error(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Error(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Error(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function Fatal(const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function Fatal(const AMessage: string; const AArgs: array of const; const ATag: string = ''): TDataLogger; overload;
+ function Fatal(const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function &Type(const AType: TLoggerType; const AMessage: string; const ATag: string = ''): TDataLogger; overload;
+ function &Type(const AType: TLoggerType; const AMessage: TJsonObject; const ATag: string = ''): TDataLogger; overload;
+ function SlineBreak: TDataLogger;
+
+ function SetLogFormat(const ALogFormat: string): TDataLogger;
+ function SetLogLevel(const ALogLevel: TLoggerType): TDataLogger;
+ function SetOnlyLogType(const ALogType: TLoggerTypes): TDataLogger;
+ function SetDisableLogType(const ALogType: TLoggerTypes): TDataLogger;
+ function SetFormatTimestamp(const AFormatTimestamp: string): TDataLogger;
+ function SetLogException(const AException: TOnLogException): TDataLogger;
+ function SetMaxRetry(const AMaxRetry: Integer): TDataLogger;
+ function SetName(const AName: string): TDataLogger;
+
+ function StartTransaction: TDataLogger;
+ function CommitTransaction: TDataLogger;
+ function RollbackTransaction: TDataLogger;
+ function InTransaction: Boolean;
+
+ function Clear: TDataLogger;
+ function CountLogInCache: Int64;
+
+ procedure AfterConstruction; override;
+ procedure BeforeDestruction; override;
+
+ class function Builder: TDataLogger;
+ end;
+
+function Logger: TDataLogger;
+
+implementation
+
+var
+ FLoggerDefault: TDataLogger;
+
+function Logger: TDataLogger;
+begin
+ if not Assigned(FLoggerDefault) then
+ FLoggerDefault := TDataLogger.Builder;
+
+ Result := FLoggerDefault;
+end;
+
+function TLogger: TDataLogger;
+begin
+ Result := Logger;
+end;
+
+{ TDataLogger }
+
+class function TDataLogger.Builder: TDataLogger;
+begin
+ Result := TDataLogger.Create;
+end;
+
+constructor TDataLogger.Create;
+begin
+ inherited Create(True);
+ FreeOnTerminate := False;
+end;
+
+procedure TDataLogger.AfterConstruction;
+begin
+ inherited;
+
+ FCriticalSection := TCriticalSection.Create;
+ FEvent := TEvent.Create;
+ FListLoggerItem := TList.Create;
+ FListProviders := TObjectList.Create(True);
+
+ SetLogLevel(TLoggerType.All);
+ SetDisableLogType([]);
+ SetOnlyLogType([TLoggerType.All]);
+ SetName('');
+
+ FSequence := 0;
+
+ Start;
+end;
+
+procedure TDataLogger.BeforeDestruction;
+begin
+ SetDisableLogType([TLoggerType.All]);
+
+ Terminate;
+ FEvent.SetEvent;
+ WaitFor;
+
+ CloseProvider;
+
+ Lock;
+ try
+ FListProviders.Free;
+ FListLoggerItem.Free;
+ FEvent.Free;
+ finally
+ UnLock;
+ end;
+
+ FCriticalSection.Free;
+
+ inherited;
+end;
+
+procedure TDataLogger.Start;
+begin
+ inherited Start;
+end;
+
+procedure TDataLogger.Execute;
+var
+ LCache: TArray;
+ LProviders: TArray;
+begin
+ while not Terminated do
+ begin
+ FEvent.WaitFor(INFINITE);
+ FEvent.ResetEvent;
+
+ LProviders := GetProviders;
+
+ if Length(LProviders) = 0 then
+ Continue;
+
+ LCache := ExtractCache;
+ if Length(LCache) = 0 then
+ Continue;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].AddCache(LCache);
+ end);
+ end;
+end;
+
+function TDataLogger.AddProvider(const AProvider: TDataLoggerProvider): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FListProviders.Add(AProvider);
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.RemoveProvider(const AProvider: TDataLoggerProvider): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FListProviders.Remove(AProvider);
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.SetProvider(const AProviders: TArray): TDataLogger;
+var
+ LItem: TDataLoggerProvider;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FListProviders.Clear;
+ FListProviders.TrimExcess;
+ finally
+ UnLock;
+ end;
+
+ for LItem in AProviders do
+ AddProvider(LItem);
+end;
+
+function TDataLogger.Trace(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Trace, AMessage, ATag);
+end;
+
+function TDataLogger.Trace(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Trace, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Trace(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Trace, AMessage, ATag);
+end;
+
+function TDataLogger.Debug(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Debug, AMessage, ATag);
+end;
+
+function TDataLogger.Debug(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Debug, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Debug(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Debug, AMessage, ATag);
+end;
+
+function TDataLogger.Info(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Info, AMessage, ATag);
+end;
+
+function TDataLogger.Info(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Info, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Info(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Info, AMessage, ATag);
+end;
+
+function TDataLogger.Success(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Success, AMessage, ATag);
+end;
+
+function TDataLogger.Success(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Success, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Success(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Success, AMessage, ATag);
+end;
+
+function TDataLogger.Warn(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Warn, AMessage, ATag);
+end;
+
+function TDataLogger.Warn(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Warn, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Warn(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Warn, AMessage, ATag);
+end;
+
+function TDataLogger.Error(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Error, AMessage, ATag);
+end;
+
+function TDataLogger.Error(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Error, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Error(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Error, AMessage, ATag);
+end;
+
+function TDataLogger.Fatal(const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Fatal, AMessage, ATag);
+end;
+
+function TDataLogger.Fatal(const AMessage: string; const AArgs: array of const; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Fatal, Format(AMessage, AArgs), ATag);
+end;
+
+function TDataLogger.Fatal(const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(TLoggerType.Fatal, AMessage, ATag);
+end;
+
+function TDataLogger.&Type(const AType: TLoggerType; const AMessage: string; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(AType, AMessage, ATag);
+end;
+
+function TDataLogger.&Type(const AType: TLoggerType; const AMessage: TJsonObject; const ATag: string = ''): TDataLogger;
+begin
+ Result := AddCache(AType, AMessage, ATag);
+end;
+
+function TDataLogger.SlineBreak: TDataLogger;
+begin
+ Result := AddCache(TLoggerType.All, '', '');
+end;
+
+function TDataLogger.SetLogFormat(const ALogFormat: string): TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].SetLogFormat(ALogFormat);
+ end);
+end;
+
+function TDataLogger.SetFormatTimestamp(const AFormatTimestamp: string): TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].SetFormatTimestamp(AFormatTimestamp);
+ end);
+end;
+
+function TDataLogger.SetLogLevel(const ALogLevel: TLoggerType): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FLogLevel := ALogLevel;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.SetDisableLogType(const ALogType: TLoggerTypes): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FDisableLogType := ALogType;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.SetOnlyLogType(const ALogType: TLoggerTypes): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FOnlyLogType := ALogType;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.SetLogException(const AException: TOnLogException): TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].SetLogException(AException);
+ end);
+end;
+
+function TDataLogger.SetMaxRetry(const AMaxRetry: Integer): TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].SetMaxRetry(AMaxRetry);
+ end);
+end;
+
+function TDataLogger.SetName(const AName: string): TDataLogger;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FName := AName;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.StartTransaction: TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].StartTransaction;
+ end);
+end;
+
+function TDataLogger.CommitTransaction: TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].CommitTransaction;
+ end);
+end;
+
+function TDataLogger.RollbackTransaction: TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].RollbackTransaction;
+ end);
+end;
+
+function TDataLogger.InTransaction: Boolean;
+var
+ LProviders: TArray;
+ LProvider: TDataLoggerProvider;
+begin
+ Result := False;
+
+ LProviders := GetProviders;
+
+ for LProvider in LProviders do
+ begin
+ Result := LProvider.InTransaction;
+
+ if Result then
+ Break;
+ end;
+end;
+
+function TDataLogger.Clear: TDataLogger;
+var
+ LProviders: TArray;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ FListLoggerItem.Clear;
+ FListLoggerItem.TrimExcess;
+ finally
+ UnLock;
+ end;
+
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].Clear;
+ end);
+end;
+
+function TDataLogger.CountLogInCache: Int64;
+begin
+ Lock;
+ try
+ Result := FListLoggerItem.Count;
+ finally
+ UnLock;
+ end;
+end;
+
+function TDataLogger.AddCache(const AType: TLoggerType; const AMessageString: string; const AMessageJSON: string; const ATag: string): TDataLogger;
+var
+ LLogItem: TLoggerItem;
+begin
+ Result := Self;
+
+ Lock;
+ try
+ if (TLoggerType.All in FDisableLogType) or (AType in FDisableLogType) then
+ Exit;
+
+ if not(TLoggerType.All in FOnlyLogType) and not(AType in FOnlyLogType) then
+ Exit;
+
+ if not(AType in FOnlyLogType) then
+ if Ord(FLogLevel) > Ord(AType) then
+ Exit;
+
+ if not(AType = TLoggerType.All) then
+ begin
+ if FSequence = 18446744073709551615 then
+ FSequence := 0;
+ Inc(FSequence);
+ end;
+
+ LLogItem := default (TLoggerItem);
+ LLogItem.Name := FName;
+ LLogItem.Sequence := FSequence;
+ LLogItem.TimeStamp := Now;
+ LLogItem.ThreadID := TThread.Current.ThreadID;
+ LLogItem.&Type := AType;
+ LLogItem.Tag := ATag;
+ LLogItem.Message := AMessageString;
+ LLogItem.MessageJSON := AMessageJSON;
+
+ LLogItem.AppName := TLoggerUtils.AppName;
+ LLogItem.AppPath := TLoggerUtils.AppPath;
+ LLogItem.AppVersion := TLoggerUtils.AppVersion;
+ LLogItem.AppSize := TLoggerUtils.AppSize;
+
+ LLogItem.ComputerName := TLoggerUtils.ComputerName;
+ LLogItem.Username := TLoggerUtils.Username;
+ LLogItem.OSVersion := TLoggerUtils.OS;
+ LLogItem.ProcessID := TLoggerUtils.ProcessID.ToString;
+ LLogItem.IPLocal := TLoggerUtils.IPLocal;
+
+ FListLoggerItem.Add(LLogItem);
+ finally
+ FEvent.SetEvent;
+ UnLock;
+ end;
+end;
+
+function TDataLogger.AddCache(const AType: TLoggerType; const AMessage: string; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(AType, AMessage, '', ATag);
+end;
+
+function TDataLogger.AddCache(const AType: TLoggerType; const AMessage: TJsonObject; const ATag: string): TDataLogger;
+begin
+ Result := AddCache(AType, '', AMessage.ToString, ATag);
+end;
+
+function TDataLogger.ExtractCache: TArray;
+var
+ LCache: TArray;
+begin
+ Lock;
+ try
+ LCache := FListLoggerItem.ToArray;
+
+ FListLoggerItem.Clear;
+ FListLoggerItem.TrimExcess;
+ finally
+ UnLock;
+ end;
+
+ Result := LCache;
+end;
+
+procedure TDataLogger.CloseProvider;
+var
+ LProviders: TArray;
+begin
+ LProviders := GetProviders;
+
+ TParallel.For(Low(LProviders), High(LProviders),
+ procedure(Index: Integer)
+ begin
+ LProviders[Index].NotifyEvent;
+ end);
+end;
+
+function TDataLogger.GetProviders: TArray;
+var
+ LProviders: TArray;
+begin
+ Result := [];
+
+ Lock;
+ try
+ LProviders := FListProviders.ToArray;
+ finally
+ UnLock;
+ end;
+
+ Result := LProviders;
+end;
+
+procedure TDataLogger.Lock;
+begin
+ FCriticalSection.Acquire;
+end;
+
+procedure TDataLogger.UnLock;
+begin
+ FCriticalSection.Release;
+end;
+
+initialization
+
+finalization
+
+if Assigned(FLoggerDefault) then
+begin
+ FLoggerDefault.Free;
+ FLoggerDefault := nil;
+end;
+
+end.
diff --git a/src/Providers/DataLogger.Provider.Console.pas b/src/Providers/DataLogger.Provider.Console.pas
index 1aca17d..f7ac915 100644
--- a/src/Providers/DataLogger.Provider.Console.pas
+++ b/src/Providers/DataLogger.Provider.Console.pas
@@ -59,16 +59,13 @@ procedure TProviderConsole.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
begin
Writeln;
Continue;
end;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -85,13 +82,13 @@ procedure TProviderConsole.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
@@ -158,6 +155,7 @@ TColor = record
end;
{$IF DEFINED(MSWINDOWS)}
+
var
ConOut: THandle;
BufInfo: TConsoleScreenBufferInfo;
@@ -170,6 +168,7 @@ TColor = record
SetConsoleTextAttribute(ConOut, BufInfo.wAttributes);
end;
{$ELSEIF DEFINED(LINUX)}
+
var
LColor: Integer;
begin
@@ -183,6 +182,7 @@ TColor = record
Write(#27'[0m');
end;
{$ELSE}
+
begin
Writeln(ALog);
end;
diff --git a/src/Providers/DataLogger.Provider.ElasticSearch.pas b/src/Providers/DataLogger.Provider.ElasticSearch.pas
index 28589d5..8936caa 100644
--- a/src/Providers/DataLogger.Provider.ElasticSearch.pas
+++ b/src/Providers/DataLogger.Provider.ElasticSearch.pas
@@ -10,27 +10,49 @@
interface
uses
- DataLogger.Provider.REST.HTTPClient, DataLogger.Types,
+{$IF DEFINED(DATALOGGER_TELEGRAM_USE_INDY)}
+ DataLogger.Provider.REST.Indy,
+{$ELSEIF DEFINED(DATALOGGER_TELEGRAM_USE_NETHTTPCLIENT)}
+ DataLogger.Provider.REST.NetHTTPClient,
+{$ELSE}
+ DataLogger.Provider.REST.HTTPClient,
+{$ENDIF}
+ DataLogger.Types,
System.SysUtils;
type
+{$IF DEFINED(DATALOGGER_TELEGRAM_USE_INDY)}
+ TProviderElasticSearch = class(TProviderRESTIndy)
+{$ELSEIF DEFINED(DATALOGGER_TELEGRAM_USE_NETHTTPCLIENT)}
+ TProviderElasticSearch = class(TProviderRESTNetHTTPClient)
+{$ELSE}
TProviderElasticSearch = class(TProviderRESTHTTPClient)
+{$ENDIF}
+ private
+ FHost: string;
+ FPort: Integer;
+ FIndex: string;
protected
procedure Save(const ACache: TArray); override;
public
- constructor Create(const AElasticHOST: string = 'http://localhost'; const AElasticPORT: Integer = 9200; const AElasticIndex: string = 'logger'); reintroduce;
+ property Host: string read FHost write FHost;
+ property Port: Integer read FPort write FPort;
+ property &Index: string read FIndex write FIndex;
+
+ constructor Create(const AHost: string = 'http://localhost'; const APort: Integer = 9200; const AIndex: string = 'logger'); reintroduce;
end;
implementation
{ TProviderElasticSearch }
-constructor TProviderElasticSearch.Create(const AElasticHOST: string = 'http://localhost'; const AElasticPORT: Integer = 9200; const AElasticIndex: string = 'logger');
-var
- LURL: string;
+constructor TProviderElasticSearch.Create(const AHost: string = 'http://localhost'; const APort: Integer = 9200; const AIndex: string = 'logger');
begin
- LURL := Format('%s:%d/%s/_doc', [AElasticHOST, AElasticPORT, AElasticIndex.ToLower]);
- inherited Create(LURL, 'application/json', '');
+ FHost := AHost;
+ FPort := APort;
+ FIndex := AIndex;
+
+ inherited Create('', 'application/json', '');
end;
procedure TProviderElasticSearch.Save(const ACache: TArray);
@@ -46,14 +68,12 @@ procedure TProviderElasticSearch.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(GetLogFormat, LItem);
+ LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(FLogFormat, LItem);
LLogItemREST.LogItem := LItem;
+ LLogItemREST.URL := Format('%s:%d/%s/_doc', [FHost, FPort, FIndex.ToLower]);
LItemREST := Concat(LItemREST, [LLogItemREST]);;
end;
diff --git a/src/Providers/DataLogger.Provider.Email.pas b/src/Providers/DataLogger.Provider.Email.pas
index b9eb093..df537d1 100644
--- a/src/Providers/DataLogger.Provider.Email.pas
+++ b/src/Providers/DataLogger.Provider.Email.pas
@@ -18,14 +18,18 @@ interface
TProviderEmail = class(TDataLoggerProvider)
private
FIdSMTP: TIdSMTP;
- FIdMessage: TIdMessage;
+ FFromAddress: string;
+ FToAddress: string;
+ FSubject: string;
protected
procedure Save(const ACache: TArray); override;
public
property IdSMTP: TIdSMTP read FIdSMTP write FIdSMTP;
+ property FromAddress: string read FFromAddress write FFromAddress;
+ property ToAddress: string read FToAddress write FToAddress;
+ property Subject: string read FSubject write FSubject;
constructor Create(const AIdSMTP: TIdSMTP; const AFromAddress: string; const AToAddress: string; const ASubject: string = 'Logger');
- destructor Destroy; override;
end;
implementation
@@ -33,89 +37,90 @@ implementation
{ TProviderEmail }
constructor TProviderEmail.Create(const AIdSMTP: TIdSMTP; const AFromAddress: string; const AToAddress: string; const ASubject: string = 'Logger');
-var
- LToAddress: TArray;
- LEmail: string;
begin
inherited Create;
FIdSMTP := AIdSMTP;
- FIdMessage := TIdMessage.Create;
-
- FIdMessage.From.Text := AFromAddress;
-
- LToAddress := AToAddress.Trim.Split([';']);
- for LEmail in LToAddress do
- FIdMessage.Recipients.Add.Text := LEmail;
-
- FIdMessage.Subject := ASubject
-end;
-
-destructor TProviderEmail.Destroy;
-begin
- FIdMessage.Free;
- inherited;
+ FFromAddress := AFromAddress;
+ FToAddress := AToAddress;
+ FSubject := ASubject;
end;
procedure TProviderEmail.Save(const ACache: TArray);
var
+ LIdMessage: TIdMessage;
+ LToAddress: TArray;
+ LEmail: string;
LRetryCount: Integer;
LItem: TLoggerItem;
LLog: string;
LString: TStringList;
begin
+ if not Assigned(FIdSMTP) then
+ raise EDataLoggerException.Create('IdSMTP not defined!');
+
if Length(ACache) = 0 then
Exit;
- LString := TStringList.Create;
+ LIdMessage := TIdMessage.Create;
try
- for LItem in ACache do
- begin
- if not ValidationBeforeSave(LItem) then
- Continue;
+ LIdMessage.From.Text := FFromAddress;
- if LItem.&Type = TLoggerType.All then
- Continue;
+ LToAddress := FToAddress.Trim.Split([';']);
+ for LEmail in LToAddress do
+ LIdMessage.Recipients.Add.Text := LEmail.Trim;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
- LString.Add(LLog);
- end;
+ LIdMessage.Subject := FSubject;
- FIdMessage.Body.Text := LString.Text;
- finally
- LString.Free;
- end;
+ LString := TStringList.Create;
+ try
+ for LItem in ACache do
+ begin
+ if LItem.&Type = TLoggerType.All then
+ Continue;
- LRetryCount := 0;
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
+ LString.Add(LLog);
+ end;
- while True do
- try
- if not FIdSMTP.Connected then
- FIdSMTP.Connect;
+ LIdMessage.Body.Text := LString.Text;
+ finally
+ LString.Free;
+ end;
- FIdSMTP.Send(FIdMessage);
+ LRetryCount := 0;
- Break;
- except
- on E: Exception do
- begin
- Inc(LRetryCount);
+ while True do
+ try
+ if not FIdSMTP.Connected then
+ FIdSMTP.Connect;
+
+ FIdSMTP.Send(LIdMessage);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ Break;
+ except
+ on E: Exception do
+ begin
+ Inc(LRetryCount);
- if Self.Terminated then
- Exit;
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
- if LRetryCount >= GetMaxRetry then
- Break;
+ if Self.Terminated then
+ Exit;
+
+ if LRetryCount >= FMaxRetry then
+ Break;
+ end;
end;
- end;
- try
- if FIdSMTP.Connected then
- FIdSMTP.Disconnect(False);
- except
+ try
+ if FIdSMTP.Connected then
+ FIdSMTP.Disconnect(False);
+ except
+ end;
+ finally
+ LIdMessage.Free;
end;
end;
diff --git a/src/Providers/DataLogger.Provider.EventLog.pas b/src/Providers/DataLogger.Provider.EventLog.pas
index 819556a..78552b1 100644
--- a/src/Providers/DataLogger.Provider.EventLog.pas
+++ b/src/Providers/DataLogger.Provider.EventLog.pas
@@ -19,12 +19,12 @@ interface
type
TProviderEventLog = class(TDataLoggerProvider)
private
-{$IF DEFINED(MSWINDOWS)}
- FEventLogger: TEventLogger;
-{$ENDIF}
+ FName: string;
protected
procedure Save(const ACache: TArray); override;
public
+ property Name: string read FName write FName;
+
constructor Create(const AName: string = '');
destructor Destroy; override;
end;
@@ -34,27 +34,21 @@ implementation
{ TProviderEventLog }
constructor TProviderEventLog.Create(const AName: string = '');
-{$IF DEFINED(MSWINDOWS)}
-var
- LName: string;
-{$ENDIF}
begin
inherited Create;
{$IF DEFINED(MSWINDOWS)}
if AName.Trim.IsEmpty then
- LName := TLoggerUtils.AppName
+ FName := TLoggerUtils.AppName
else
- LName := AName;
-
- FEventLogger := TEventLogger.Create(LName);
+ FName := AName;
{$ENDIF}
end;
destructor TProviderEventLog.Destroy;
begin
{$IF DEFINED(MSWINDOWS)}
- FEventLogger.Free;
+
{$ENDIF}
inherited;
end;
@@ -62,6 +56,7 @@ destructor TProviderEventLog.Destroy;
procedure TProviderEventLog.Save(const ACache: TArray);
{$IF DEFINED(MSWINDOWS)}
var
+ LEventLogger: TEventLogger;
LRetryCount: Integer;
LItem: TLoggerItem;
LLog: string;
@@ -70,55 +65,59 @@ procedure TProviderEventLog.Save(const ACache: TArray);
if Length(ACache) = 0 then
Exit;
- for LItem in ACache do
- begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
- if LItem.&Type = TLoggerType.All then
- Continue;
-
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
-
- case LItem.&Type of
- TLoggerType.Debug:
- LEventType := EVENTLOG_INFORMATION_TYPE;
- TLoggerType.Info:
+ LEventLogger := TEventLogger.Create(FName);
+ try
+ for LItem in ACache do
+ begin
+ if LItem.&Type = TLoggerType.All then
+ Continue;
+
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
+
+ case LItem.&Type of
+ TLoggerType.Debug:
+ LEventType := EVENTLOG_INFORMATION_TYPE;
+ TLoggerType.Info:
+ LEventType := EVENTLOG_INFORMATION_TYPE;
+ TLoggerType.Warn:
+ LEventType := EVENTLOG_WARNING_TYPE;
+ TLoggerType.Error:
+ LEventType := EVENTLOG_ERROR_TYPE;
+ TLoggerType.Success:
+ LEventType := EVENTLOG_SUCCESS;
+ else
LEventType := EVENTLOG_INFORMATION_TYPE;
- TLoggerType.Warn:
- LEventType := EVENTLOG_WARNING_TYPE;
- TLoggerType.Error:
- LEventType := EVENTLOG_ERROR_TYPE;
- TLoggerType.Success:
- LEventType := EVENTLOG_SUCCESS;
- else
- LEventType := EVENTLOG_INFORMATION_TYPE;
- end;
+ end;
- LRetryCount := 0;
+ LRetryCount := 0;
- while True do
- try
- FEventLogger.LogMessage(LLog, LEventType, 0, 0);
- Break;
- except
- on E: Exception do
- begin
- Inc(LRetryCount);
+ while True do
+ try
+ LEventLogger.LogMessage(LLog, LEventType, 0, 0);
+ Break;
+ except
+ on E: Exception do
+ begin
+ Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
- if Self.Terminated then
- Exit;
+ if Self.Terminated then
+ Exit;
- if LRetryCount >= GetMaxRetry then
- Break;
+ if LRetryCount >= FMaxRetry then
+ Break;
+ end;
end;
- end;
+ end;
+ finally
+ LEventLogger.Free;
end;
end;
{$ELSE}
+
+
begin
end;
{$ENDIF}
diff --git a/src/Providers/DataLogger.Provider.Events.pas b/src/Providers/DataLogger.Provider.Events.pas
index c527a21..8ea8c7e 100644
--- a/src/Providers/DataLogger.Provider.Events.pas
+++ b/src/Providers/DataLogger.Provider.Events.pas
@@ -76,7 +76,7 @@ procedure TProviderEvents.Save(const ACache: TArray);
procedure _Execute(const AEvent: TExecuteEvents; const AItem: TLoggerItem);
begin
if Assigned(AEvent) then
- AEvent(GetLogFormat, AItem, GetFormatTimestamp);
+ AEvent(FLogFormat, AItem, FFormatTimestamp);
end;
var
@@ -84,16 +84,13 @@ procedure TProviderEvents.Save(const ACache: TArray);
LItem: TLoggerItem;
begin
if not Assigned(FConfig) then
- raise EDataLoggerException.Create('Config not defined');
+ raise EDataLoggerException.Create('Config not defined!');
if Length(ACache) = 0 then
Exit;
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
@@ -126,13 +123,13 @@ procedure TProviderEvents.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end
diff --git a/src/Providers/DataLogger.Provider.ListBox.pas b/src/Providers/DataLogger.Provider.ListBox.pas
index 45917da..91e5898 100644
--- a/src/Providers/DataLogger.Provider.ListBox.pas
+++ b/src/Providers/DataLogger.Provider.ListBox.pas
@@ -50,6 +50,7 @@ constructor TProviderListBox.Create(const AListBox: TCustomListBox; const AMaxLo
{$ENDIF}
+
procedure TProviderListBox.Save(const ACache: TArray);
{$IF DEFINED(MSWINDOWS)}
var
@@ -59,20 +60,17 @@ procedure TProviderListBox.Save(const ACache: TArray);
LLines: Integer;
begin
if not Assigned(FListBox) then
- raise EDataLoggerException.Create('ListBox not defined');
+ raise EDataLoggerException.Create('ListBox not defined!');
if Length(ACache) = 0 then
Exit;
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
LLog := ''
else
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -130,19 +128,20 @@ procedure TProviderListBox.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
end;
end;
{$ELSE}
+
begin
end;
{$ENDIF}
diff --git a/src/Providers/DataLogger.Provider.ListView.pas b/src/Providers/DataLogger.Provider.ListView.pas
index 33ffa6b..0a8cab4 100644
--- a/src/Providers/DataLogger.Provider.ListView.pas
+++ b/src/Providers/DataLogger.Provider.ListView.pas
@@ -50,6 +50,7 @@ constructor TProviderListView.Create(const AListView: TCustomListView; const AMa
{$ENDIF}
+
procedure TProviderListView.Save(const ACache: TArray);
{$IF DEFINED(MSWINDOWS)}
var
@@ -59,20 +60,17 @@ procedure TProviderListView.Save(const ACache: TArray);
LLines: Integer;
begin
if not Assigned(FListView) then
- raise EDataLoggerException.Create('ListView not defined');
+ raise EDataLoggerException.Create('ListView not defined!');
if Length(ACache) = 0 then
Exit;
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
LLog := ''
else
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -130,19 +128,20 @@ procedure TProviderListView.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
end;
end;
{$ELSE}
+
begin
end;
{$ENDIF}
diff --git a/src/Providers/DataLogger.Provider.Logstach.pas b/src/Providers/DataLogger.Provider.Logstach.pas
index b8fc5b9..1e10146 100644
--- a/src/Providers/DataLogger.Provider.Logstach.pas
+++ b/src/Providers/DataLogger.Provider.Logstach.pas
@@ -10,27 +10,49 @@
interface
uses
- DataLogger.Provider.REST.HTTPClient, DataLogger.Types,
+{$IF DEFINED(DATALOGGER_LOGSTACH_USE_INDY)}
+ DataLogger.Provider.REST.Indy,
+{$ELSEIF DEFINED(DATALOGGER_LOGSTACH_USE_NETHTTPCLIENT)}
+ DataLogger.Provider.REST.NetHTTPClient,
+{$ELSE}
+ DataLogger.Provider.REST.HTTPClient,
+{$ENDIF}
+ DataLogger.Types,
System.SysUtils;
type
+{$IF DEFINED(DATALOGGER_LOGSTACH_USE_INDY)}
+ TProviderLogstach = class(TProviderRESTIndy)
+{$ELSEIF DEFINED(DATALOGGER_LOGSTACH_USE_NETHTTPCLIENT)}
+ TProviderLogstach = class(TProviderRESTNetHTTPClient)
+{$ELSE}
TProviderLogstach = class(TProviderRESTHTTPClient)
+{$ENDIF}
+ private
+ FHost: string;
+ FPort: Integer;
+ FIndex: string;
protected
procedure Save(const ACache: TArray); override;
public
- constructor Create(const ALogstachHOST: string = 'http://localhost'; const ALogstachPORT: Integer = 5044; const ALogstachIndex: string = 'logger'); reintroduce;
+ property Host: string read FHost write FHost;
+ property Port: Integer read FPort write FPort;
+ property &Index: string read FIndex write FIndex;
+
+ constructor Create(const AHost: string = 'http://localhost'; const APort: Integer = 5044; const AIndex: string = 'logger'); reintroduce;
end;
implementation
{ TProviderLogstach }
-constructor TProviderLogstach.Create(const ALogstachHOST: string = 'http://localhost'; const ALogstachPORT: Integer = 5044; const ALogstachIndex: string = 'logger');
-var
- LURL: string;
+constructor TProviderLogstach.Create(const AHost: string = 'http://localhost'; const APort: Integer = 5044; const AIndex: string = 'logger');
begin
- LURL := Format('%s:%d/%s/doc', [ALogstachHOST, ALogstachPORT, ALogstachIndex.ToLower]);
- inherited Create(LURL, 'application/json', '');
+ FHost := AHost;
+ FPort := APort;
+ FIndex := AIndex;
+
+ inherited Create('', 'application/json');
end;
procedure TProviderLogstach.Save(const ACache: TArray);
@@ -46,18 +68,15 @@ procedure TProviderLogstach.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(GetLogFormat, LItem);
+ LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(FLogFormat, LItem);
LLogItemREST.LogItem := LItem;
+ LLogItemREST.URL := Format('%s:%d/%s/doc', [FHost, FPort, FIndex.ToLower]);
LItemREST := Concat(LItemREST, [LLogItemREST]);
end;
-
InternalSave(TLoggerMethod.tlmPost, LItemREST);
end;
diff --git a/src/Providers/DataLogger.Provider.Mattermost.Hooks.pas b/src/Providers/DataLogger.Provider.Mattermost.Hooks.pas
new file mode 100644
index 0000000..6e26b2e
--- /dev/null
+++ b/src/Providers/DataLogger.Provider.Mattermost.Hooks.pas
@@ -0,0 +1,153 @@
+{
+ *************************************
+ Created by Danilo Lucas
+ Github - https://github.com/dliocode
+ *************************************
+}
+
+// https://api.mattermost.com/
+
+unit DataLogger.Provider.Mattermost.Hooks;
+
+interface
+
+uses
+{$IF DEFINED(DATALOGGER_MATTERMOST_USE_INDY)}
+ DataLogger.Provider.REST.Indy,
+{$ELSEIF DEFINED(DATALOGGER_MATTERMOST_USE_NETHTTPCLIENT)}
+ DataLogger.Provider.REST.NetHTTPClient,
+{$ELSE}
+ DataLogger.Provider.REST.HTTPClient,
+{$ENDIF}
+ DataLogger.Types,
+ System.SysUtils, System.Classes, System.JSON, System.Net.URLClient, System.NetConsts, System.Net.HTTPClient;
+
+type
+{$IF DEFINED(DATALOGGER_MATTERMOST_USE_INDY)}
+ TProviderMattermostHooks = class(TProviderRESTIndy)
+{$ELSEIF DEFINED(DATALOGGER_MATTERMOST_USE_NETHTTPCLIENT)}
+ TProviderMattermostHooks = class(TProviderRESTNetHTTPClient)
+{$ELSE}
+ TProviderMattermostHooks = class(TProviderRESTHTTPClient)
+{$ENDIF}
+ private
+ FURL: string;
+ FChannelId: string;
+ FUsername: string;
+ FModePropsCard: Boolean;
+ protected
+ procedure Save(const ACache: TArray); override;
+ public
+ property URL: string read FURL write FURL;
+ property ChannelId: string read FChannelId write FChannelId;
+ property Username: string read FUsername write FUsername;
+ property ModePropsCard: Boolean read FModePropsCard write FModePropsCard;
+
+ constructor Create(const AURL: string; const AChannelId: string; const AUserName: string = ''; const AModePropsCard: Boolean = False); reintroduce;
+ end;
+
+implementation
+
+{ TProviderMattermostHooks }
+
+constructor TProviderMattermostHooks.Create(const AURL: string; const AChannelId: string; const AUserName: string = ''; const AModePropsCard: Boolean = False);
+begin
+ FURL := AURL;
+ FChannelId := AChannelId;
+ FUsername := AUserName;
+ FModePropsCard := AModePropsCard;
+
+ inherited Create('', 'application/json');
+end;
+
+procedure TProviderMattermostHooks.Save(const ACache: TArray);
+var
+ LItemREST: TArray;
+ LJO: TJSONObject;
+ LLog: string;
+
+ procedure Default;
+ var
+ LItem: TLoggerItem;
+ LLogItemREST: TLogItemREST;
+ begin
+ for LItem in ACache do
+ begin
+ if LItem.&Type = TLoggerType.All then
+ Continue;
+
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
+
+ LJO := TJSONObject.Create;
+ try
+ LJO.AddPair('channel_id', FChannelId);
+ LJO.AddPair('username', FUsername);
+ LJO.AddPair('text', LLog);
+
+ LLogItemREST.Stream := TStringStream.Create(LJO.ToString, TEncoding.UTF8);
+ LLogItemREST.LogItem := LItem;
+ LLogItemREST.URL := FURL;
+ finally
+ LJO.Free;
+ end;
+
+ LItemREST := Concat(LItemREST, [LLogItemREST]);
+ end;
+ end;
+
+ procedure PropsCard;
+ var
+ LItem: TLoggerItem;
+ LLogItemREST: TLogItemREST;
+ LAppend: TStringBuilder;
+ begin
+ LJO := TJSONObject.Create;
+ try
+ LJO.AddPair('channel_id', FChannelId);
+ LJO.AddPair('username', FUsername);
+
+ LAppend := TStringBuilder.Create;
+ try
+ for LItem in ACache do
+ begin
+ if LItem.&Type = TLoggerType.All then
+ Continue;
+
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
+
+ LAppend.Append(LLog);
+ LAppend.AppendLine;
+ end;
+
+ LJO.AddPair('props', TJSONObject.Create(TJSONPair.Create('card', LAppend.ToString)))
+ finally
+ LAppend.Free;
+ end;
+
+ LJO.AddPair('text', LLog);
+
+ LLogItemREST.Stream := TStringStream.Create(LJO.ToString.Replace('\r\n', '\r\n\r\n'), TEncoding.UTF8);
+ LLogItemREST.LogItem := LItem;
+ LLogItemREST.URL := FURL;
+ finally
+ LJO.Free;
+ end;
+
+ LItemREST := Concat(LItemREST, [LLogItemREST]);
+ end;
+
+begin
+ if Length(ACache) = 0 then
+ Exit;
+
+ LItemREST := [];
+
+ if FModePropsCard and (Length(ACache) > 1) then
+ PropsCard
+ else
+ Default;
+
+ InternalSave(TLoggerMethod.tlmPost, LItemREST);
+end;
+
+end.
diff --git a/src/Providers/DataLogger.Provider.Mattermost.pas b/src/Providers/DataLogger.Provider.Mattermost.pas
index fc0711f..9009aed 100644
--- a/src/Providers/DataLogger.Provider.Mattermost.pas
+++ b/src/Providers/DataLogger.Provider.Mattermost.pas
@@ -12,48 +12,66 @@
interface
uses
- DataLogger.Provider.REST.HTTPClient, DataLogger.Types,
- System.SysUtils, System.Classes, System.JSON, System.Net.URLClient, System.NetConsts, System.Net.HttpClient;
+{$IF DEFINED(DATALOGGER_MATTERMOST_USE_INDY)}
+ DataLogger.Provider.REST.Indy,
+{$ELSEIF DEFINED(DATALOGGER_MATTERMOST_USE_NETHTTPCLIENT)}
+ DataLogger.Provider.REST.NetHTTPClient,
+{$ELSE}
+ DataLogger.Provider.REST.HTTPClient,
+{$ENDIF}
+ DataLogger.Types,
+ System.SysUtils, System.Classes, System.JSON, System.Net.URLClient, System.NetConsts, System.Net.HTTPClient;
type
+{$IF DEFINED(DATALOGGER_MATTERMOST_USE_INDY)}
+ TProviderMattermost = class(TProviderRESTIndy)
+{$ELSEIF DEFINED(DATALOGGER_MATTERMOST_USE_NETHTTPCLIENT)}
+ TProviderMattermost = class(TProviderRESTNetHTTPClient)
+{$ELSE}
TProviderMattermost = class(TProviderRESTHTTPClient)
+{$ENDIF}
private
- FChannel: string;
+ FURL: string;
+ FTokenBearer: string;
+ FChannelId: string;
function Login(const AURL: string; const AUsername: string; const APassword: string): string;
protected
procedure Save(const ACache: TArray); override;
public
- constructor Create(const AURL: string; const ATokenBearer: string; const AChannel: string); reintroduce;
- constructor CreateLogin(const AURL: string; const AUsername: string; const APassword: string; const AChannel: string);
+ property URL: string read FURL write FURL;
+ property TokenBearer: string read FTokenBearer write FTokenBearer;
+ property ChannelId: string read FChannelId write FChannelId;
+
+ constructor Create(const AURL: string; const ATokenBearer: string; const AChannelId: string); reintroduce;
+ constructor CreateLogin(const AURL: string; const AUsername: string; const APassword: string; const AChannelId: string);
end;
implementation
{ TProviderMattermost }
-constructor TProviderMattermost.Create(const AURL: string; const ATokenBearer: string; const AChannel: string);
-var
- LURL: string;
+constructor TProviderMattermost.Create(const AURL: string; const ATokenBearer: string; const AChannelId: string);
begin
- FChannel := AChannel;
+ FURL := AURL;
+ FTokenBearer := ATokenBearer;
+ FChannelId := AChannelId;
- LURL := Format('%s/api/v4/posts', [ExcludeTrailingPathDelimiter(AURL)]);
- inherited Create(LURL, 'application/json', ATokenBearer);
+ inherited Create('', 'application/json', ATokenBearer);
end;
-constructor TProviderMattermost.CreateLogin(const AURL: string; const AUsername: string; const APassword: string; const AChannel: string);
+constructor TProviderMattermost.CreateLogin(const AURL: string; const AUsername: string; const APassword: string; const AChannelId: string);
var
LTokenBearer: string;
begin
LTokenBearer := Login(AURL, AUsername, APassword);
- Create(AURL, LTokenBearer, AChannel);
+ Create(AURL, LTokenBearer, AChannelId);
end;
function TProviderMattermost.Login(const AURL: string; const AUsername: string; const APassword: string): string;
var
LHTTP: THTTPClient;
- LBodyJSON: TJSONOBject;
+ LBodyJSON: TJSONObject;
LBody: TStream;
LResponse: IHTTPResponse;
begin
@@ -67,15 +85,14 @@ function TProviderMattermost.Login(const AURL: string; const AUsername: string;
LHTTP.HandleRedirects := True;
LHTTP.UserAgent := 'DataLogger.Provider.Mattermost';
LHTTP.ContentType := 'application/json';
-
LHTTP.AcceptCharSet := 'utf-8';
LHTTP.AcceptEncoding := 'utf-8';
LHTTP.Accept := 'application/json';
LBodyJSON := TJSONObject.Create;
try
- LBodyJSON.AddPair('login_id',AUsername);
- LBodyJSON.AddPair('password',APassword);
+ LBodyJSON.AddPair('login_id', AUsername);
+ LBodyJSON.AddPair('password', APassword);
LBody := TStringStream.Create(LBodyJSON.ToString, TEncoding.UTF8);
finally
@@ -88,7 +105,7 @@ function TProviderMattermost.Login(const AURL: string; const AUsername: string;
raise EDataLoggerException.Create('Erro: Invalid authentication in Provider Mattermost - Response nil!');
if LResponse.StatusCode <> 200 then
- raise EDataLoggerException.CreateFmt('Error: Invalid authentication in Provider Mattermost - (%d) %s',[LResponse.StatusCode, LResponse.ContentAsString(TEncoding.UTF8)]);
+ raise EDataLoggerException.CreateFmt('Error: Invalid authentication in Provider Mattermost - (%d) %s', [LResponse.StatusCode, LResponse.ContentAsString(TEncoding.UTF8)]);
Result := LResponse.HeaderValue['Token'];
finally
@@ -114,21 +131,19 @@ procedure TProviderMattermost.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LJO := TJSONObject.Create;
try
- LJO.AddPair('channel_id', TJSONString.Create(FChannel));
- LJO.AddPair('message', TJSONString.Create(LLog));
+ LJO.AddPair('channel_id', FChannelId);
+ LJO.AddPair('message', LLog);
LLogItemREST.Stream := TStringStream.Create(LJO.ToString, TEncoding.UTF8);
LLogItemREST.LogItem := LItem;
+ LLogItemREST.URL := Format('%s/api/v4/posts', [ExcludeTrailingPathDelimiter(FURL)]);
finally
LJO.Free;
end;
diff --git a/src/Providers/DataLogger.Provider.Memo.pas b/src/Providers/DataLogger.Provider.Memo.pas
index 78ebec9..0bbe229 100644
--- a/src/Providers/DataLogger.Provider.Memo.pas
+++ b/src/Providers/DataLogger.Provider.Memo.pas
@@ -43,7 +43,6 @@ implementation
{$IF DEFINED(MSWINDOWS)}
-
constructor TProviderMemo.Create(const AMemo: TCustomMemo; const AMaxLogLines: Integer = 0; const AModeInsert: TModeInsert = tmLast);
begin
inherited Create;
@@ -65,20 +64,17 @@ procedure TProviderMemo.Save(const ACache: TArray);
LLines: Integer;
begin
if not Assigned(FMemo) then
- raise EDataLoggerException.Create('Memo not defined');
+ raise EDataLoggerException.Create('Memo not defined!');
if Length(ACache) = 0 then
Exit;
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
LLog := ''
else
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -148,22 +144,20 @@ procedure TProviderMemo.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
end;
end;
-
{$ELSE}
-
begin
end;
{$ENDIF}
diff --git a/src/Providers/DataLogger.Provider.Memory.pas b/src/Providers/DataLogger.Provider.Memory.pas
index 9e1d3f7..59126a6 100644
--- a/src/Providers/DataLogger.Provider.Memory.pas
+++ b/src/Providers/DataLogger.Provider.Memory.pas
@@ -53,13 +53,10 @@ procedure TProviderMemory.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -73,13 +70,13 @@ procedure TProviderMemory.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
diff --git a/src/Providers/DataLogger.Provider.OutputDebugString.pas b/src/Providers/DataLogger.Provider.OutputDebugString.pas
index 1fc5ed3..93a8f78 100644
--- a/src/Providers/DataLogger.Provider.OutputDebugString.pas
+++ b/src/Providers/DataLogger.Provider.OutputDebugString.pas
@@ -38,19 +38,15 @@ procedure TProviderOutputDebugString.Save(const ACache: TArray);
{$IF DEFINED(LINUX)}
Exit;
{$ENDIF}
-
if Length(ACache) = 0 then
Exit;
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -61,20 +57,19 @@ procedure TProviderOutputDebugString.Save(const ACache: TArray);
{$ELSEIF DEFINED(ANDROID) || DEFINED(IOS)}
FMX.Types.Log.d(LLog);
{$ENDIF}
-
Break;
except
on E: Exception do
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
diff --git a/src/Providers/DataLogger.Provider.REST.HTTPClient.pas b/src/Providers/DataLogger.Provider.REST.HTTPClient.pas
index c48bc44..519de61 100644
--- a/src/Providers/DataLogger.Provider.REST.HTTPClient.pas
+++ b/src/Providers/DataLogger.Provider.REST.HTTPClient.pas
@@ -27,23 +27,25 @@ TLogItemResponse = record
Content: string;
end;
- TSaveFinally = reference to procedure(const ALogItem: TLoggerItem; const AContent: string);
+ TExecuteFinally = reference to procedure(const ALogItem: TLoggerItem; const AContent: string);
TLoggerMethod = (tlmGet, tlmPost);
TProviderRESTHTTPClient = class(TDataLoggerProvider)
private
FURL: string;
- FBearerToken: string;
FContentType: string;
- FSaveFinally: TSaveFinally;
+ FBearerToken: string;
+ FExecuteFinally: TExecuteFinally;
procedure HTTP(const AMethod: TLoggerMethod; const AItemREST: TLogItemREST);
protected
- procedure SetURL(const AURL: string);
+ property URL: string read FURL write FURL;
+ property ContentType: string read FContentType write FContentType;
+ property BearerToken: string read FBearerToken write FBearerToken;
procedure InternalSave(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
procedure InternalSaveAsync(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
- procedure SetSendFinally(const ASaveFinally: TSaveFinally);
+ procedure SetExecuteFinally(const AExecuteFinally: TExecuteFinally);
procedure Save(const ACache: TArray); override;
public
constructor Create(const AURL: string; const AContentType: string = 'text/plain'; const ABearerToken: string = '');
@@ -73,7 +75,7 @@ constructor TProviderRESTHTTPClient.Create(const AURL: string; const AContentTyp
if FContentType.Trim.IsEmpty then
FContentType := 'text/plain';
- FSaveFinally := nil;
+ FExecuteFinally := nil;
end;
procedure TProviderRESTHTTPClient.Save(const ACache: TArray);
@@ -89,16 +91,13 @@ procedure TProviderRESTHTTPClient.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
if Trim(LowerCase(FContentType)) = 'application/json' then
- LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(GetLogFormat, LItem)
+ LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(FLogFormat, LItem)
else
- LLogItemREST.Stream := TLoggerLogFormat.AsStream(GetLogFormat, LItem, GetFormatTimestamp);
+ LLogItemREST.Stream := TLoggerLogFormat.AsStream(FLogFormat, LItem, FFormatTimestamp);
LLogItemREST.LogItem := LItem;
@@ -108,14 +107,9 @@ procedure TProviderRESTHTTPClient.Save(const ACache: TArray);
InternalSaveAsync(TLoggerMethod.tlmPost, LItemREST);
end;
-procedure TProviderRESTHTTPClient.SetSendFinally(const ASaveFinally: TSaveFinally);
-begin
- FSaveFinally := ASaveFinally;
-end;
-
-procedure TProviderRESTHTTPClient.SetURL(const AURL: string);
+procedure TProviderRESTHTTPClient.SetExecuteFinally(const AExecuteFinally: TExecuteFinally);
begin
- FURL := AURL;
+ FExecuteFinally := AExecuteFinally;
end;
procedure TProviderRESTHTTPClient.InternalSave(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
@@ -215,21 +209,21 @@ procedure TProviderRESTHTTPClient.HTTP(const AMethod: TLoggerMethod; const AItem
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, AItemREST.LogItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, AItemREST.LogItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
finally
LHTTP.Free;
- if Assigned(FSaveFinally) then
- FSaveFinally(AItemREST.LogItem, LResponseContent);
+ if Assigned(FExecuteFinally) then
+ FExecuteFinally(AItemREST.LogItem, LResponseContent);
if Assigned(AItemREST.Stream) then
AItemREST.Stream.Free;
diff --git a/src/Providers/DataLogger.Provider.REST.Indy.pas b/src/Providers/DataLogger.Provider.REST.Indy.pas
index 6a3f241..49e9be7 100644
--- a/src/Providers/DataLogger.Provider.REST.Indy.pas
+++ b/src/Providers/DataLogger.Provider.REST.Indy.pas
@@ -12,7 +12,7 @@ interface
uses
DataLogger.Provider, DataLogger.Types,
System.SysUtils, System.Classes, System.Threading,
- IdHTTP;
+ IdHTTP, IdSSLOpenSSL;
type
TIdHTTP = IdHTTP.TIdHTTP;
@@ -23,23 +23,25 @@ TLogItemREST = record
URL: string;
end;
- TSaveFinally = reference to procedure(const ALogItem: TLoggerItem; const AContent: string);
+ TExecuteFinally = reference to procedure(const ALogItem: TLoggerItem; const AContent: string);
TLoggerMethod = (tlmGet, tlmPost);
TProviderRESTIndy = class(TDataLoggerProvider)
private
FURL: string;
- FBearerToken: string;
FContentType: string;
- FSaveFinally: TSaveFinally;
+ FBearerToken: string;
+ FExecuteFinally: TExecuteFinally;
procedure HTTP(const AMethod: TLoggerMethod; const AItemREST: TLogItemREST);
protected
- procedure SetURL(const AURL: string);
+ property URL: string read FURL write FURL;
+ property ContentType: string read FContentType write FContentType;
+ property BearerToken: string read FBearerToken write FBearerToken;
procedure InternalSave(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
procedure InternalSaveAsync(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
- procedure SetSendFinally(const ASaveFinally: TSaveFinally);
+ procedure SetExecuteFinally(const AExecuteFinally: TExecuteFinally);
procedure Save(const ACache: TArray); override;
public
constructor Create(const AURL: string; const AContentType: string = 'text/plain'; const ABearerToken: string = '');
@@ -83,16 +85,13 @@ procedure TProviderRESTIndy.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
if Trim(LowerCase(FContentType)) = 'application/json' then
- LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(GetLogFormat, LItem)
+ LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(FLogFormat, LItem)
else
- LLogItemREST.Stream := TLoggerLogFormat.AsStream(GetLogFormat, LItem, GetFormatTimestamp);
+ LLogItemREST.Stream := TLoggerLogFormat.AsStream(FLogFormat, LItem, FFormatTimestamp);
LLogItemREST.LogItem := LItem;
@@ -102,14 +101,9 @@ procedure TProviderRESTIndy.Save(const ACache: TArray);
InternalSaveAsync(TLoggerMethod.tlmPost, LItemREST);
end;
-procedure TProviderRESTIndy.SetSendFinally(const ASaveFinally: TSaveFinally);
-begin
- FSaveFinally := ASaveFinally;
-end;
-
-procedure TProviderRESTIndy.SetURL(const AURL: string);
+procedure TProviderRESTIndy.SetExecuteFinally(const AExecuteFinally: TExecuteFinally);
begin
- FURL := AURL;
+ FExecuteFinally := AExecuteFinally;
end;
procedure TProviderRESTIndy.InternalSave(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
@@ -140,6 +134,7 @@ procedure TProviderRESTIndy.HTTP(const AMethod: TLoggerMethod; const AItemREST:
LRetryCount: Integer;
LURL: string;
LHTTP: TIdHTTP;
+ LSSL: TIdSSLIOHandlerSocketOpenSSL;
LResponseContent: string;
begin
if Self.Terminated then
@@ -159,6 +154,7 @@ procedure TProviderRESTIndy.HTTP(const AMethod: TLoggerMethod; const AItemREST:
try
LHTTP := TIdHTTP.Create(nil);
+ LSSL := nil;
except
if Assigned(AItemREST.Stream) then
AItemREST.Stream.Free;
@@ -180,6 +176,17 @@ procedure TProviderRESTIndy.HTTP(const AMethod: TLoggerMethod; const AItemREST:
if not FBearerToken.Trim.IsEmpty then
LHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FBearerToken);
+ if LURL.ToLower.Contains('https://') then
+ begin
+ if not LoadOpenSSLLibrary then
+ raise EDataLoggerException.Create('DLL''s not compatible or not found (ssleay32 e libeay32)');
+
+ LSSL := TIdSSLIOHandlerSocketOpenSSL.Create(LHTTP);
+ LSSL.SSLOptions.Method := sslvTLSv1_2;
+ end;
+
+ LHTTP.IOHandler := LSSL;
+
LRetryCount := 0;
while True do
@@ -205,21 +212,24 @@ procedure TProviderRESTIndy.HTTP(const AMethod: TLoggerMethod; const AItemREST:
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, AItemREST.LogItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, AItemREST.LogItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
finally
LHTTP.Free;
- if Assigned(FSaveFinally) then
- FSaveFinally(AItemREST.LogItem, LResponseContent);
+ if Assigned(LSSL) then
+ UnLoadOpenSSLLibrary;
+
+ if Assigned(FExecuteFinally) then
+ FExecuteFinally(AItemREST.LogItem, LResponseContent);
if Assigned(AItemREST.Stream) then
AItemREST.Stream.Free;
diff --git a/src/Providers/DataLogger.Provider.REST.NetHTTPClient.pas b/src/Providers/DataLogger.Provider.REST.NetHTTPClient.pas
index 894fa4f..b7278f2 100644
--- a/src/Providers/DataLogger.Provider.REST.NetHTTPClient.pas
+++ b/src/Providers/DataLogger.Provider.REST.NetHTTPClient.pas
@@ -22,24 +22,26 @@ TLogItemREST = record
URL: string;
end;
- TSaveFinally = reference to procedure(const ALogItem: TLoggerItem; const AContent: string);
+ TExecuteFinally = reference to procedure(const ALogItem: TLoggerItem; const AContent: string);
TLoggerMethod = (tlmGet, tlmPost);
TProviderRESTNetHTTPClient = class(TDataLoggerProvider)
private
FURL: string;
- FBearerToken: string;
FContentType: string;
- FSaveFinally: TSaveFinally;
+ FBearerToken: string;
+ FExecuteFinally: TExecuteFinally;
procedure HTTP(const AMethod: TLoggerMethod; const AItemREST: TLogItemREST);
protected
- procedure SetURL(const AURL: string);
+ property URL: string read FURL write FURL;
+ property ContentType: string read FContentType write FContentType;
+ property BearerToken: string read FBearerToken write FBearerToken;
procedure InternalSave(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
procedure InternalSaveAsync(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
- procedure SetSendFinally(const ASaveFinally: TSaveFinally);
+ procedure SetExecuteFinally(const AExecuteFinally: TExecuteFinally);
procedure Save(const ACache: TArray); override;
public
constructor Create(const AURL: string; const AContentType: string = 'text/plain'; const ABearerToken: string = '');
@@ -83,16 +85,13 @@ procedure TProviderRESTNetHTTPClient.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
if Trim(LowerCase(FContentType)) = 'application/json' then
- LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(GetLogFormat, LItem)
+ LLogItemREST.Stream := TLoggerLogFormat.AsStreamJsonObject(FLogFormat, LItem)
else
- LLogItemREST.Stream := TLoggerLogFormat.AsStream(GetLogFormat, LItem, GetFormatTimestamp);
+ LLogItemREST.Stream := TLoggerLogFormat.AsStream(FLogFormat, LItem, FFormatTimestamp);
LLogItemREST.LogItem := LItem;
@@ -102,14 +101,9 @@ procedure TProviderRESTNetHTTPClient.Save(const ACache: TArray);
InternalSaveAsync(TLoggerMethod.tlmPost, LItemREST);
end;
-procedure TProviderRESTNetHTTPClient.SetSendFinally(const ASaveFinally: TSaveFinally);
-begin
- FSaveFinally := ASaveFinally;
-end;
-
-procedure TProviderRESTNetHTTPClient.SetURL(const AURL: string);
+procedure TProviderRESTNetHTTPClient.SetExecuteFinally(const AExecuteFinally: TExecuteFinally);
begin
- FURL := AURL;
+ FExecuteFinally := AExecuteFinally;
end;
procedure TProviderRESTNetHTTPClient.InternalSave(const AMethod: TLoggerMethod; const ALogItemREST: TArray);
@@ -211,21 +205,21 @@ procedure TProviderRESTNetHTTPClient.HTTP(const AMethod: TLoggerMethod; const AI
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, AItemREST.LogItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, AItemREST.LogItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
finally
LHTTP.Free;
- if Assigned(FSaveFinally) then
- FSaveFinally(AItemREST.LogItem, LResponseContent);
+ if Assigned(FExecuteFinally) then
+ FExecuteFinally(AItemREST.LogItem, LResponseContent);
if Assigned(AItemREST.Stream) then
AItemREST.Stream.Free;
diff --git a/src/Providers/DataLogger.Provider.Redis.pas b/src/Providers/DataLogger.Provider.Redis.pas
index 1e51d22..e32b26c 100644
--- a/src/Providers/DataLogger.Provider.Redis.pas
+++ b/src/Providers/DataLogger.Provider.Redis.pas
@@ -17,13 +17,18 @@ interface
type
TProviderRedis = class(TDataLoggerProvider)
private
+ FHost: string;
+ FPort: Integer;
FKeyPrefix: string;
FMaxSize: Int64;
- FRedisClient: IRedisClient;
- FConnected: Boolean;
protected
procedure Save(const ACache: TArray); override;
public
+ property Host: string read FHost write FHost;
+ property Port: Integer read FPort write FPort;
+ property KeyPrefix: string read FKeyPrefix write FKeyPrefix;
+ property MaxSize: Int64 read FMaxSize write FMaxSize;
+
constructor Create(const AHost: string = '127.0.0.1'; const APort: Integer = 6379; const AKeyPrefix: string = 'DataLogger'; const AMaxSize: Int64 = 10000);
end;
@@ -35,15 +40,16 @@ constructor TProviderRedis.Create(const AHost: string = '127.0.0.1'; const APort
begin
inherited Create;
- FRedisClient := TRedisClient.Create(AHost, APort);
- FConnected := False;
-
+ FHost := AHost;
+ FPort := APort;
FKeyPrefix := AKeyPrefix;
FMaxSize := AMaxSize;
end;
procedure TProviderRedis.Save(const ACache: TArray);
var
+ LRedisClient: IRedisClient;
+ LConnected: Boolean;
LRetryCount: Integer;
LKey: string;
LItem: TLoggerItem;
@@ -54,60 +60,60 @@ procedure TProviderRedis.Save(const ACache: TArray);
LKey := FKeyPrefix + '::DataLoggerRedis';
+ LRedisClient := TRedisClient.Create(FHost, FPort);
+ LConnected := False;
+
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
while True do
try
- if not FConnected then
+ if not LConnected then
begin
- FRedisClient.Connect;
- FConnected := True;
+ LRedisClient.Connect;
+ LConnected := True;
end;
- FRedisClient.RPUSH(LKey, [LLog]);
+ LRedisClient.RPUSH(LKey, [LLog]);
Break;
except
on E: Exception do
begin
- if FConnected then
+ if LConnected then
begin
try
try
- FRedisClient.Disconnect;
+ LRedisClient.Disconnect;
except
end;
finally
- FConnected := False;
+ LConnected := False;
end;
end;
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
end;
try
- FRedisClient.LTRIM(LKey, -FMaxSize, -1);
+ LRedisClient.LTRIM(LKey, -FMaxSize, -1);
except
end;
end;
diff --git a/src/Providers/DataLogger.Provider.SendEmail.pas b/src/Providers/DataLogger.Provider.SendEmail.pas
index e93a807..0950f8c 100644
--- a/src/Providers/DataLogger.Provider.SendEmail.pas
+++ b/src/Providers/DataLogger.Provider.SendEmail.pas
@@ -21,7 +21,8 @@ TProviderSendEmail = class(TDataLoggerProvider)
protected
procedure Save(const ACache: TArray); override;
public
- function SendEmail: TSendEmail;
+ property SendEmail: TSendEmail read FSendEmail write FSendEmail;
+
constructor Create(const ASendEmail: TSendEmail);
end;
@@ -36,11 +37,6 @@ constructor TProviderSendEmail.Create(const ASendEmail: TSendEmail);
FSendEmail := ASendEmail;
end;
-function TProviderSendEmail.SendEmail: TSendEmail;
-begin
- Result := FSendEmail;
-end;
-
procedure TProviderSendEmail.Save(const ACache: TArray);
var
LRetryCount: Integer;
@@ -55,13 +51,10 @@ procedure TProviderSendEmail.Save(const ACache: TArray);
try
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LString.Add(LLog);
end;
@@ -82,13 +75,13 @@ procedure TProviderSendEmail.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
diff --git a/src/Providers/DataLogger.Provider.Slack.pas b/src/Providers/DataLogger.Provider.Slack.pas
index 330f91b..fcd00b0 100644
--- a/src/Providers/DataLogger.Provider.Slack.pas
+++ b/src/Providers/DataLogger.Provider.Slack.pas
@@ -12,39 +12,52 @@
interface
uses
- DataLogger.Provider.REST.HTTPClient, DataLogger.Types,
+{$IF DEFINED(DATALOGGER_SLACK_USE_INDY)}
+ DataLogger.Provider.REST.Indy,
+{$ELSEIF DEFINED(DATALOGGER_SLACK_USE_NETHTTPCLIENT)}
+ DataLogger.Provider.REST.NetHTTPClient,
+{$ELSE}
+ DataLogger.Provider.REST.HTTPClient,
+{$ENDIF}
+ DataLogger.Types,
System.SysUtils, System.Classes, System.JSON;
type
+{$IF DEFINED(DATALOGGER_SLACK_USE_INDY)}
+ TProviderSlack = class(TProviderRESTIndy)
+{$ELSEIF DEFINED(DATALOGGER_SLACK_USE_NETHTTPCLIENT)}
+ TProviderSlack = class(TProviderRESTNetHTTPClient)
+{$ELSE}
TProviderSlack = class(TProviderRESTHTTPClient)
+{$ENDIF}
private
+ FServiceName: string;
FChannel: string;
FUsername: string;
protected
procedure Save(const ACache: TArray); override;
public
- constructor Create(const AServicesName: string; const AChannel: string = ''; const AUsername: string = ''); reintroduce;
+ property Channel: string read FChannel write FChannel;
+ property Username: string read FUsername write FUsername;
+
+ constructor Create(const AServiceName: string; const AChannel: string = ''; const AUsername: string = ''); reintroduce;
end;
implementation
{ TProviderSlack }
-constructor TProviderSlack.Create(const AServicesName: string; const AChannel: string = ''; const AUsername: string = '');
-var
- LURL: string;
+constructor TProviderSlack.Create(const AServiceName: string; const AChannel: string = ''; const AUsername: string = '');
begin
- LURL := Format('https://hooks.slack.com/services/%s', [AServicesName]);
-
+ FServiceName := AServiceName;
FChannel := AChannel;
+ FUsername := AUsername;
if not FChannel.Trim.IsEmpty then
if not FChannel.StartsWith('#') then
FChannel := '#' + AChannel;
- FUsername := AUsername;
-
- inherited Create(LURL, 'application/json', '');
+ inherited Create('', 'application/json');
end;
procedure TProviderSlack.Save(const ACache: TArray);
@@ -64,26 +77,24 @@ procedure TProviderSlack.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LJO := TJSONObject.Create;
try
- LJO.AddPair('text', TJSONString.Create(LLog));
+ LJO.AddPair('text', LLog);
if not FChannel.Trim.IsEmpty then
- LJO.AddPair('channel', TJSONString.Create(FChannel));
+ LJO.AddPair('channel', FChannel);
if not FUsername.Trim.IsEmpty then
- LJO.AddPair('username', TJSONString.Create(FUsername));
+ LJO.AddPair('username', FUsername);
LLogItemREST.Stream := TStringStream.Create(LJO.ToString, TEncoding.UTF8);
LLogItemREST.LogItem := LItem;
+ LLogItemREST.URL := Format('https://hooks.slack.com/services/%s', [FServiceName]);
finally
LJO.Free;
end;
diff --git a/src/Providers/DataLogger.Provider.SysLog.pas b/src/Providers/DataLogger.Provider.SysLog.pas
index efb8882..a7ea880 100644
--- a/src/Providers/DataLogger.Provider.SysLog.pas
+++ b/src/Providers/DataLogger.Provider.SysLog.pas
@@ -84,13 +84,10 @@ procedure TProviderSysLog.Save(const ACache: TArray);
for LItem in LCache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LSysLogMessage := TIdSysLogMessage.Create(nil);
try
@@ -139,13 +136,13 @@ procedure TProviderSysLog.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;
diff --git a/src/Providers/DataLogger.Provider.Telegram.pas b/src/Providers/DataLogger.Provider.Telegram.pas
index a20cc43..58f1756 100644
--- a/src/Providers/DataLogger.Provider.Telegram.pas
+++ b/src/Providers/DataLogger.Provider.Telegram.pas
@@ -10,13 +10,27 @@
interface
uses
- DataLogger.Provider.REST.HTTPClient, DataLogger.Types,
+{$IF DEFINED(DATALOGGER_TELEGRAM_USE_INDY)}
+ DataLogger.Provider.REST.Indy,
+{$ELSEIF DEFINED(DATALOGGER_TELEGRAM_USE_NETHTTPCLIENT)}
+ DataLogger.Provider.REST.NetHTTPClient,
+{$ELSE}
+ DataLogger.Provider.REST.HTTPClient,
+{$ENDIF}
+ DataLogger.Types,
System.SysUtils, System.NetEncoding;
type
TTelegramParseMode = (tpNone, tpHTML, tpMarkdown);
+{$IF DEFINED(DATALOGGER_TELEGRAM_USE_INDY)}
+
+ TProviderTelegram = class(TProviderRESTIndy)
+{$ELSEIF DEFINED(DATALOGGER_TELEGRAM_USE_NETHTTPCLIENT)}
+ TProviderTelegram = class(TProviderRESTNetHTTPClient)
+{$ELSE}
TProviderTelegram = class(TProviderRESTHTTPClient)
+{$ENDIF}
private
FBotToken: string;
FChatId: string;
@@ -24,8 +38,11 @@ TProviderTelegram = class(TProviderRESTHTTPClient)
protected
procedure Save(const ACache: TArray); override;
public
- constructor Create(const ABotToken: string; const AChatId: string; const AParseMode: TTelegramParseMode = tpMarkdown); reintroduce; overload;
- constructor Create(const ABotToken: string; const AChatId: Double; const AParseMode: TTelegramParseMode = tpMarkdown); reintroduce; overload; deprecated 'ChatId type is string - This function will be removed in future versions';
+ property BotToken: string read FBotToken write FBotToken;
+ property ChatId: string read FChatId write FChatId;
+ property ParseMode: TTelegramParseMode read FParseMode write FParseMode;
+
+ constructor Create(const ABotToken: string; const AChatId: string; const AParseMode: TTelegramParseMode = tpMarkdown); reintroduce;
end;
implementation
@@ -47,11 +64,6 @@ constructor TProviderTelegram.Create(const ABotToken: string; const AChatId: str
inherited Create('', 'application/json');
end;
-constructor TProviderTelegram.Create(const ABotToken: string; const AChatId: Double; const AParseMode: TTelegramParseMode = tpMarkdown);
-begin
- Create(ABotToken, FloatToStr(AChatId), AParseMode);
-end;
-
procedure TProviderTelegram.Save(const ACache: TArray);
var
LItemREST: TArray;
@@ -130,14 +142,11 @@ procedure TProviderTelegram.Save(const ACache: TArray);
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
Continue;
LParseMode := '';
- LMessage := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp).Trim;
+ LMessage := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp).Trim;
if FParseMode <> tpNone then
SerializeMessageParseMode;
diff --git a/src/Providers/DataLogger.Provider.TextFile.pas b/src/Providers/DataLogger.Provider.TextFile.pas
index 09aa9c3..e9f19ee 100644
--- a/src/Providers/DataLogger.Provider.TextFile.pas
+++ b/src/Providers/DataLogger.Provider.TextFile.pas
@@ -32,14 +32,14 @@ TProviderTextFile = class(TDataLoggerProvider)
property CleanOnRun: Boolean read FCleanOnRun write FCleanOnRun;
property FormatDateTime: string read FFormatDateTime write FFormatDateTime;
- constructor Create(const ALogDir: string = ''; const APrefixFileName: string = ''; const AExtension: string = 'txt'; const ACleanOnStart: Boolean = False; const AFormatDateTime: string = 'yyyy-mm-dd');
+ constructor Create(const ALogDir: string = '.'; const APrefixFileName: string = ''; const AExtension: string = 'txt'; const ACleanOnStart: Boolean = False; const AFormatDateTime: string = 'yyyy-mm-dd');
end;
implementation
{ TProviderTextFile }
-constructor TProviderTextFile.Create(const ALogDir: string = ''; const APrefixFileName: string = ''; const AExtension: string = 'txt'; const ACleanOnStart: Boolean = False; const AFormatDateTime: string = 'yyyy-mm-dd');
+constructor TProviderTextFile.Create(const ALogDir: string = '.'; const APrefixFileName: string = ''; const AExtension: string = 'txt'; const ACleanOnStart: Boolean = False; const AFormatDateTime: string = 'yyyy-mm-dd');
begin
inherited Create;
@@ -111,7 +111,7 @@ procedure TProviderTextFile.Save(const ACache: TArray);
Sleep(100);
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
raise;
end;
end;
@@ -120,13 +120,10 @@ procedure TProviderTextFile.Save(const ACache: TArray);
try
for LItem in ACache do
begin
- if not ValidationBeforeSave(LItem) then
- Continue;
-
if LItem.&Type = TLoggerType.All then
LLog := ''
else
- LLog := TLoggerLogFormat.AsString(GetLogFormat, LItem, GetFormatTimestamp);
+ LLog := TLoggerLogFormat.AsString(FLogFormat, LItem, FFormatTimestamp);
LRetryCount := 0;
@@ -143,13 +140,13 @@ procedure TProviderTextFile.Save(const ACache: TArray);
begin
Inc(LRetryCount);
- if Assigned(LogException) then
- LogException(Self, LItem, E, LRetryCount);
+ if Assigned(FLogException) then
+ FLogException(Self, LItem, E, LRetryCount);
if Self.Terminated then
Exit;
- if LRetryCount >= GetMaxRetry then
+ if LRetryCount >= FMaxRetry then
Break;
end;
end;