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 + + +
Form2
+ 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;