Automated exception logging to the cloud

Bookmarks: 

Wednesday, March 09, 2016

Exceptions


The new 1.1 release of TMS Logging supports automated exception handling. All you need is a simple Boolean property set to true and your existing applications can benefit from this new feature that will automatically
log unhandled exceptions to one or more registered output handlers.

The following sample demonstrates how easy it is to add this new functionality to your application.
TMSLogger.ExceptionHandling := True;
TMSLogger.RegisterOutputHandlerClass(TTMSLoggerBrowserOutputHandler, [Self]);
TMSLogger.Outputs := AllOutputs;
We all know the following code generates a division by zero and we should at least add an if statement to our code, checking whether b > 0 before attempting to execute the division and
assigning the result to the c variable, but let's say this code is more complex and hidden somewhere in a lost unit inside your project.
procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: Integer;
begin
  a := 10;
  b := 0;
  c := a div b;
end;
Clicking the button will generate an unhandled division by zero exception.



Because the TMSLogger has the ExceptionHandling property set to True, the exception will automatically be sent to our registered output handler(s).
In this sample, we have registered a browser output handler as seen in the screenshot below.



As only unhandled exceptions are handled by the logger, wrapping the code with a try except code block will not send an exception output to the output handlers, therefore we have exposed an Exception method that will allow you to further customize the message that is logged.
procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: Integer;
begin
  try
    a := 10;
    b := 0;
    c := a div b;
  except on e: EDivByZero do
    TMSLogger.ExceptionFormat('{%s} occured in Button1Click() at line 35', [e.Message]);
  end;
end;

Cloud


Now where does the above exception handling fit into the cloud stor(y)(age)? The new TMS VCL Cloud Pack and TMS FMX Cloud Pack have 2 new cloud components available that can be used as an output handler for the logger.
The first one is the myCloudData storage service which is able to (as the name indicates) store data in the cloud. The second one is the Exceptionless logging and exception handling service. The TMS Logging distribution has 2 separate units
available that can be used to link to both services and automatically log messages / exceptions to those services. Registering an Exceptionless or myCloudData outputhandler is done in the same way as any other output handler.
The output handler requires an already authenticated service, as the output handler will not perform authentication on the connected cloud service, it will try to directly send log or exception messages.

Exceptionless

Depending on the chosen framework, you can either add FMX.TMSLoggingExceptionlessOutputHandler or VCL.TMSLoggingExceptionlessOutputHandler unit to the uses list.
The initialization code authenticates with the Exceptionless service and afterwards registers the output handler specifically designed for this cloud service.
The cloud service component is passed as a parameter to the output handler registration along with a project ID, created through the Exceptionless dashboard.
uses
  FMX.TMSLoggingExceptionlessOutputHandler;

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c: Integer;
begin
  a := 10;
  b := 0;
  c := a div b;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  p: TExceptionlessProject;
begin
  TMSFMXCloudExceptionLess1.Username := 'MyUsername';
  TMSFMXCloudExceptionLess1.Password := 'MyPassword';
  TMSFMXCloudExceptionLess1.DoAuth;
  if TMSFMXCloudExceptionLess1.TestTokens then
  begin
    TMSFMXCloudExceptionLess1.GetProjects;
    p := TMSFMXCloudExceptionLess1.GetProjectByName('TMSCloudPack');
    if Assigned(p) then
    begin
      TMSLogger.ExceptionHandling := True;
      TMSLogger.RegisterOutputHandlerClass(TTMSLoggerExceptionlessOutputHandler, [TMSFMXCloudExceptionLess1, p.ID]);
    end;
  end;
end;



myCloudData


The same approach can be applied to the myCloudData cloud service component, as with the Exceptionless cloud service component. The initialization code is slightly different due to the authentication process. Instead of a project ID, an optional tablename can be chosen. In this sample, the registration is done when the myCloudData service is connected after authentication. The initialization code additionally connects the cloud service through a dataset to our TDBAdvGrid component to display the records. The field names are stored in the MetaData property under the TTMSLoggermyCloudDataOutputHandler instance, which is returned by the RegisterOutputHandlerClass function.
procedure TForm1.AdvmyCloudData1Connected(Sender: TObject);
begin
  TMSLogger.RegisterOutputHandlerClass(TTMSLoggermyCloudDataOutputHandler, [AdvmyCloudData1, 'MyTableName']);
  ds.Active := True;
  grd.AutoSizeColumns(True);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  obj: TMyObject;
begin
  obj := TMyObject.Create;
  obj.X := 'Hello World !';
  obj.Y := 123.456;
  TMSLogger.StartTimer;
  TMSLogger.LogSystemInformation;
  TMSLogger.WarningFormat('The value for property Y is {%.3f}', [obj.Y]);
  TMSLogger.Trace(obj);
  TMSLogger.StopTimer;
  TMSLogger.Debug('
  • Item 1
  • Item 2
  • Item 3
'); obj.Free; ds.Refresh; grd.AutoSizeColumns(True); end; procedure TForm1.Button2Click(Sender: TObject); begin AdvmyCloudData1.Connect; end; procedure TForm1.FormCreate(Sender: TObject); begin grd := TDBAdvGrid.Create(Self); grd.Parent := Self; grd.Left := 20; grd.Top := 50; grd.Width := Width; AdvmyCloudData1.App.Key := 'MyAppKey'; AdvmyCloudData1.App.Secret := 'MyAppSecret'; AdvmyCloudData1.PersistTokens.Location := plIniFile; AdvmyCloudData1.PersistTokens.Key := '.myclouddata.ini'; AdvmyCloudData1.PersistTokens.Section := 'tokens'; AdvmyCloudData1.App.CallBackPort := 8888; AdvmyCloudData1.App.CallBackURL := 'http://127.0.0.1:8888'; da := TCloudDataStoreAdapter.Create(Self); da.CloudDataStore := AdvmyCloudData1; ds := TCloudDataSet.Create(Self); ds.Adapter := da; ds.Active := False; d := TDataSource.Create(Self); d.DataSet := ds; grd.DataSource := d; TMSLogger.Outputs := [loTimeStamp, loProcessID, loThreadID, loMemoryUsage, loLogLevel, loName, loValue, loType]; end;




Pieter Scheldeman


Bookmarks: 

This blog post has received 2 comments. Add a comment.




Previous  |  Next  |  Index