123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- {
- This file is part of the Free Pascal Run Time Library (rtl)
- Copyright (c) 1999-2019 by the Free Pascal development team
- This file provides the base of an application analytics system.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit System.Analytics;
- {$MODE OBJFPC}
- {$SCOPEDENUMS ON}
- interface
- {$IFDEF FPC_DOTTEDUNITS}
- uses
- System.SysUtils, System.Contnrs, System.Classes;
- {$ELSE}
- uses
- sysutils, contnrs, classes;
- {$ENDIF}
- type
- IApplicationActivityCacheManager = interface ['{6145E812-8ECA-4B69-994C-26A81B2A84DC}']
- function GetCacheCount: Integer;
- procedure PersistData(const Wait: Boolean);
- procedure ClearData;
- procedure Log(const AMessage: string);
- procedure RemoveEventAtIndex(const Index: Integer);
- function GetEventAtIndex(const Index: Integer): string;
- procedure SetOnDataCacheFull(const AValue: TNotifyEvent);
- function GetOnDataCacheFull: TNotifyEvent;
- procedure SetMaxCacheSize(const AValue: Integer);
- function GetMaxCacheSize: Integer;
- property CacheCount: Integer read GetCacheCount;
- property MaxCacheSize: Integer read GetMaxCacheSize write SetMaxCacheSize;
- property Event[const Index: Integer]: string read GetEventAtIndex;
- property OnDataCacheFull: TNotifyEvent read GetOnDataCacheFull write SetOnDataCacheFull;
- end;
- IAppAnalyticsStartupDataRecorder = interface ['{783ED8DB-86BC-41C7-BBD3-443C19468FF1}']
- procedure AddEnvironmentField(const AKey, AValue: string);
- end;
- IApplicationActivityListener = interface ['{A67DE237-F274-4028-AAC8-DA0BDA0D5D78}']
- procedure TrackAppStart(const aTimeStamp: TDateTime);
- procedure TrackAppExit(const aTimeStamp: TDateTime);
- procedure TrackControlFocused(const aTimeStamp: TDateTime; const aSender: TObject);
- procedure TrackWindowActivated(const aTimeStamp: TDateTime; const aSender: TObject);
- procedure TrackEvent(const aTimeStamp: TDateTime; const aSender, aContext: TObject);
- procedure TrackException(const aTimeStamp: TDateTime; const E: Exception);
- end;
- TAppActivity = (AppStart, AppExit, ControlFocused, WindowActivated, Exception, Custom);
- TAppActivityOptions = set of TAppActivity;
- TAnalyticsManager = class
- private
- FClients: TInterfaceList;
- function GetTrackingEnabled: Boolean;
- function GetClientCount : Integer;
- function GetClient(aIndex : Integer) : IApplicationActivityListener;
- Protected
- Property Clients[aIndex : Integer] : IApplicationActivityListener Read GetClient;
- Property ClientCount : Integer Read GetClientCount;
- public
- destructor Destroy; override;
- procedure RegisterActivityListener(const aListener: IApplicationActivityListener);
- procedure UnregisterActivityListener(const aListener: IApplicationActivityListener);
- procedure RecordActivity(const aActivity: TAppActivity); overload;
- procedure RecordActivity(const aActivity: TAppActivity; const aSender: TObject); overload;
- procedure RecordActivity(const aActivity: TAppActivity; const aSender: TObject; const aContext: TObject); overload;
- property TrackingEnabled: Boolean read GetTrackingEnabled;
- end;
- EAnalyticsInitializationFailed = class(Exception);
- implementation
- { TAnalyticsManager }
- destructor TAnalyticsManager.Destroy;
- begin
- FreeAndNil(FClients);
- inherited;
- end;
- function TAnalyticsManager.GetClientCount : Integer;
- begin
- if not assigned(FClients) then
- Result:=0
- else
- Result:=FClients.Count;
- end;
- function TAnalyticsManager.GetClient(aIndex : Integer) : IApplicationActivityListener;
- begin
- if not Assigned(FClients) then
- Raise EListError.Create('Index (%d) out of bounds');
- Result:=(FClients[aIndex]) as IApplicationActivityListener;
- end;
- procedure TAnalyticsManager.RecordActivity(const aActivity: TAppActivity);
- begin
- RecordActivity(aActivity,nil,nil);
- end;
- procedure TAnalyticsManager.RecordActivity(const aActivity: TAppActivity; const aSender: TObject);
- begin
- RecordActivity(aActivity,aSender,nil);
- end;
- function TAnalyticsManager.GetTrackingEnabled: Boolean;
- begin
- Result:=(ClientCount>0)
- end;
- procedure TAnalyticsManager.RecordActivity(const aActivity: TAppActivity; const aSender,aContext: TObject);
- var
- I : Integer;
- TS : TDateTime;
- A : IApplicationActivityListener;
-
- begin
- if ClientCount=0 then
- exit;
- TS:=Now;
- for I:=0 to ClientCount-1 do
- begin
- A:=Clients[I];
- case aActivity of
- TAppActivity.AppStart:
- A.TrackAppStart(Ts);
- TAppActivity.AppExit:
- A.TrackAppExit(Ts);
- TAppActivity.ControlFocused:
- A.TrackControlFocused(Ts,aSender);
- TAppActivity.WindowActivated:
- A.TrackWindowActivated(Ts,aSender);
- TAppActivity.Exception:
- if aSender is Exception then
- A.TrackException(Ts,Exception(aSender));
- TAppActivity.Custom:
- A.TrackEvent(Ts,aSender,aContext);
- end;
- A:=Nil;
- end;
- end;
- procedure TAnalyticsManager.RegisterActivityListener(const aListener: IApplicationActivityListener);
- begin
- if Not Assigned(FClients) then
- FClients:=TInterfaceList.Create
- else if FClients.IndexOf(aListener)<>-1 then
- Exit;
- FClients.Add(aListener);
- end;
- procedure TAnalyticsManager.UnregisterActivityListener(const aListener: IApplicationActivityListener);
- begin
- if Assigned(FClients) then
- FClients.Remove(aListener);
- end;
- end.
|