Automated exception logging to the cloud

  

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 1Item 2Item 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;

Comments are closed.