BrookLogger.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. (* _ _
  2. * | |__ _ __ ___ ___ | | __
  3. * | '_ \| '__/ _ \ / _ \| |/ /
  4. * | |_) | | | (_) | (_) | <
  5. * |_.__/|_| \___/ \___/|_|\_\
  6. *
  7. * Microframework which helps to develop web Pascal applications.
  8. *
  9. * Copyright (c) 2012-2021 Silvio Clecio <[email protected]>
  10. *
  11. * Brook framework is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation; either
  14. * version 2.1 of the License, or (at your option) any later version.
  15. *
  16. * Brook framework is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with Brook framework; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *)
  25. { Contains classes for basic logging. }
  26. unit BrookLogger;
  27. {$I BrookDefines.inc}
  28. interface
  29. uses
  30. RTLConsts,
  31. {$IFDEF FPC}
  32. Math,
  33. {$ELSE}
  34. Types,
  35. IOUtils,
  36. {$ENDIF}
  37. SysUtils,
  38. DateUtils,
  39. Classes,
  40. BrookExtra;
  41. const
  42. { Default logger name. }
  43. BROOK_LOGGER_OUTPUT_NAME = 'Console';
  44. { Default logger tag. }
  45. BROOK_LOGGER_TAG = 'BrookLogger_';
  46. resourcestring
  47. { Error message @code('Empty output name.'). }
  48. SBrookEmptyOutputName = 'Empty output name.';
  49. { Error message @code('Active output log.'). }
  50. SBrookActiveOutput = 'Active output log.';
  51. { Error message @code('Inactive output log.'). }
  52. SBrookInactiveOutput = 'Inactive output log.';
  53. { Error message @code('Invalid output class: <class-name>.'). }
  54. SBrookInvalidOutputClass = 'Invalid output class: %s.';
  55. { Error message @code('Unknown output name: <output-name>.'). }
  56. SBrookUnknownOutputName = 'Unknown output name: %s.';
  57. { Name for information log level. }
  58. SBrookLevelInfo = 'INFO';
  59. { Name for hint log level. }
  60. SBrookLevelHint = 'HINT';
  61. { Name for warning log level. }
  62. SBrookLevelWarn = 'WARN';
  63. { Name for debug log level. }
  64. SBrookLevelDebug = 'DEBUG';
  65. { Name for error log level. }
  66. SBrookLevelError = 'ERROR';
  67. type
  68. { Abstract class for logger output. }
  69. TBrookLoggerOutput = class abstract(TPersistent)
  70. private
  71. FFilters: TStringList;
  72. FOptions: TStringList;
  73. class function InternalFormat(const ALevel,
  74. AMessage: string): string; {$IFNDEF DEBUG}inline;{$ENDIF}
  75. protected
  76. class function FormatLog(const ALevel, AMessage: string): string; virtual;
  77. class function FormatFail(const ALevel: string;
  78. AException: Exception): string; virtual;
  79. public
  80. { Creates an instance of @code(TBrookLoggerOutput).
  81. @param(AFilters[in] Filters to be assigned to the logger instance.)
  82. @param(AOptions[in] Options to be assigned to the logger instance.) }
  83. constructor Create(AFilters, AOptions: TStringList); virtual;
  84. { Returns the alias name for output source.
  85. @returns(Output source alias.) }
  86. class function GetRegisterAlias: string; virtual;
  87. { Returns the name for output source.
  88. @returns(Output source name.) }
  89. class function GetName: string; virtual; abstract;
  90. { Returns @True if a certain log level is filtered.
  91. @param(ALevel[in] Log level.) }
  92. function IsFiltered(const ALevel: string): Boolean; virtual;
  93. { Appends a message to the output log.
  94. @param(ALevel[in] Log level.)
  95. @param(AMessage[in] Log message.) }
  96. procedure Log(const ALevel, AMessage: string); virtual; abstract;
  97. { Appends an exception message to the output log.
  98. @param(ALevel[in] Log level.)
  99. @param(AException[in] Log exception.) }
  100. procedure Fail(const ALevel: string;
  101. AException: Exception); virtual; abstract;
  102. { List containing the filtered log levels. }
  103. property Filters: TStringList read FFilters;
  104. { List containing additional options to the output. }
  105. property Options: TStringList read FOptions;
  106. end;
  107. { Class-reference for @code(TBrookLoggerOutput). }
  108. TBrookLoggerOutputClass = class of TBrookLoggerOutput;
  109. { Class for console logger output. }
  110. TBrookLoggerOutputConsole = class(TBrookLoggerOutput)
  111. public
  112. { Returns the name for output source.
  113. @returns(Output source name.) }
  114. class function GetName: string; override;
  115. { Appends a message to the output log.
  116. @param(ALevel[in] Log level.)
  117. @param(AMessage[in] Log message.) }
  118. procedure Log(const ALevel, AMessage: string); override;
  119. { Appends an exception message to the output log.
  120. @param(ALevel[in] Log level.)
  121. @param(AException[in] Log exception.) }
  122. procedure Fail(const ALevel: string; AException: Exception); override;
  123. end;
  124. { Class for file logger output. }
  125. TBrookLoggerOutputFile = class(TBrookLoggerOutput)
  126. private
  127. FHandle: TFileStream;
  128. FEncoding: TEncoding;
  129. FLastDate: TDate;
  130. FDirectory: string;
  131. FFileName: TFileName;
  132. procedure SetDirectory(const AValue: string);
  133. protected
  134. function CreateFile(AEncoding: TEncoding;
  135. const AFileName: TFileName): TFileStream; overload; virtual;
  136. function CreateFile(
  137. const AFileName: TFileName): TFileStream; overload; virtual;
  138. function RecreateFile(const AFileName: TFileName): TFileStream; virtual;
  139. procedure UpgradeFileName; virtual;
  140. procedure UpgradeFile; virtual;
  141. procedure WriteLog(const AMsg: string); {$IFNDEF DEBUG}inline;{$ENDIF}
  142. property LastDate: TDate read FLastDate;
  143. property Handle: TFileStream read FHandle;
  144. public
  145. { Method triggered after the constructor is called. }
  146. procedure AfterConstruction; override;
  147. { Destroys an instance of @code(TBrookLoggerOutputFile). }
  148. destructor Destroy; override;
  149. { Returns the name for output source.
  150. @returns(Output source name.) }
  151. class function GetName: string; override;
  152. { Appends a message to the output log.
  153. @param(ALevel[in] Log level.)
  154. @param(AMessage[in] Log message.) }
  155. procedure Log(const ALevel, AMessage: string); override;
  156. { Appends an exception message to the output log.
  157. @param(ALevel[in] Log level.)
  158. @param(AException[in] Log exception.) }
  159. procedure Fail(const ALevel: string; AException: Exception); override;
  160. { Specifies the output directory containing the logs. }
  161. property Directory: string read FDirectory write SetDirectory;
  162. { Generated absolute filename for the log. }
  163. property FileName: TFileName read FFileName;
  164. end;
  165. { Class that retains the log levels. }
  166. TBrookLoggerLevels = class(TPersistent)
  167. private
  168. FInfo: string;
  169. FHint: string;
  170. FWarn: string;
  171. FDebug: string;
  172. FError: string;
  173. function IsInfoStored: Boolean;
  174. function IsHintStored: Boolean;
  175. function IsWarnStored: Boolean;
  176. function IsDebugStored: Boolean;
  177. function IsErrorStored: Boolean;
  178. public
  179. { Creates an instance of @code(TBrookLoggerLevels). }
  180. constructor Create; virtual;
  181. { Copies the properties of the source levels.
  182. @param(ASource[in] Levels source to be copied.) }
  183. procedure Assign(ASource: TPersistent); override;
  184. published
  185. { Level message for information log. }
  186. property Info: string read FInfo write FInfo stored IsInfoStored;
  187. { Level message for hint log. }
  188. property Hint: string read FHint write FHint stored IsHintStored;
  189. { Level message for warning log. }
  190. property Warn: string read FWarn write FWarn stored IsWarnStored;
  191. { Level message for debug log. }
  192. property Debug: string read FDebug write FDebug stored IsDebugStored;
  193. { Level message for error log. }
  194. property Error: string read FError write FError stored IsErrorStored;
  195. end;
  196. { Component that writes log to a predefined output type. }
  197. TBrookLogger = class(TComponent)
  198. private
  199. FOutput: TBrookLoggerOutput;
  200. FFilters: TStringList;
  201. FOptions: TStringList;
  202. FLevels: TBrookLoggerLevels;
  203. FOutputName: string;
  204. FStreamedActive: Boolean;
  205. FActive: Boolean;
  206. function GetOutput: TBrookLoggerOutput;
  207. procedure SetActive(AValue: Boolean);
  208. procedure SetOutputName(const AValue: string);
  209. function IsActiveStored: Boolean;
  210. function IsOutputNameStored: Boolean;
  211. procedure SetFilters(AValue: TStringList);
  212. procedure SetOptions(AValue: TStringList);
  213. protected
  214. procedure Loaded; override;
  215. function CreateFilters: TStringList; virtual;
  216. function CreateOptions: TStringList; virtual;
  217. function CreateOutput(AFilters,
  218. AOptions: TStringList): TBrookLoggerOutput; virtual;
  219. function CreateLevels: TBrookLoggerLevels; virtual;
  220. procedure DoOpen; virtual;
  221. procedure DoClose; virtual;
  222. procedure CheckActive; {$IFNDEF DEBUG}inline;{$ENDIF}
  223. procedure CheckInactive; {$IFNDEF DEBUG}inline;{$ENDIF}
  224. procedure CheckOutputName; {$IFNDEF DEBUG}inline;{$ENDIF}
  225. public
  226. { Creates an instance of @code(TBrookLogger).
  227. @param(AOwner[in] Owner component.) }
  228. constructor Create(AOwner: TComponent); override;
  229. { Destroys an instance of @code(TBrookLogger). }
  230. destructor Destroy; override;
  231. { Gets an output log class from the classes register. }
  232. function GetOutputClass: TBrookLoggerOutputClass;
  233. {$IFNDEF DEBUG}inline;{$ENDIF}
  234. { Enabled the logger component. }
  235. procedure Open;
  236. { Disables the logger component. }
  237. procedure Close;
  238. { Appends a message to the output log.
  239. @param(ALevel[in] Log level.)
  240. @param(AMessage[in] Log message.) }
  241. procedure Log(const ALevel, AMessage: string);
  242. {$IFNDEF DEBUG}inline;{$ENDIF}
  243. { Appends an exception message to the output log.
  244. @param(ALevel[in] Log level.)
  245. @param(AException[in] Log exception.) }
  246. procedure Fail(const ALevel: string; AException: Exception);
  247. {$IFNDEF DEBUG}inline;{$ENDIF}
  248. { Appends a message to the output log as information level.
  249. @param(AMessage[in] Log message.) }
  250. procedure Info(const AMessage: string); {$IFNDEF DEBUG}inline;{$ENDIF}
  251. { Appends a message to the output log as hint level.
  252. @param(AMessage[in] Log message.) }
  253. procedure Hint(const AMessage: string); {$IFNDEF DEBUG}inline;{$ENDIF}
  254. { Appends a message to the output log as warning level.
  255. @param(AMessage[in] Log message.) }
  256. procedure Warn(const AMessage: string); {$IFNDEF DEBUG}inline;{$ENDIF}
  257. { Appends a message to the output log as debug level.
  258. @param(AMessage[in] Log message.) }
  259. procedure Debug(const AMessage: string); {$IFNDEF DEBUG}inline;{$ENDIF}
  260. { Appends a message to the output log as error level.
  261. @param(AMessage[in] Log message.) }
  262. procedure Error(AException: Exception); {$IFNDEF DEBUG}inline;{$ENDIF}
  263. { Current active log output. }
  264. property Output: TBrookLoggerOutput read GetOutput;
  265. published
  266. { Activates the logger component. }
  267. property Active: Boolean read FActive write SetActive stored IsActiveStored;
  268. { Retains the log levels. }
  269. property Levels: TBrookLoggerLevels read FLevels write FLevels;
  270. { Name of the chosen output type. }
  271. property OutputName: string read FOutputName write SetOutputName
  272. stored IsOutputNameStored;
  273. { List containing the filtered log levels. }
  274. property Filters: TStringList read FFilters write SetFilters;
  275. { List containing additional options to the chosen output. }
  276. property Options: TStringList read FOptions write SetOptions;
  277. end;
  278. implementation
  279. { TBrookLoggerOutput }
  280. constructor TBrookLoggerOutput.Create(AFilters, AOptions: TStringList);
  281. begin
  282. inherited Create;
  283. if not Assigned(AFilters) then
  284. raise EArgumentNilException.CreateFmt(SParamIsNil, ['AFilters']);
  285. if not Assigned(AOptions) then
  286. raise EArgumentNilException.CreateFmt(SParamIsNil, ['AOptions']);
  287. FFilters := AFilters;
  288. FOptions := AOptions;
  289. end;
  290. class function TBrookLoggerOutput.GetRegisterAlias: string;
  291. begin
  292. Result := Concat(BROOK_LOGGER_TAG, GetName);
  293. end;
  294. class function TBrookLoggerOutput.InternalFormat(const ALevel,
  295. AMessage: string): string;
  296. begin
  297. Result := Concat(FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now), ' ', ALevel,
  298. ': ', AMessage.TrimRight);
  299. end;
  300. class function TBrookLoggerOutput.FormatLog(const ALevel,
  301. AMessage: string): string;
  302. begin
  303. Result := InternalFormat(ALevel, AMessage);
  304. end;
  305. class function TBrookLoggerOutput.FormatFail(const ALevel: string;
  306. AException: Exception): string;
  307. begin
  308. if not Assigned(AException) then
  309. raise EArgumentNilException.CreateFmt(SParamIsNil, ['AException']);
  310. Result := FormatLog(ALevel, Concat(AException.ClassName, ': ',
  311. AException.Message));
  312. end;
  313. function TBrookLoggerOutput.IsFiltered(const ALevel: string): Boolean;
  314. begin
  315. Result := FFilters.IndexOf(ALevel) > -1;
  316. end;
  317. { TBrookLoggerOutputConsole }
  318. class function TBrookLoggerOutputConsole.GetName: string;
  319. begin
  320. Result := 'Console';
  321. end;
  322. procedure TBrookLoggerOutputConsole.Log(const ALevel, AMessage: string);
  323. begin
  324. if IsConsole and not IsFiltered(ALevel) then
  325. WriteLn(Output, FormatLog(ALevel, AMessage));
  326. end;
  327. procedure TBrookLoggerOutputConsole.Fail(const ALevel: string;
  328. AException: Exception);
  329. begin
  330. if IsConsole and not IsFiltered(ALevel) then
  331. WriteLn(ErrOutput, FormatFail(ALevel, AException));
  332. end;
  333. { TBrookLoggerOutputFile }
  334. procedure TBrookLoggerOutputFile.AfterConstruction;
  335. begin
  336. inherited AfterConstruction;
  337. if not FDirectory.IsEmpty then
  338. Exit;
  339. FDirectory := FOptions.Values['Directory'];
  340. if FDirectory.IsEmpty then
  341. FDirectory :=
  342. {$IFDEF FPC}
  343. GetUserDir
  344. {$ELSE}
  345. TPath.GetHomePath
  346. {$ENDIF};
  347. UpgradeFileName;
  348. end;
  349. destructor TBrookLoggerOutputFile.Destroy;
  350. begin
  351. FHandle.Free;
  352. inherited Destroy;
  353. end;
  354. function TBrookLoggerOutputFile.CreateFile(AEncoding: TEncoding;
  355. const AFileName: TFileName): TFileStream;
  356. var
  357. VMode: Word;
  358. begin
  359. FEncoding := AEncoding;
  360. if not Assigned(FEncoding) then
  361. FEncoding := TEncoding.UTF8;
  362. if FileExists(AFileName) then
  363. VMode := fmOpenReadWrite
  364. else
  365. VMode := fmCreate;
  366. VMode := VMode or fmShareDenyWrite;
  367. Result := TFileStream.Create(AFileName, VMode, BROOK_FILE_RIGHTS);
  368. end;
  369. function TBrookLoggerOutputFile.CreateFile(
  370. const AFileName: TFileName): TFileStream;
  371. begin
  372. Result := CreateFile(TEncoding.UTF8, AFileName);
  373. end;
  374. function TBrookLoggerOutputFile.RecreateFile(
  375. const AFileName: TFileName): TFileStream;
  376. begin
  377. FHandle.Free;
  378. Result := CreateFile(FEncoding, AFileName);
  379. end;
  380. procedure TBrookLoggerOutputFile.UpgradeFileName;
  381. var
  382. VDate: TDate;
  383. begin
  384. VDate := Date;
  385. if CompareDateTime(IncDay(FLastDate), VDate) <> LessThanValue then
  386. Exit;
  387. FLastDate := VDate;
  388. FFileName := Concat(IncludeTrailingPathDelimiter(FDirectory),
  389. ChangeFileExt(ExtractFileName(ParamStr(0)), ''), '_',
  390. FormatDateTime('yyyymmdd', FLastDate), '.log');
  391. end;
  392. procedure TBrookLoggerOutputFile.UpgradeFile;
  393. begin
  394. if not FDirectory.IsEmpty then
  395. ForceDirectories(FDirectory);
  396. UpgradeFileName;
  397. FHandle := RecreateFile(FFileName);
  398. end;
  399. procedure TBrookLoggerOutputFile.SetDirectory(const AValue: string);
  400. begin
  401. if AValue = FDirectory then
  402. Exit;
  403. FDirectory := AValue;
  404. FLastDate := 0;
  405. end;
  406. procedure TBrookLoggerOutputFile.WriteLog(const AMsg: string);
  407. var
  408. VBuffer: TBytes;
  409. begin
  410. if not Assigned(FHandle) then
  411. Exit;
  412. VBuffer := FEncoding.GetBytes(
  413. {$IFDEF FPC}UnicodeString({$ENDIF}Concat(AMsg, sLineBreak){$IFDEF FPC}){$ENDIF});
  414. FHandle.Seek(0, TSeekOrigin.soEnd);
  415. FHandle.WriteBuffer(VBuffer[0], FEncoding.GetCharCount(VBuffer));
  416. end;
  417. class function TBrookLoggerOutputFile.GetName: string;
  418. begin
  419. Result := 'File';
  420. end;
  421. procedure TBrookLoggerOutputFile.Log(const ALevel, AMessage: string);
  422. begin
  423. if IsFiltered(ALevel) then
  424. Exit;
  425. UpgradeFile;
  426. WriteLog(FormatLog(ALevel, AMessage));
  427. end;
  428. procedure TBrookLoggerOutputFile.Fail(const ALevel: string;
  429. AException: Exception);
  430. begin
  431. if IsFiltered(ALevel) then
  432. Exit;
  433. UpgradeFile;
  434. WriteLog(FormatFail(ALevel, AException));
  435. end;
  436. { TBrookLoggerLevels }
  437. constructor TBrookLoggerLevels.Create;
  438. begin
  439. inherited Create;
  440. FInfo := SBrookLevelInfo;
  441. FHint := SBrookLevelHint;
  442. FWarn := SBrookLevelWarn;
  443. FDebug := SBrookLevelDebug;
  444. FError := SBrookLevelError;
  445. end;
  446. procedure TBrookLoggerLevels.Assign(ASource: TPersistent);
  447. var
  448. VSrc: TBrookLoggerLevels;
  449. begin
  450. if ASource is TBrookLoggerLevels then
  451. begin
  452. VSrc := ASource as TBrookLoggerLevels;
  453. FInfo := VSrc.Info;
  454. FHint := VSrc.Hint;
  455. FWarn := VSrc.Warn;
  456. FDebug := VSrc.Debug;
  457. FError := VSrc.Error;
  458. end
  459. else
  460. inherited Assign(ASource);
  461. end;
  462. function TBrookLoggerLevels.IsInfoStored: Boolean;
  463. begin
  464. Result := FInfo <> SBrookLevelInfo;
  465. end;
  466. function TBrookLoggerLevels.IsHintStored: Boolean;
  467. begin
  468. Result := FHint <> SBrookLevelHint;
  469. end;
  470. function TBrookLoggerLevels.IsWarnStored: Boolean;
  471. begin
  472. Result := FWarn <> SBrookLevelWarn;
  473. end;
  474. function TBrookLoggerLevels.IsDebugStored: Boolean;
  475. begin
  476. Result := FDebug <> SBrookLevelDebug;
  477. end;
  478. function TBrookLoggerLevels.IsErrorStored: Boolean;
  479. begin
  480. Result := FError <> SBrookLevelError;
  481. end;
  482. { TBrookLogger }
  483. constructor TBrookLogger.Create(AOwner: TComponent);
  484. begin
  485. inherited Create(AOwner);
  486. FLevels := CreateLevels;
  487. FFilters := CreateFilters;
  488. FOptions := CreateOptions;
  489. FOutputName := BROOK_LOGGER_OUTPUT_NAME;
  490. end;
  491. destructor TBrookLogger.Destroy;
  492. begin
  493. SetActive(False);
  494. FLevels.Free;
  495. FOptions.Free;
  496. FFilters.Free;
  497. inherited Destroy;
  498. end;
  499. function TBrookLogger.CreateFilters: TStringList;
  500. begin
  501. Result := TStringList.Create;
  502. Result.Add(FLevels.Info);
  503. Result.Add(FLevels.Hint);
  504. Result.Add(FLevels.Debug);
  505. end;
  506. function TBrookLogger.CreateOptions: TStringList;
  507. begin
  508. Result := TStringList.Create;
  509. end;
  510. function TBrookLogger.GetOutputClass: TBrookLoggerOutputClass;
  511. var
  512. C: TPersistentClass;
  513. N: string;
  514. begin
  515. N := Concat(BROOK_LOGGER_TAG, FOutputName);
  516. C := Classes.GetClass(N);
  517. if not Assigned(C) then
  518. raise EClassNotFound.CreateFmt(SBrookUnknownOutputName, [FOutputName]);
  519. if not C.InheritsFrom(TBrookLoggerOutput) then
  520. raise EInvalidCast.CreateFmt(SBrookInvalidOutputClass, [C.ClassName]);
  521. Result := TBrookLoggerOutputClass(C);
  522. end;
  523. function TBrookLogger.CreateOutput(AFilters,
  524. AOptions: TStringList): TBrookLoggerOutput;
  525. begin
  526. Result := GetOutputClass.Create(AFilters, AOptions);
  527. end;
  528. function TBrookLogger.CreateLevels: TBrookLoggerLevels;
  529. begin
  530. Result := TBrookLoggerLevels.Create;
  531. end;
  532. procedure TBrookLogger.CheckOutputName;
  533. begin
  534. if FOutputName.IsEmpty then
  535. raise EArgumentException.Create(SBrookEmptyOutputName);
  536. end;
  537. procedure TBrookLogger.CheckActive;
  538. begin
  539. if not Active then
  540. raise EInvalidOpException.Create(SBrookInactiveOutput);
  541. end;
  542. procedure TBrookLogger.CheckInactive;
  543. begin
  544. if (not (csLoading in ComponentState)) and Active then
  545. raise EInvalidOpException.Create(SBrookActiveOutput);
  546. end;
  547. procedure TBrookLogger.Loaded;
  548. begin
  549. inherited Loaded;
  550. try
  551. if FStreamedActive then
  552. SetActive(True);
  553. except
  554. if csDesigning in ComponentState then
  555. begin
  556. if Assigned(ApplicationHandleException) then
  557. ApplicationHandleException(ExceptObject)
  558. else
  559. ShowException(ExceptObject, ExceptAddr);
  560. end
  561. else
  562. raise;
  563. end;
  564. end;
  565. procedure TBrookLogger.DoOpen;
  566. begin
  567. if Assigned(FOutput) then
  568. Exit;
  569. CheckOutputName;
  570. FOutput := CreateOutput(FFilters, FOptions);
  571. FActive := True;
  572. end;
  573. procedure TBrookLogger.DoClose;
  574. begin
  575. if not Assigned(FOutput) then
  576. Exit;
  577. FOutput.Destroy;
  578. FOutput := nil;
  579. FActive := False;
  580. end;
  581. function TBrookLogger.IsActiveStored: Boolean;
  582. begin
  583. Result := FActive;
  584. end;
  585. function TBrookLogger.GetOutput: TBrookLoggerOutput;
  586. begin
  587. CheckActive;
  588. Result := FOutput;
  589. end;
  590. function TBrookLogger.IsOutputNameStored: Boolean;
  591. begin
  592. Result := FOutputName <> BROOK_LOGGER_OUTPUT_NAME;
  593. end;
  594. procedure TBrookLogger.SetActive(AValue: Boolean);
  595. begin
  596. if AValue = FActive then
  597. Exit;
  598. if csDesigning in ComponentState then
  599. FActive := AValue
  600. else
  601. if AValue then
  602. begin
  603. if csReading in ComponentState then
  604. FStreamedActive := True
  605. else
  606. DoOpen;
  607. end
  608. else
  609. DoClose;
  610. end;
  611. procedure TBrookLogger.SetFilters(AValue: TStringList);
  612. begin
  613. FFilters.Assign(AValue);
  614. end;
  615. procedure TBrookLogger.SetOptions(AValue: TStringList);
  616. begin
  617. FOptions.Assign(AValue);
  618. end;
  619. procedure TBrookLogger.SetOutputName(const AValue: string);
  620. begin
  621. if FOutputName = AValue then
  622. Exit;
  623. if not FStreamedActive then
  624. CheckInactive;
  625. FOutputName := AValue;
  626. if FOutputName.IsEmpty then
  627. FOutputName := BROOK_LOGGER_OUTPUT_NAME;
  628. end;
  629. procedure TBrookLogger.Open;
  630. begin
  631. SetActive(True);
  632. end;
  633. procedure TBrookLogger.Close;
  634. begin
  635. SetActive(False);
  636. end;
  637. procedure TBrookLogger.Log(const ALevel, AMessage: string);
  638. begin
  639. if Active then
  640. Output.Log(ALevel, AMessage);
  641. end;
  642. procedure TBrookLogger.Fail(const ALevel: string; AException: Exception);
  643. begin
  644. if Active then
  645. Output.Fail(ALevel, AException);
  646. end;
  647. procedure TBrookLogger.Info(const AMessage: string);
  648. begin
  649. Log(FLevels.Info, AMessage);
  650. end;
  651. procedure TBrookLogger.Hint(const AMessage: string);
  652. begin
  653. Log(FLevels.Hint, AMessage);
  654. end;
  655. procedure TBrookLogger.Warn(const AMessage: string);
  656. begin
  657. Log(FLevels.Warn, AMessage);
  658. end;
  659. procedure TBrookLogger.Debug(const AMessage: string);
  660. begin
  661. Log(FLevels.Debug, AMessage);
  662. end;
  663. procedure TBrookLogger.Error(AException: Exception);
  664. begin
  665. Fail(FLevels.Error, AException);
  666. end;
  667. initialization
  668. RegisterClassAlias(TBrookLoggerOutputConsole,
  669. TBrookLoggerOutputConsole.GetRegisterAlias);
  670. RegisterClassAlias(TBrookLoggerOutputFile,
  671. TBrookLoggerOutputFile.GetRegisterAlias);
  672. finalization
  673. UnregisterClass(TBrookLoggerOutputConsole);
  674. UnregisterClass(TBrookLoggerOutputFile);
  675. end.