system.analytics.pp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. {
  2. This file is part of the Free Pascal Run Time Library (rtl)
  3. Copyright (c) 1999-2019 by the Free Pascal development team
  4. This file provides the base of an application analytics system.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit System.Analytics;
  12. {$MODE OBJFPC}
  13. {$SCOPEDENUMS ON}
  14. interface
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. uses
  17. System.SysUtils, System.Contnrs, System.Classes;
  18. {$ELSE}
  19. uses
  20. sysutils, contnrs, classes;
  21. {$ENDIF}
  22. type
  23. IApplicationActivityCacheManager = interface ['{6145E812-8ECA-4B69-994C-26A81B2A84DC}']
  24. function GetCacheCount: Integer;
  25. procedure PersistData(const Wait: Boolean);
  26. procedure ClearData;
  27. procedure Log(const AMessage: string);
  28. procedure RemoveEventAtIndex(const Index: Integer);
  29. function GetEventAtIndex(const Index: Integer): string;
  30. procedure SetOnDataCacheFull(const AValue: TNotifyEvent);
  31. function GetOnDataCacheFull: TNotifyEvent;
  32. procedure SetMaxCacheSize(const AValue: Integer);
  33. function GetMaxCacheSize: Integer;
  34. property CacheCount: Integer read GetCacheCount;
  35. property MaxCacheSize: Integer read GetMaxCacheSize write SetMaxCacheSize;
  36. property Event[const Index: Integer]: string read GetEventAtIndex;
  37. property OnDataCacheFull: TNotifyEvent read GetOnDataCacheFull write SetOnDataCacheFull;
  38. end;
  39. IAppAnalyticsStartupDataRecorder = interface ['{783ED8DB-86BC-41C7-BBD3-443C19468FF1}']
  40. procedure AddEnvironmentField(const AKey, AValue: string);
  41. end;
  42. IApplicationActivityListener = interface ['{A67DE237-F274-4028-AAC8-DA0BDA0D5D78}']
  43. procedure TrackAppStart(const aTimeStamp: TDateTime);
  44. procedure TrackAppExit(const aTimeStamp: TDateTime);
  45. procedure TrackControlFocused(const aTimeStamp: TDateTime; const aSender: TObject);
  46. procedure TrackWindowActivated(const aTimeStamp: TDateTime; const aSender: TObject);
  47. procedure TrackEvent(const aTimeStamp: TDateTime; const aSender, aContext: TObject);
  48. procedure TrackException(const aTimeStamp: TDateTime; const E: Exception);
  49. end;
  50. TAppActivity = (AppStart, AppExit, ControlFocused, WindowActivated, Exception, Custom);
  51. TAppActivityOptions = set of TAppActivity;
  52. TAnalyticsManager = class
  53. private
  54. FClients: TInterfaceList;
  55. function GetTrackingEnabled: Boolean;
  56. function GetClientCount : Integer;
  57. function GetClient(aIndex : Integer) : IApplicationActivityListener;
  58. Protected
  59. Property Clients[aIndex : Integer] : IApplicationActivityListener Read GetClient;
  60. Property ClientCount : Integer Read GetClientCount;
  61. public
  62. destructor Destroy; override;
  63. procedure RegisterActivityListener(const aListener: IApplicationActivityListener);
  64. procedure UnregisterActivityListener(const aListener: IApplicationActivityListener);
  65. procedure RecordActivity(const aActivity: TAppActivity); overload;
  66. procedure RecordActivity(const aActivity: TAppActivity; const aSender: TObject); overload;
  67. procedure RecordActivity(const aActivity: TAppActivity; const aSender: TObject; const aContext: TObject); overload;
  68. property TrackingEnabled: Boolean read GetTrackingEnabled;
  69. end;
  70. EAnalyticsInitializationFailed = class(Exception);
  71. implementation
  72. { TAnalyticsManager }
  73. destructor TAnalyticsManager.Destroy;
  74. begin
  75. FreeAndNil(FClients);
  76. inherited;
  77. end;
  78. function TAnalyticsManager.GetClientCount : Integer;
  79. begin
  80. if not assigned(FClients) then
  81. Result:=0
  82. else
  83. Result:=FClients.Count;
  84. end;
  85. function TAnalyticsManager.GetClient(aIndex : Integer) : IApplicationActivityListener;
  86. begin
  87. if not Assigned(FClients) then
  88. Raise EListError.Create('Index (%d) out of bounds');
  89. Result:=(FClients[aIndex]) as IApplicationActivityListener;
  90. end;
  91. procedure TAnalyticsManager.RecordActivity(const aActivity: TAppActivity);
  92. begin
  93. RecordActivity(aActivity,nil,nil);
  94. end;
  95. procedure TAnalyticsManager.RecordActivity(const aActivity: TAppActivity; const aSender: TObject);
  96. begin
  97. RecordActivity(aActivity,aSender,nil);
  98. end;
  99. function TAnalyticsManager.GetTrackingEnabled: Boolean;
  100. begin
  101. Result:=(ClientCount>0)
  102. end;
  103. procedure TAnalyticsManager.RecordActivity(const aActivity: TAppActivity; const aSender,aContext: TObject);
  104. var
  105. I : Integer;
  106. TS : TDateTime;
  107. A : IApplicationActivityListener;
  108. begin
  109. if ClientCount=0 then
  110. exit;
  111. TS:=Now;
  112. for I:=0 to ClientCount-1 do
  113. begin
  114. A:=Clients[I];
  115. case aActivity of
  116. TAppActivity.AppStart:
  117. A.TrackAppStart(Ts);
  118. TAppActivity.AppExit:
  119. A.TrackAppExit(Ts);
  120. TAppActivity.ControlFocused:
  121. A.TrackControlFocused(Ts,aSender);
  122. TAppActivity.WindowActivated:
  123. A.TrackWindowActivated(Ts,aSender);
  124. TAppActivity.Exception:
  125. if aSender is Exception then
  126. A.TrackException(Ts,Exception(aSender));
  127. TAppActivity.Custom:
  128. A.TrackEvent(Ts,aSender,aContext);
  129. end;
  130. A:=Nil;
  131. end;
  132. end;
  133. procedure TAnalyticsManager.RegisterActivityListener(const aListener: IApplicationActivityListener);
  134. begin
  135. if Not Assigned(FClients) then
  136. FClients:=TInterfaceList.Create
  137. else if FClients.IndexOf(aListener)<>-1 then
  138. Exit;
  139. FClients.Add(aListener);
  140. end;
  141. procedure TAnalyticsManager.UnregisterActivityListener(const aListener: IApplicationActivityListener);
  142. begin
  143. if Assigned(FClients) then
  144. FClients.Remove(aListener);
  145. end;
  146. end.