Blog Options
Archive
<< October 2025 >>-
Friday 24
- TMS Halloween Challenge: Share Your Spooky App Creations! -
Thursday 23
- Automate StellarDS database operations with AI via MCP -
Tuesday 21
- TMS AI Studio v1.4 is bringing HTTP.sys to MCP -
Wednesday 15
- Using AI Services securely in TMS AI Studio -
Tuesday 14
- Our components are ready for Windows 11 -
Thursday 9
- Seamlessly combining the power of TWebDataGrid with StellarDS.io backend -
Wednesday 8
- Automatic Token Renewal with FetchAccessToken in TMS FNC Cloud Pack -
Tuesday 7
- Next Generation Data Grid for Delphi: Paging (BETA) -
Thursday 2
- Celebrating 10 Years of TMS ALL-ACCESS
- Introducing Attributes Support for MCP Servers in Delphi
Authors
- Bernard Roussely (3)
- Wagner Landgraf (93)
- Dennis Röhner (1)
- Roman Yankovsky (2)
- Bart Holvoet (41)
- Aaron Decramer (58)
- Pieter Scheldeman (125)
- Nancy Lescouhier (32)
- Adrian Gallero (34)
- Bruno Fierens (445)
- Marcos Douglas B. Santos (5)
- Bernard (4)
- Bradley Velghe (35)
- Andrew Simard (86)
- Holger Flick (15)
- Gjalt Vanhouwaert (42)
- Tunde Keller (32)
- Masiha Zemarai (117)
Blog
All Blog Posts | Next Post | Previous Post
Audit Log using TMS Aurelius events
Friday, April 24, 2015
The latest release of TMS Aurelius introduces an event system that allows you to subscribe listeners to some events that might be fired while you are using Aurelius, especially the TObjectManager.One key difference between regular Delphi events and Aurelius events is that the latter are multicast events, meaning you can add listeners (handlers) to the events without worrying if you are replacing a listener that was already set to event. This way it's possible to create "plugins" to Aurelius that perform additional logic. For example you can easily add code that will be executed whenever an entity is inserted in the database:
TMappingExplorer.Default.Events.OnInserted.Subscribe(
procedure(Args: TInsertedArgs)
begin
// Use Args.Entity to retrieve the inserted entity
end
);
One very common use of that feature is implementing Audit Trail, a mechanism where you can log every entity (or database record, if you prefer to see it that way) that is created (inserted), deleted or modified (updated). The Music Library demo included in TMS Aurelius distribution was updated to include a simple Audit Log Viewer that illustrates how to use the events.
In the demo, the Audit Log Viewer just listen to the events and log them in a memo component in a form. You can enable/disable the logging. In real applications, you will just log the modifications to another place, like a text log file, or even the database itself, using Aurelius, if you prefer.
You can check the demo for the full source code. In this blog post, I will show only the relevant parts, for the OnInserted and OnUpdated events. Other parts of the code even inside procedures were removed for simplicity. Here is how we subscribe to the events:
TfmAuditLogViewer = class(TForm)
private
FInsertedProc: TInsertedProc;
FUpdatedProc: TUpdatedProc;
procedure InsertedHandler(Args: TInsertedArgs);
procedure UpdatedHandler(Args: TUpdatedArgs);
procedure SubscribeListeners;
procedure UnsubscribeListeners;
{...}
end;
constructor TfmAuditLogViewer.Create(AOwner: TComponent);
begin
inherited;
FInsertedProc := InsertedHandler;
FUpdatedProc := UpdatedHandler;
end;
procedure TfmAuditLogViewer.SubscribeListeners;
var
E: TManagerEvents;
begin
E := TMappingExplorer.Default.Events;
E.OnInserted.Subscribe(FInsertedProc);
E.OnUpdated.Subscribe(FUpdatedProc);
end;
Note that we set the method reference in field variables so that we can later unsubscribe them if we want to:
procedure TfmAuditLogViewer.UnsubscribeListeners; var E: TManagerEvents; begin E := TMappingExplorer.Default.Events; E.OnInserted.Unsubscribe(FInsertedProc); E.OnUpdated.Unsubscribe(FUpdatedProc); end;
And here is how we implemented our event listeners:
procedure TfmAuditLogViewer.InsertedHandler(Args: TInsertedArgs);
begin
Log(Format('Inserted: %s', [EntityDesc(Args.Entity, Args.Manager)]));
BreakLine;
end;
procedure TfmAuditLogViewer.UpdatedHandler(Args: TUpdatedArgs);
var
Pair: TPair<string, Variant>;
OldValue: Variant;
begin
Log(Format('Updated: %s', [EntityDesc(Args.Entity, Args.Manager)]));
for Pair in Args.NewColumnValues do
if not (Args.OldColumnValues.TryGetValue(Pair.Key, OldValue) and (OldValue = Pair.Value)) then
Log(Format(' %s Changed from %s to %s',
[Pair.Key, TUtils.VariantToString(OldValue), TUtils.VariantToString(Pair.Value)]));
BreakLine;
end;
Some different methods are called from those event handlers, but they are just helper methods. EntityDesc just retrieves a string representation of the entity being logged (class name and id), and Log and BreakLine just add text to the memo component:
function TfmAuditLogViewer.EntityDesc(Entity, Manager: TObject): string;
var
IdValue: Variant;
IdString: string;
begin
IdValue := TObjectManager(Manager).Explorer.GetIdValue(Entity);
IdString := TUtils.VariantToString(IdValue);
Result := Format('%s(%s)', [Entity.ClassName, IdString]);
end;
procedure TfmAuditLogViewer.Log(const S: string);
begin
Memo.Lines.Add(S);
end;
procedure TfmAuditLogViewer.BreakLine;
begin
Memo.Lines.Add('================================================');
end;
After playing with Music Library demo for a while, adding and updating entities, we have our audit log results:
Wagner Landgraf
This blog post has received 2 comments.
2. Sunday, March 20, 2022 at 12:50:31 PM
It should work fine. In any case, use the Support Center to ask technical questions, it''s the best place: https://support.tmssoftware.com.
Wagner Landgraf
All Blog Posts | Next Post | Previous Post
Stapel Andreas