Skip to content

Commit ced6fe8

Browse files
[OF-1739] test: Add batched analytics events (#791)
Added two new methods to the AnalyticsSystem; BatchAnalyticsEvent and FlushAnalyticsEvents. The BatchAnalyticsEvent method makes it possible to add an analytic event to a queue to be sent to MCS later as part of a batch. The queue will be processed when one of the following conditions is met: 1. The time since the last batch was sent reaches the batch rate (default 60 seconds). 2. The number of events in the queue reaches the maximum batch size (default 25 events). 3. The client application calls FlushAnalyticsEvents() as part of their log out or shut down procedure to force the batch to be sent. The FlushAnalyticsEvents method will trigger immediate dispatch of the Analytics Records queue to MCS. This method is designed to be called as part of a client applications log out and shutdown procedures to ensure that any queued analytics records are flushed and sent to MCS before the user is logged out or the application is shut down.
1 parent 8b6f588 commit ced6fe8

File tree

3 files changed

+516
-61
lines changed

3 files changed

+516
-61
lines changed

Library/include/CSP/Systems/Analytics/AnalyticsSystem.h

Lines changed: 117 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@
2222
#include "CSP/Common/String.h"
2323
#include "CSP/Systems/SystemBase.h"
2424

25+
#include <chrono>
26+
#include <mutex>
27+
28+
CSP_START_IGNORE
29+
#ifdef CSP_TESTS
30+
class CSPEngine_AnalyticsSystemTests_QueueAnalyticsEventQueueSendRateTest_Test;
31+
class CSPEngine_AnalyticsSystemTests_QueueAnalyticsEventQueueSizeTest_Test;
32+
class CSPEngine_AnalyticsSystemTests_FlushAnalyticsEventsQueueTest_Test;
33+
#endif
34+
CSP_END_IGNORE
35+
2536
namespace csp
2637
{
2738
class ClientUserAgent;
@@ -37,57 +48,147 @@ namespace csp::web
3748
class WebClient;
3849
} // namespace csp::web
3950

51+
namespace csp::services::generated::userservice
52+
{
53+
class AnalyticsRecord;
54+
}
55+
4056
namespace csp::systems
4157
{
4258

4359
/// @ingroup Analytics System
44-
/// @brief Public facing system that allows AnalyticsRecords to be sent to MCS.
60+
/// @brief Public facing system that allows AnalyticsRecords to be sent to the backend services.
61+
/// @invariant Users must be logged in to send AnalyticsRecords to the backend services.
4562
class CSP_API AnalyticsSystem : public SystemBase
4663
{
4764
CSP_START_IGNORE
4865
/** @cond DO_NOT_DOCUMENT */
4966
friend class SystemsManager;
67+
68+
#ifdef CSP_TESTS
69+
friend class ::CSPEngine_AnalyticsSystemTests_QueueAnalyticsEventQueueSendRateTest_Test;
70+
friend class ::CSPEngine_AnalyticsSystemTests_QueueAnalyticsEventQueueSizeTest_Test;
71+
friend class ::CSPEngine_AnalyticsSystemTests_FlushAnalyticsEventsQueueTest_Test;
72+
#endif
5073
/** @endcond */
5174
CSP_END_IGNORE
5275

5376
public:
5477
/**
55-
* @brief Sends an analytics event to the Analytics service.
56-
* @details Please note: The BatchAnalyticsEvent method should be used by default as it will batch events before sending them.
57-
* This method will immediately send the analytics event and should therefore only be used when this behaviour is required.
78+
* @brief Constructs an Analytics Record which is added to a queue to be sent to the backend services in a single batch.
79+
* @details The queue will be sent when one of the following conditions are met:
80+
* 1. The time since the last batch was sent reaches the AnalyticsQueueSendRate (default 60 seconds).
81+
* 2. The number of events in the queue reaches the MaxQueueSize threshhold (default 25 events).
82+
* 3. The client application calls FlushAnalyticsEventsQueue(). Clients should call this as part of their log out or shut down procedure to force
83+
* the queue to be sent. For more information about flushing events see the method documentation @ref
84+
* AnalyticsSystem::FlushAnalyticsEventsQueue().
5885
*
5986
* Example: Consider the following user action that is to be captured as an analytics event:
60-
* A [web client] user [clicks] on a [menu] item in the [UI].
87+
* - A [web client] user [clicks] on a [menu] item in the [UI].
6188
*
6289
* In this example:
63-
* [web client] is captured internally.
64-
* [clicks] is the InteractionType.
65-
* [menu] is the Category.
66-
* [UI] is the ProductContextSection.
90+
* - [web client] is captured internally.
91+
* - [clicks] is the InteractionType.
92+
* - [menu] is the Category.
93+
* - [UI] is the ProductContextSection.
94+
*
95+
* @note The following data is captured internally and included in the analytics record:
96+
* - tenant name, client sku, client version and client build environment.
97+
*
98+
* @pre The user must be logged in to send Analytics Records to the backend services.
99+
* @param ProductContextSection const csp::common::String& : The specific, high-level functional area or context within the product where the
100+
* event occurred. This field acts as a primary identifier for the part of the application or system the user is interacting with.
101+
* @param Category const csp::common::String& : Categorization field which acts as a namespace for the InteractionType. It provides a means of
102+
* grouping similar events, which makes it easier to analyze and filter analytics data.
103+
* @param InteractionType const csp::common::String& : Describes the precise and specific interaction that is being tracked. This field identifies
104+
* what the user did or what happened within the product at a specific moment in time.
105+
* @param SubCategory const csp::common::Optional<csp::common::String>& : Optional sub-category field to provide additional context if required.
106+
* @param Metadata const csp::common::Optional<csp::common::Map<csp::common::String, csp::common::String>>& : Optional analytics event metadata.
107+
* Metadata is the event payload. It may be used to store such information as the space the user is in, their geographical region, as well as
108+
* relevant device specs.
109+
*/
110+
void QueueAnalyticsEvent(const csp::common::String& ProductContextSection, const csp::common::String& Category,
111+
const csp::common::String& InteractionType, const csp::common::Optional<csp::common::String>& SubCategory,
112+
const csp::common::Optional<csp::common::Map<csp::common::String, csp::common::String>>& Metadata);
113+
114+
/**
115+
* @brief Constructs an Analytics Record which is immediately sent to the backend services.
116+
* @note The QueueAnalyticsEvent method should be used by default as it will queue events before sending them. This method will immediately send
117+
* the analytics event and should therefore only be used when this behaviour is required.
67118
*
68-
* @note The following data is captured internally and included in the analytics record: tenant name, client sku, client version and client build
69-
* environment.
119+
* For more information about how the Analytics Record is constructed, see the documentation for @ref AnalyticsSystem::QueueAnalyticsEvent().
70120
*
71-
* @param ProductContextSection const csp::common::String& : Section of the client or runtime-context.
72-
* @param Category const csp::common::String& : Categorization field.
73-
* @param InteractionType const csp::common::String& : The interaction that occurred.
74-
* @param SubCategory const csp::common::Optional<csp::common::String>& : Optional sub-category field.
121+
* @pre The user must be logged in to send Analytics Records to the backend services.
122+
* @param ProductContextSection const csp::common::String& : The specific, high-level functional area or context within the product where the
123+
* event occurred. This field acts as a primary identifier for the part of the application or system the user is interacting with.
124+
* @param Category const csp::common::String& : Categorization field which acts as a namespace for the InteractionType. It provides a means of
125+
* grouping similar events, which makes it easier to analyze and filter analytics data.
126+
* @param InteractionType const csp::common::String& : Describes the precise and specific interaction that is being tracked. This field identifies
127+
* what the user did or what happened within the product at a specific moment in time.
128+
* @param SubCategory const csp::common::Optional<csp::common::String>& : Optional sub-category field to provide additional context if required.
75129
* @param Metadata const csp::common::Optional<csp::common::Map<csp::common::String, csp::common::String>>& : Optional analytics event metadata.
76-
* @note Metadata is the event payload. It may be used to store such information as the space the user is in, their geographical region as well as
130+
* Metadata is the event payload. It may be used to store such information as the space the user is in, their geographical region, as well as
77131
* relevant device specs.
132+
* @param Callback NullResultCallback : the callback to execute on completion of the send operation.
78133
*/
79134
void SendAnalyticsEvent(const csp::common::String& ProductContextSection, const csp::common::String& Category,
80135
const csp::common::String& InteractionType, const csp::common::Optional<csp::common::String>& SubCategory,
81136
const csp::common::Optional<csp::common::Map<csp::common::String, csp::common::String>>& Metadata, NullResultCallback Callback);
82137

138+
/**
139+
* @brief Trigger immediate dispatch of the Analytics Records queue to the backend services.
140+
* @note This method should be called as part of client log out or shut down procedure to ensure that any queued analytics records are flushed and
141+
* sent to the backend services before the user is logged out or the application is shut down.
142+
* @param Callback NullResultCallback : the callback to execute on completion of the flush operation.
143+
* @pre The user must be logged in to send an Analytics Record to the backend services.
144+
*/
145+
CSP_EVENT void FlushAnalyticsEventsQueue(NullResultCallback Callback);
146+
147+
/**
148+
* @brief Retrieves the time since the queue was last sent.
149+
* @return std::chrono::milliseconds : time since epoch in milliseconds.
150+
*/
151+
CSP_NO_EXPORT std::chrono::milliseconds GetTimeSinceLastQueueSend() const { return TimeSinceLastQueueSend; }
152+
153+
/**
154+
* @brief Retrieves the rate at which the queued Analytics Records are sent.
155+
* @return std::chrono::milliseconds : send rate in milliseconds.
156+
*/
157+
CSP_NO_EXPORT std::chrono::milliseconds GetQueueSendRate() const { return AnalyticsQueueSendRate; }
158+
159+
/**
160+
* @brief Retrieves the current size of the Analytics Records queue.
161+
* @return size_t : the queue size.
162+
*/
163+
CSP_NO_EXPORT size_t GetCurrentQueueSize() const { return AnalyticsRecordQueue.size(); }
164+
165+
/**
166+
* @brief Retrieves the max permitted size of the Analytics Records queue.
167+
* If the queue size reaches this value, the queue will be sent as a single batch to the backend services.
168+
* @return size_t : the queue size at which a batch will be sent.
169+
*/
170+
CSP_NO_EXPORT size_t GetMaxQueueSize() const { return MaxQueueSize; }
171+
83172
private:
84173
AnalyticsSystem(); // This constructor is only provided to appease the wrapper generator and should not be used
85174
CSP_NO_EXPORT AnalyticsSystem(csp::web::WebClient* InWebClient, const csp::ClientUserAgent* AgentInfo, common::LogSystem& LogSystem);
86175
~AnalyticsSystem();
87176

177+
void SetTimeSinceLastQueueSend(std::chrono::milliseconds NewTimeSinceLastQueueSend);
178+
179+
// This is a utility function to allow us to test the queueing functionality in a reasonable time frame.
180+
void __SetQueueSendRateAndMaxSize(std::chrono::milliseconds NewSendRate, size_t NewQueueSize);
181+
88182
std::unique_ptr<csp::services::ApiBase> AnalyticsApi;
89183

184+
std::unique_ptr<class AnalyticsQueueEventHandler> EventHandler;
185+
std::mutex AnalyticsQueueLock;
186+
std::vector<std::shared_ptr<csp::services::generated::userservice::AnalyticsRecord>> AnalyticsRecordQueue;
187+
90188
const csp::ClientUserAgent* UserAgentInfo;
189+
std::chrono::milliseconds AnalyticsQueueSendRate;
190+
std::chrono::milliseconds TimeSinceLastQueueSend;
191+
size_t MaxQueueSize;
91192
};
92193

93194
} // namespace csp::systems

0 commit comments

Comments
 (0)