Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | added TSynLog.Release method and protected the global TSynLog instances list against potential race condition |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
e2420ad79368448c5ecd726d457b76a8 |
User & Date: | User 2014-03-29 10:48:50 |
2014-03-29
| ||
11:16 | fixed Delphi 2009-XE2 compilation issue check-in: fed09df557 user: User tags: trunk | |
10:48 | added TSynLog.Release method and protected the global TSynLog instances list against potential race condition check-in: e2420ad793 user: User tags: trunk | |
10:48 | added TObjectListLocked class check-in: 7918565793 user: User tags: trunk | |
Changes to SQLite3/mORMotSelfTests.pas.
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
{$endif FPC}
procedure SQLite3ConsoleTests;
begin
AllocConsole;
TSynLogTestLog := TSQLLog; // share the same log file with whole mORMot
TSQLLog.Family.Level := LOG_STACKTRACE; // log errors by default
if false then // "if not false then" will create around 450 MB of log file
with TSQLLog.Family do begin
Level := LOG_VERBOSE;
PerThreadLog := ptIdentifiedInOnFile;
//HighResolutionTimeStamp := true;
//RotateFileCount := 5; RotateFileSizeKB := 20*1024; // rotate by 20 MB logs
end
else
|
| |
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
{$endif FPC}
procedure SQLite3ConsoleTests;
begin
AllocConsole;
TSynLogTestLog := TSQLLog; // share the same log file with whole mORMot
TSQLLog.Family.Level := LOG_STACKTRACE; // log errors by default
if false then // "if not false then" will create around 500 MB of log file
with TSQLLog.Family do begin
Level := LOG_VERBOSE;
PerThreadLog := ptIdentifiedInOnFile;
//HighResolutionTimeStamp := true;
//RotateFileCount := 5; RotateFileSizeKB := 20*1024; // rotate by 20 MB logs
end
else
|
Changes to SynCommons.pas.
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 .... 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 ..... 36799 36800 36801 36802 36803 36804 36805 36806 36807 36808 36809 36810 36811 36812 36813 36814 36815 36816 36817 ..... 36886 36887 36888 36889 36890 36891 36892 36893 36894 36895 36896 36897 36898 36899 36900 36901 36902 36903 36904 36905 36906 36907 36908 36909 36910 36911 36912 36913 36914 36915 36916 36917 36918 36919 36920 36921 36922 ..... 37192 37193 37194 37195 37196 37197 37198 37199 37200 37201 37202 37203 37204 37205 37206 37207 37208 37209 37210 37211 37212 37213 37214 37215 37216 37217 37218 37219 37220 37221 37222 37223 37224 37225 37226 37227 37228 37229 37230 37231 37232 37233 37234 37235 37236 37237 37238 37239 37240 37241 ..... 37306 37307 37308 37309 37310 37311 37312 37313 37314 37315 37316 37317 37318 37319 37320 37321 ..... 37488 37489 37490 37491 37492 37493 37494 37495 37496 37497 37498 37499 37500 37501 |
- TSynTests will now write the tests summary with colored console output - added TSynTestCase.CleanUp virtual method for proper cleaning before Destroy - added TSynTestCase.CheckMatchAny() method for multi-value checks - TSynTestCase.TestFailed now triggers a debugger breakpoint when run from IDE - TSynLog will now append only the execution time when leaving a method, without the class/method name (smaller log file, and less resource use) - TSynLog header now contains system environment variables - added TSynLog.DebuggerNotify() and TSynLog.CloseLogFile methods - introducing TSynLogFamily.StackTraceUse: TSynLogStackTraceUse property - introducing TSynLogFamily.EchoToConsole: TSynLogInfos property, able to optionally echo the process log to the current console window, using colors - if new property TSynLogFamily.PerThreadLog is set to ptIdentifiedInOnFile, a new column will be added for each logged row - LogViewer has been updated to allow easy and efficient multi-thread process logging - introducing TSynLogFamily.RotateFileCount and RotateFileSizeKB properties, ................................................................................ /// release all memory and internal handles destructor Destroy; override; /// flush all log content to file // - if ForceDiskWrite is TRUE, will wait until written on disk (slow) procedure Flush(ForceDiskWrite: boolean); /// flush all log content to file and close the file procedure CloseLogFile; {/ handle generic method enter / auto-leave tracing - this is the main method to be called within a procedure/function to trace: ! procedure TMyDB.SQLExecute(const SQL: RawUTF8); ! var ILog: ISynLog; ! begin ! ILog := TSynLogDB.Enter(self,'SQLExecute'); ! // do some stuff ................................................................................ var /// internal list of registered TSynLogFamily // - up to MAX_SYNLOGFAMILY+1 families may be defined SynLogFamily: TObjectList = nil; /// internal list of created TSynLog instance, one per each log file on disk // - do not use directly - necessary for inlining TSynLogFamily.SynLog method SynLogFile: TObjectList = nil; threadvar /// each thread can access to its own TSynLogFile // - TSynLogFile instance is SynLogFile[SynLogFileIndex[TSynLogFamily.Ident]-1] SynLogFileIndexThreadVar: TSynLogFileIndex; {$ifndef NOEXCEPTIONINTERCEPT} { ESynException } function ESynException.CustomLog(WR: TTextWriter; const Context: TSynLogExceptionContext): boolean; ................................................................................ var Index: ^TSynLogFileIndex; i: integer; ndx, n: cardinal; begin result := CurrentHandleExceptionSynLog; if (result<>nil) and result.fFamily.fHandleExceptions then exit; if SynLogFile=nil then begin // we are here is no previous log content was trigerred for i := 0 to SynLogFamily.Count-1 do with TSynLogFamily(SynLogFamily.List[i]) do if fHandleExceptions then begin result := SynLog; exit; end; end else begin Index := @SynLogFileIndexThreadVar; n := SynLogFile.Count; for i := 0 to high(Index^) do begin ndx := Index^[i]-1; if ndx<=n then begin result := TSynLog(SynLogFile.List[ndx]); if result.fFamily.fHandleExceptions then exit; end; end; for i := 0 to n-1 do begin result := TSynLog(SynLogFile.List[i]); if result.fFamily.fHandleExceptions then exit; end; end; result := nil; end; type PExceptionRecord = ^TExceptionRecord; ................................................................................ fLevelStackTrace := [sllError,sllException,sllExceptionOS,sllFail,sllLastError,sllStackTrace]; end; function TSynLogFamily.CreateSynLog: TSynLog; var i: integer; begin if SynLogFile=nil then GarbageCollectorFreeAndNil(SynLogFile,TObjectList.Create); result := fSynLogClass.Create(self); i := SynLogFile.Add(result); if (fPerThreadLog=ptOneFilePerThread) and (fRotateFileCount=0) and (fRotateFileSize=0) then SynLogFileIndexThreadVar[fIdent] := i+1 else fGlobalLog := result; end; var AutoFlushThread: THandle = 0; AutoFlushSecondElapsed: cardinal; procedure AutoFlushProc(P: pointer); stdcall; // TThread not needed here var i: integer; begin repeat Sleep(1000); // thread will awake every second to check of pending data if AutoFlushThread=0 then break; // avoid GPF if SynLogFile=nil then continue; // nothing to flush inc(AutoFlushSecondElapsed); for i := 0 to SynLogFile.Count-1 do with TSynLog(SynLogFile.List[i]) do if AutoFlushThread=0 then break else // avoid GPF if (fFamily.fAutoFlush<>0) and (fWriter<>nil) and (AutoFlushSecondElapsed mod fFamily.fAutoFlush=0) then if fWriter.B-fWriter.fTempBuf>1 then begin if not IsMultiThread and not fWriterStream.InheritsFrom(TFileStream) then IsMultiThread := true; // only TFileStream is thread-safe Flush(false); // write pending data end; until false; ExitThread(0); end; procedure TSynLogFamily.SetAutoFlush(TimeOut: cardinal); var ID: cardinal; begin ................................................................................ function TSynLogFamily.SynLog: TSynLog; var ndx: integer; begin if (fRotateFileCount=0) and (fRotateFileSize=0) and (fPerThreadLog=ptOneFilePerThread) then begin ndx := SynLogFileIndexThreadVar[fIdent]-1; if ndx>=0 then result := SynLogFile.List[ndx] else result := CreateSynLog; end else // for ptMergedInOneFile and ptIdentifiedInOnFile if fGlobalLog<>nil then result := fGlobalLog else result := CreateSynLog; {$ifndef NOEXCEPTIONINTERCEPT} if fHandleExceptions and (CurrentHandleExceptionSynLog<>result) then ................................................................................ fWriter.Flush; FreeAndNil(fWriterStream); FreeAndNil(fWriter); finally LeaveCriticalSection(fThreadLock); end; end; procedure TSynLog.Flush(ForceDiskWrite: boolean); begin if fWriter=nil then exit; EnterCriticalSection(fThreadLock); try |
| > > > > > > > > > > > > > > > > > > > > > > > | | | > > | | | | | | | | | | | | | | > > > | | > > | | | | | | > > > | > > | | | | | | | | | | | | > > > | | > > > > > > > > > > > > > > > > |
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 .... 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 ..... 36821 36822 36823 36824 36825 36826 36827 36828 36829 36830 36831 36832 36833 36834 36835 36836 36837 36838 36839 36840 ..... 36909 36910 36911 36912 36913 36914 36915 36916 36917 36918 36919 36920 36921 36922 36923 36924 36925 36926 36927 36928 36929 36930 36931 36932 36933 36934 36935 36936 36937 36938 36939 36940 36941 36942 36943 36944 36945 36946 36947 36948 36949 36950 ..... 37220 37221 37222 37223 37224 37225 37226 37227 37228 37229 37230 37231 37232 37233 37234 37235 37236 37237 37238 37239 37240 37241 37242 37243 37244 37245 37246 37247 37248 37249 37250 37251 37252 37253 37254 37255 37256 37257 37258 37259 37260 37261 37262 37263 37264 37265 37266 37267 37268 37269 37270 37271 37272 37273 37274 37275 37276 37277 37278 37279 ..... 37344 37345 37346 37347 37348 37349 37350 37351 37352 37353 37354 37355 37356 37357 37358 37359 ..... 37526 37527 37528 37529 37530 37531 37532 37533 37534 37535 37536 37537 37538 37539 37540 37541 37542 37543 37544 37545 37546 37547 37548 37549 37550 37551 37552 37553 37554 37555 |
- TSynTests will now write the tests summary with colored console output - added TSynTestCase.CleanUp virtual method for proper cleaning before Destroy - added TSynTestCase.CheckMatchAny() method for multi-value checks - TSynTestCase.TestFailed now triggers a debugger breakpoint when run from IDE - TSynLog will now append only the execution time when leaving a method, without the class/method name (smaller log file, and less resource use) - TSynLog header now contains system environment variables - added TSynLog.DebuggerNotify() and TSynLog.CloseLogFile / Release methods - protected the global TSynLog instances list against potential race condition - introducing TSynLogFamily.StackTraceUse: TSynLogStackTraceUse property - introducing TSynLogFamily.EchoToConsole: TSynLogInfos property, able to optionally echo the process log to the current console window, using colors - if new property TSynLogFamily.PerThreadLog is set to ptIdentifiedInOnFile, a new column will be added for each logged row - LogViewer has been updated to allow easy and efficient multi-thread process logging - introducing TSynLogFamily.RotateFileCount and RotateFileSizeKB properties, ................................................................................ /// release all memory and internal handles destructor Destroy; override; /// flush all log content to file // - if ForceDiskWrite is TRUE, will wait until written on disk (slow) procedure Flush(ForceDiskWrite: boolean); /// flush all log content to file and close the file procedure CloseLogFile; /// flush all log content to file, close the file, and release the instance // - you should never call the Free method directly, since the instance // is registered in a global TObjectList and an access violation may // occur at application closing: you can use this Release method if you // are sure that you won't need this TSynLog instance any more // - ensure there is no pending Leave element in a stack-allocated ISynLog // (see below) // - can be used e.g. to release the instance when finishing a thread when // Family.PerThreadLog=ptOneFilePerThread: // ! var // ! TThreadLogger : TSynLogClass = TSynLog; // ! // ! procedure TMyThread.Execute; // ! var log : ISynLog; // ! begin // ! log := TThreadLogger.Enter(self); // ! ... // ! log := nil; // to force logging end of method // ! TThreadLogger.SynLog.Release; // ! end; procedure Release; {/ handle generic method enter / auto-leave tracing - this is the main method to be called within a procedure/function to trace: ! procedure TMyDB.SQLExecute(const SQL: RawUTF8); ! var ILog: ISynLog; ! begin ! ILog := TSynLogDB.Enter(self,'SQLExecute'); ! // do some stuff ................................................................................ var /// internal list of registered TSynLogFamily // - up to MAX_SYNLOGFAMILY+1 families may be defined SynLogFamily: TObjectList = nil; /// internal list of created TSynLog instance, one per each log file on disk // - do not use directly - necessary for inlining TSynLogFamily.SynLog method // - also used by AutoFlushProc() to get a global list of TSynLog instances SynLogFileList: TObjectListLocked = nil; threadvar /// each thread can access to its own TSynLogFile // - TSynLogFile instance is SynLogFileList[SynLogFileIndex[TSynLogFamily.Ident]-1] SynLogFileIndexThreadVar: TSynLogFileIndex; {$ifndef NOEXCEPTIONINTERCEPT} { ESynException } function ESynException.CustomLog(WR: TTextWriter; const Context: TSynLogExceptionContext): boolean; ................................................................................ var Index: ^TSynLogFileIndex; i: integer; ndx, n: cardinal; begin result := CurrentHandleExceptionSynLog; if (result<>nil) and result.fFamily.fHandleExceptions then exit; if SynLogFileList=nil then begin // we are here is no previous log content was trigerred for i := 0 to SynLogFamily.Count-1 do with TSynLogFamily(SynLogFamily.List[i]) do if fHandleExceptions then begin result := SynLog; exit; end; end else begin SynLogFileList.Lock; try Index := @SynLogFileIndexThreadVar; n := SynLogFileList.Count; for i := 0 to high(Index^) do begin ndx := Index^[i]-1; if ndx<=n then begin result := TSynLog(SynLogFileList.List[ndx]); if result.fFamily.fHandleExceptions then exit; end; end; for i := 0 to n-1 do begin result := TSynLog(SynLogFileList.List[i]); if result.fFamily.fHandleExceptions then exit; end; finally SynLogFileList.UnLock; end; end; result := nil; end; type PExceptionRecord = ^TExceptionRecord; ................................................................................ fLevelStackTrace := [sllError,sllException,sllExceptionOS,sllFail,sllLastError,sllStackTrace]; end; function TSynLogFamily.CreateSynLog: TSynLog; var i: integer; begin if SynLogFileList=nil then GarbageCollectorFreeAndNil(SynLogFileList,TObjectListLocked.Create); SynLogFileList.Lock; try result := fSynLogClass.Create(self); i := SynLogFileList.Add(result); if (fPerThreadLog=ptOneFilePerThread) and (fRotateFileCount=0) and (fRotateFileSize=0) then SynLogFileIndexThreadVar[fIdent] := i+1 else fGlobalLog := result; finally SynLogFileList.UnLock; end; end; var AutoFlushThread: THandle = 0; AutoFlushSecondElapsed: cardinal; procedure AutoFlushProc(P: pointer); stdcall; // TThread not needed here var i: integer; begin repeat Sleep(1000); // thread will awake every second to check of pending data if AutoFlushThread=0 then break; // avoid GPF if SynLogFileList=nil then continue; // nothing to flush inc(AutoFlushSecondElapsed); SynLogFileList.Lock; try for i := 0 to SynLogFileList.Count-1 do with TSynLog(SynLogFileList.List[i]) do if AutoFlushThread=0 then break else // avoid GPF if (fFamily.fAutoFlush<>0) and (fWriter<>nil) and (AutoFlushSecondElapsed mod fFamily.fAutoFlush=0) then if fWriter.B-fWriter.fTempBuf>1 then begin if not IsMultiThread and not fWriterStream.InheritsFrom(TFileStream) then IsMultiThread := true; // only TFileStream is thread-safe Flush(false); // write pending data end; finally SynLogFileList.UnLock; end; until false; ExitThread(0); end; procedure TSynLogFamily.SetAutoFlush(TimeOut: cardinal); var ID: cardinal; begin ................................................................................ function TSynLogFamily.SynLog: TSynLog; var ndx: integer; begin if (fRotateFileCount=0) and (fRotateFileSize=0) and (fPerThreadLog=ptOneFilePerThread) then begin ndx := SynLogFileIndexThreadVar[fIdent]-1; if ndx>=0 then // SynLogFileList.Lock/Unlock is not mandatory here result := SynLogFileList.List[ndx] else result := CreateSynLog; end else // for ptMergedInOneFile and ptIdentifiedInOnFile if fGlobalLog<>nil then result := fGlobalLog else result := CreateSynLog; {$ifndef NOEXCEPTIONINTERCEPT} if fHandleExceptions and (CurrentHandleExceptionSynLog<>result) then ................................................................................ fWriter.Flush; FreeAndNil(fWriterStream); FreeAndNil(fWriter); finally LeaveCriticalSection(fThreadLock); end; end; procedure TSynLog.Release; begin SynLogFileList.Lock; try CloseLogFile; SynLogFileList.Remove(self); with fFamily do if (fPerThreadLog=ptOneFilePerThread) and (fRotateFileCount=0) and (fRotateFileSize=0) then SynLogFileIndexThreadVar[fIdent] := 0; finally SynLogFileList.Unlock; end; Free; end; procedure TSynLog.Flush(ForceDiskWrite: boolean); begin if fWriter=nil then exit; EnterCriticalSection(fThreadLock); try |