Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (2)


Exception or Event LoggerGo to Max Kleiner's websiteFormat this article printer-friendly!Bookmark function is only available for registered users!
How to keep track of runtime exceptions or component events?
Product:
Delphi all versions
Category:
Object Pascal
Skill Level:
Scoring:
Last Update:
09/28/2009
Search Keys:
delphi delphi3000 article borland vcl code-snippet Exceptions Logger Error-report Quality Assert events
Times Scored:
5
Visits:
4905
Uploader: Max Kleiner
Company: kleiner kommunikation
Reference: http://max.kleiner.com/uml_buch.htm
 
Question/Problem/Abstract:
Each project has logical errors or by runtime. It would be fine to write these exceptions down to a file in order to find out, what's happened weeks ago ;) or to track component events
Answer:



Exceptions are mistakes and errors due to some run-time problem. This is obviously a wishy-washy definition, but generally run-time problems would
be things like running out of memory whilst adding a data object or an index out of bounds.
In our team we wrote a procedure (years ago), which intercepts those nasty things like exceptions by assigning a global new event-handler in the main-unit:

{$IFDEF DEBUG}
  Application.OnException:= AppOnException;
{$ENDIF}

If DEBUG is not set the code runs at full speed, but I advise to set the handler all the time, cause then you can analyse each applications exception file. Normal testing should identify programming mistakes, whereas the other type of error are exceptions to the norm.
The event-handler goes like this:


procedure TCWForm.AppOnException(sender: TObject; E: Exception);
var
  Addr: string[9];
  FErrorLog: System.Text;
  FileNamePath: string;
begin  //writes errorlog.txt file
  FileNamePath:= extractFilePath(application.exeName) +  
                                            'errorlog.txt';
  AssignFile(FErrorLog, FileNamePath);
  try
    System.Append(FErrorlog);
  except
    on EInOutError do Rewrite(FErrorLog);
  end;
  Addr:= IntToHex(Seg(ErrorAddr),4) + ';'
                         +IntToHex(Ofs(ErrorAddr),4);
  Writeln(FErrorLog, format('%s[%s]%s%s',[DateTimeToStr(Now),
                             getNetUserName, E.Message, Addr]));
  System.Close(FErrorLog);}
  MessageDlg('CW5' + E.Message +'. occured at:
                                   '+Addr,mtError,[mbOK],0);
end;


To avoid scope conflicts, Assign File replaces the Assign procedure that was available in previous versions of Delphi. The Addr also depends on the OS. Note, that you want still see exceptions on the screen, you get it with the last MessageDlg in the AppOnException-routine.

Then you get an output in a well shaped manner:

*************************ERRORLOG************************************
26.09.99 12:09:16 [MAX] List index out of bounds 52FF;1226
26.09.99 13:05:28 [MAX] Database BezSpr not found 5F6F;1226
26.09.99 13:21:37 [THOMAS] List index out of bounds 69DF;1226
26.09.99 13:43:35 [MAX] GP fault in module CW5.EXE at 0002:3588 2A9F;1226
30.09.99 14:32:23 [SIMON] Cannot perform this operation on a closed dataset 320F;1254
30.09.99 14:35:36 [MAX] Record locked by another user. Table:GBK.DB


Maybe, the function getNetUserName has to be changed, it depends on the operating-system or the database you deal with:

function getNetUserName: string;
var
  szVar: array[0..32] of char;
begin
  DBIGetNetUserName(szVar);
  result:= StrPas(@szVar) ;
end;

Instead of Addr:= by an Exception, use in a 32-bit environment:
   mem: TMemoryStatus;
   mem.dwLength:=sizeOf(TMemoryStatus);
   GlobalMemoryStatus(mem);
   edit3.text:=intToStr((mem.dwAvailPageFile)
                                div 1024) ;
   edit4.text:=intToStr((mem.dwAvailPhys)
                                div 1024);


Component Event Logger (Update 1.3.02)
------------------------------------------------------
On the other side you want to know component events to track down user or system behavior. This is also usefull to show the events on runtime in a listbox or to store it in a file.
First your declare a procedure in your class:

events: TListBox;
procedure LogEvent(const EventStr: string; Component: TComponent = nil);


Second you define the procedure with a listbox as events:

procedure TransAct.LogEvent(const EventStr: string;
                             Component: TComponent = nil);
var
  ItemCount: Integer;
begin
  if (csDestroying in ComponentState) or not Events.Visible then Exit;
  if (Component  nil) and (Component.Name  '') then
    Events.Items.Add(Format('%s(%s)', [EventStr, Component.Name])) else
    Events.Items.Add(EventStr);
  ItemCount := Events.Items.Count;
  Events.ItemIndex := ItemCount - 1;
  if ItemCount  (Events.ClientHeight div Events.ItemHeight) then
    Events.TopIndex := ItemCount - 1;  //tracing
end;

Third you call the procedure LogEvent in your code as you want, e.g.:
LogEvent('OnDataChange', Sender as TComponent);
LogEvent('BeforeOpen', DataSet);
LogEvent('AfterClose', DataSet);

procedure TransAct.DataSetBeforeClose(DataSet: TDataSet);
begin
  LogEvent('BeforeClose');
end;

procedure TransAct.DataSetError(DataSet: TDataSet;
                           E: EDatabaseError; var Action: TDataAction);
begin
  LogEvent('OnDelete/OnEdit/OnPost Errors', DataSet);
end;

procedure TransAct.Disconnect(Connection: TADOConnection;
                                var EventStatus: TEventStatus);
begin LogEvent('Disconnect', Connection);
end;


Update 06.04.02 with automatic file writing each with a time-stamp
-------------------------------------------------------------------

function TScanner.SaveLogData(const UserData: WideString; const CheckSum : DWORD) : Boolean;
var
  SL       : TStringList;
  FileName : String;
begin
  SL := TStringList.Create;
  FileName :=
    'D:\Scanner\LogData\'+FormatDateTime('yyyymmdd-hhnnsszzz',Now)+'.txt';
  SL.Text := UserData;
  SL.SaveToFile(FileName);
  SL.Free;
  Result := True;
end;

update 28.9.2009
----------------------------------------------------------------

When you want to set the file from begin to end and save time and resources for each event:  

initialization
  assignFile(FErrorlog,'errorlog.txt');
  append(FErrorlog)
finalization
  closeFile(FErrorlog)







Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
compile errors
    Kurt Mueller (Oct 6 2001 3:12PM)

very interesting article...
Delphi5 Pro I have following compile errors:

[Fehler] Main.pas(149): Undefinierter Bezeichner: 'Seg'
[Fehler] Main.pas(149): Undefinierter Bezeichner: 'Ofs'
[Fehler] Main.pas(150): Undefinierter Bezeichner: 'ErrorLog'
[Fehler] Main.pas(152): Anweisung erwartet, aber ')' gefunden
[Fehler] Main.pas(160): Undefinierter Bezeichner: 'DBIGetNetUserName'

can you give me an Tip to solve this problem?
Best regards
Kurt
Respond

RE: compile errors
Max Kleiner (Oct 16 2001 4:54PM)

Error  'Seg' 'Ofs' were values in a 16-bit environment (segment-offset),  'ErrorLog' must be FErrorLog and the function  'DBIGetNetUserName' is explained at the bottom in the text and depends on your database


Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
I. Siticov
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)