eventlog.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2003 by the Free Pascal development team
  4. Cross-platform event logging facility.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. unit eventlog;
  14. interface
  15. uses SysUtils,Classes;
  16. Type
  17. TEventLog = Class;
  18. TLogType = (ltSystem,ltFile,ltStdOut,ltStdErr);
  19. TLogCodeEvent = Procedure (Sender : TObject; Var Code : DWord) of Object;
  20. TLogCategoryEvent = Procedure (Sender : TObject; Var Code : Word) of Object;
  21. TLogMessageEvent = Procedure (Sender : TObject; EventType : TEventType; Const Msg : String) of Object;
  22. TEventLog = Class(TComponent)
  23. Private
  24. fAppendContent : Boolean;
  25. FEventIDOffset : DWord;
  26. FLogHandle : Pointer;
  27. FStream : TFileStream;
  28. FActive: Boolean;
  29. FRaiseExceptionOnError: Boolean;
  30. FIdentification: String;
  31. FDefaultEventType: TEventType;
  32. FLogtype: TLogType;
  33. FFileName: String;
  34. FTimeStampFormat: String;
  35. FCustomLogType: Word;
  36. FOnGetCustomCategory : TLogCategoryEvent;
  37. FOnGetCustomEventID : TLogCodeEvent;
  38. FOnGetCustomEvent : TLogCodeEvent;
  39. FOnLogMessage: TLogMessageEvent;
  40. FPaused : Boolean;
  41. procedure SetActive(const Value: Boolean);
  42. procedure SetIdentification(const Value: String);
  43. procedure SetlogType(const Value: TLogType);
  44. procedure ActivateLog;
  45. procedure DeActivateLog;
  46. procedure ActivateFileLog;
  47. procedure SetFileName(const Value: String);
  48. procedure ActivateIOLog;
  49. procedure ActivateSystemLog;
  50. function DefaultFileName: String;
  51. function FormatLogMessage(EventType : TEventType; const Msg: String): String;
  52. procedure WriteFileLog(EventType : TEventType; const Msg: String);
  53. procedure WriteSystemLog(EventType: TEventType; const Msg: String);
  54. procedure WriteIOLog(EventType: TEventType; const Msg: String; var OutFile: TextFile);
  55. procedure DeActivateFileLog;
  56. procedure DeActivateSystemLog;
  57. procedure CheckIdentification;
  58. Procedure DoGetCustomEventID(Var Code : DWord);
  59. Procedure DoGetCustomEventCategory(Var Code : Word);
  60. Procedure DoGetCustomEvent(Var Code : DWord);
  61. Procedure DoLogMessage(EventType : TEventType; const Msg: String);
  62. Protected
  63. Procedure CheckInactive;
  64. Procedure EnsureActive;
  65. function MapTypeToEvent(EventType: TEventType): DWord;
  66. Function MapTypeToCategory(EventType : TEventType) : Word;
  67. Function MapTypeToEventID(EventType : TEventType) : DWord;
  68. Public
  69. Destructor Destroy; override;
  70. Function EventTypeToString(E : TEventType) : String;
  71. Function RegisterMessageFile(AFileName : String) : Boolean; virtual;
  72. Function UnRegisterMessageFile : Boolean; virtual;
  73. Procedure Pause;
  74. Procedure Resume;
  75. Procedure Log (EventType : TEventType; const Msg : String); {$ifndef fpc }Overload;{$endif}
  76. Procedure Log (EventType : TEventType; const Fmt : String; Args : Array of const); {$ifndef fpc }Overload;{$endif}
  77. Procedure Log (const Msg : String); {$ifndef fpc }Overload;{$endif}
  78. Procedure Log (const Fmt : String; Args : Array of const); {$ifndef fpc }Overload;{$endif}
  79. Procedure Warning (const Msg : String); {$ifndef fpc }Overload;{$endif}
  80. Procedure Warning (const Fmt : String; Args : Array of const); {$ifndef fpc }Overload;{$endif}
  81. Procedure Error (const Msg : String); {$ifndef fpc }Overload;{$endif}
  82. Procedure Error (const Fmt : String; Args : Array of const); {$ifndef fpc }Overload;{$endif}
  83. Procedure Debug (const Msg : String); {$ifndef fpc }Overload;{$endif}
  84. Procedure Debug (const Fmt : String; Args : Array of const); {$ifndef fpc }Overload;{$endif}
  85. Procedure Info (const Msg : String); {$ifndef fpc }Overload;{$endif}
  86. Procedure Info (const Fmt : String; Args : Array of const); {$ifndef fpc }Overload;{$endif}
  87. Published
  88. Property AppendContent : Boolean Read fAppendContent Write fAppendContent;
  89. Property Identification : String Read FIdentification Write SetIdentification;
  90. Property LogType : TLogType Read Flogtype Write SetlogType;
  91. Property Active : Boolean Read FActive write SetActive;
  92. Property RaiseExceptionOnError : Boolean Read FRaiseExceptionOnError Write FRaiseExceptionOnError;
  93. Property DefaultEventType : TEventType Read FDEfaultEventType Write FDefaultEventType;
  94. Property FileName : String Read FFileName Write SetFileName;
  95. Property TimeStampFormat : String Read FTimeStampFormat Write FTimeStampFormat;
  96. Property CustomLogType : Word Read FCustomLogType Write FCustomLogType;
  97. Property EventIDOffset : DWord Read FEventIDOffset Write FEventIDOffset;
  98. Property OnGetCustomCategory : TLogCategoryEvent Read FOnGetCustomCategory Write FOnGetCustomCategory;
  99. Property OnGetCustomEventID : TLogCodeEvent Read FOnGetCustomEventID Write FOnGetCustomEventID;
  100. Property OnGetCustomEvent : TLogCodeEvent Read FOnGetCustomEvent Write FOnGetCustomEvent;
  101. Property OnLogMessage : TLogMessageEvent read FOnLogMessage write FOnLogMessage;
  102. Property Paused : Boolean Read FPaused Write FPaused;
  103. End;
  104. ELogError = Class(Exception);
  105. Resourcestring
  106. SLogInfo = 'Info';
  107. SLogWarning = 'Warning';
  108. SLogError = 'Error';
  109. SLogDebug = 'Debug';
  110. SLogCustom = 'Custom (%d)';
  111. SErrLogFailedMsg = 'Failed to log entry (Error: %s)';
  112. SErrLogOpenStdOut = 'Standard Output not available for logging';
  113. SErrLogOpenStdErr = 'Standard Error not available for logging';
  114. implementation
  115. {$i eventlog.inc}
  116. (* File based dummy implementation is used for all platforms not providing
  117. specific implementation of eventlog.inc for the particular platform. *)
  118. { TEventLog }
  119. Resourcestring
  120. SErrOperationNotAllowed = 'Operation not allowed when eventlog is active.';
  121. procedure TEventLog.CheckInactive;
  122. begin
  123. If Active then
  124. Raise ELogError.Create(SErrOperationNotAllowed);
  125. end;
  126. procedure TEventLog.Debug(const Fmt: String; Args: array of const);
  127. begin
  128. Debug(Format(Fmt,Args));
  129. end;
  130. procedure TEventLog.Debug(const Msg: String);
  131. begin
  132. Log(etDebug,Msg);
  133. end;
  134. procedure TEventLog.EnsureActive;
  135. begin
  136. If Not Active then
  137. Active:=True;
  138. end;
  139. Procedure TEventLog.Pause;
  140. begin
  141. Paused:=True;
  142. end;
  143. Procedure TEventLog.Resume;
  144. begin
  145. Paused:=False;
  146. end;
  147. procedure TEventLog.Error(const Fmt: String; Args: array of const);
  148. begin
  149. Error(Format(Fmt,Args));
  150. end;
  151. procedure TEventLog.Error(const Msg: String);
  152. begin
  153. Log(etError,Msg);
  154. end;
  155. procedure TEventLog.Info(const Fmt: String; Args: array of const);
  156. begin
  157. Info(Format(Fmt,Args));
  158. end;
  159. procedure TEventLog.Info(const Msg: String);
  160. begin
  161. Log(etInfo,Msg);
  162. end;
  163. procedure TEventLog.Log(const Msg: String);
  164. begin
  165. Log(DefaultEventType,msg);
  166. end;
  167. procedure TEventLog.Log(EventType: TEventType; const Fmt: String;
  168. Args: array of const);
  169. begin
  170. Log(EventType,Format(Fmt,Args));
  171. end;
  172. procedure TEventLog.Log(EventType: TEventType; const Msg: String);
  173. begin
  174. If Paused then
  175. exit;
  176. EnsureActive;
  177. Case FlogType of
  178. ltFile : WriteFileLog(EventType,Msg);
  179. ltSystem : WriteSystemLog(EventType,Msg);
  180. ltStdOut : WriteIOLog(EventType,Msg,StdOut);
  181. ltStdErr : WriteIOLog(EventType,Msg,StdErr);
  182. end;
  183. DoLogMessage(EventType, Msg);
  184. end;
  185. function TEventLog.FormatLogMessage(EventType : TEventType; const Msg: String): String;
  186. Var
  187. TS,T : String;
  188. begin
  189. If FTimeStampFormat='' then
  190. FTimeStampFormat:='yyyy-mm-dd hh:nn:ss.zzz';
  191. TS:=FormatDateTime(FTimeStampFormat,Now);
  192. T:=EventTypeToString(EventType);
  193. Result:=Format('%s [%s %s] %s',[Identification,TS,T,Msg]);
  194. end;
  195. procedure TEventLog.WriteFileLog(EventType : TEventType; const Msg : String);
  196. Var
  197. S : String;
  198. begin
  199. S:=FormatLogMessage(EventType, Msg)+LineEnding;
  200. try
  201. FStream.WriteBuffer(S[1],Length(S));
  202. S:='';
  203. except
  204. On E : Exception do
  205. S:=E.Message;
  206. end;
  207. If (S<>'') and RaiseExceptionOnError then
  208. Raise ELogError.CreateFmt(SErrLogFailedMsg,[S]);
  209. end;
  210. procedure TEventLog.WriteIOLog(EventType: TEventType; const Msg: String; var OutFile: TextFile);
  211. begin
  212. Writeln(OutFile,FormatLogMessage(EventType,Msg));
  213. end;
  214. procedure TEventLog.Log(const Fmt: String; Args: array of const);
  215. begin
  216. Log(Format(Fmt,Args));
  217. end;
  218. procedure TEventLog.SetActive(const Value: Boolean);
  219. begin
  220. If Value<>FActive then
  221. begin
  222. If Value then
  223. ActivateLog
  224. else
  225. DeActivateLog;
  226. FActive:=Value;
  227. end;
  228. end;
  229. Procedure TEventLog.ActivateLog;
  230. begin
  231. Case FLogType of
  232. ltFile : ActivateFileLog;
  233. ltSystem : ActivateSystemLog;
  234. ltStdOut,
  235. ltStdErr : ActivateIOLog;
  236. end;
  237. end;
  238. Procedure TEventLog.DeActivateLog;
  239. begin
  240. Case FLogType of
  241. ltFile : DeActivateFileLog;
  242. ltSystem : DeActivateSystemLog;
  243. { nothing to do here }
  244. ltStdOut,ltStdErr : ;
  245. end;
  246. end;
  247. Procedure TEventLog.ActivateFileLog;
  248. var
  249. fFileFlags : Word;
  250. begin
  251. If (FFileName='') then
  252. FFileName:=DefaultFileName;
  253. // This will raise an exception if the file cannot be opened for writing !
  254. if fAppendContent and FileExists(FFileName) then
  255. fFileFlags := fmOpenWrite
  256. else
  257. fFileFlags := fmCreate;
  258. fFileFlags := fFileFlags or fmShareDenyWrite;
  259. FStream:=TFileStream.Create(FFileName,fFileFlags);
  260. if fAppendContent then
  261. FStream.Seek(0,soFromEnd);
  262. end;
  263. Procedure TEventLog.ActivateIOLog;
  264. var
  265. errmsg: String;
  266. m: LongInt;
  267. begin
  268. if FLogtype = ltStdOut then begin
  269. m := TextRec(StdOut).Mode;
  270. errmsg := SErrLogOpenStdOut;
  271. end else begin
  272. m := TextRec(StdErr).Mode;
  273. errmsg := SErrLogOpenStdErr;
  274. end;
  275. if (m <> fmOutput) and (m <> fmAppend) then
  276. raise ELogError.Create(errmsg);
  277. end;
  278. Procedure TEventLog.DeActivateFileLog;
  279. begin
  280. FStream.Free;
  281. FStream:=Nil;
  282. end;
  283. procedure TEventLog.SetIdentification(const Value: String);
  284. begin
  285. FIdentification := Value;
  286. end;
  287. procedure TEventLog.SetlogType(const Value: TLogType);
  288. begin
  289. CheckInactive;
  290. Flogtype := Value;
  291. end;
  292. procedure TEventLog.Warning(const Fmt: String; Args: array of const);
  293. begin
  294. Warning(Format(Fmt,Args));
  295. end;
  296. procedure TEventLog.Warning(const Msg: String);
  297. begin
  298. Log(etWarning,Msg);
  299. end;
  300. procedure TEventLog.SetFileName(const Value: String);
  301. begin
  302. CheckInactive;
  303. FFileName := Value;
  304. end;
  305. Procedure TEventLog.CheckIdentification;
  306. begin
  307. If (Identification='') then
  308. Identification:=ChangeFileExt(ExtractFileName(Paramstr(0)),'');
  309. end;
  310. Function TEventLog.EventTypeToString(E : TEventType) : String;
  311. begin
  312. Case E of
  313. etInfo : Result:=SLogInfo;
  314. etWarning : Result:=SLogWarning;
  315. etError : Result:=SLogError;
  316. etDebug : Result:=SLogDebug;
  317. etCustom : Result:=Format(SLogCustom,[CustomLogType]);
  318. end;
  319. end;
  320. Procedure TEventLog.DoGetCustomEventID(Var Code : DWord);
  321. begin
  322. If Assigned(FOnGetCustomEventID) then
  323. FOnGetCustomEventID(Self,Code);
  324. end;
  325. Procedure TEventLog.DoGetCustomEventCategory(Var Code : Word);
  326. begin
  327. If Assigned(FOnGetCustomCategory) then
  328. FOnGetCustomCategory(Self,Code);
  329. end;
  330. Procedure TEventLog.DoGetCustomEvent(Var Code : DWord);
  331. begin
  332. If Assigned(FOnGetCustomEvent) then
  333. FOnGetCustomEvent(Self,Code);
  334. end;
  335. Procedure TEventLog.DoLogMessage(EventType : TEventType; const Msg: String);
  336. begin
  337. If Assigned(FOnLogMessage) then
  338. FOnLogMessage(Self,EventType,Msg);
  339. end;
  340. destructor TEventLog.Destroy;
  341. begin
  342. Active:=False;
  343. inherited;
  344. end;
  345. end.