Files
UnrealEngineUWP/Engine/Source/Runtime/Analytics/AnalyticsET/Private/AnalyticsSessionSummarySender.cpp
Patrick Laflamme cb3aaf9000 Fixed analytics summary system losing type information.
- Instead of converting summary properties to string duing session aggregation, put properties in FAnalyticsEventAttribute instances to preserve the type information.
Added MonitorEngineVersion, MonitorReportCount, MonitorEnsureCount, MonitorAssertCount to CRC analytics summary.
Added MissingDataFrom to the analytics summary when the property file from a collaboration process failed to load.
Fixed the analytics summary manager to aggreage and produce a report even if the helper process data couldn't be loaded.

#rb Jamie.Dale

[CL 16382795 by Patrick Laflamme in ue5-main branch]
2021-05-19 06:22:37 -04:00

76 lines
4.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnalyticsSessionSummarySender.h"
#include "AnalyticsET.h"
#include "AnalyticsEventAttribute.h"
#include "IAnalyticsProviderET.h"
#include "Misc/EngineVersion.h"
DEFINE_LOG_CATEGORY_STATIC(LogAnalyticsSessionSummarySender, Verbose, All);
FAnalyticsSessionSummarySender::FAnalyticsSessionSummarySender(IAnalyticsProviderET& Provider, TFunction<bool(const FAnalyticsEventAttribute&)> ShouldEmitFilterFunc)
: AnalyticsProvider(Provider)
, ShouldEmitPropFunc(MoveTemp(ShouldEmitFilterFunc))
{
}
bool FAnalyticsSessionSummarySender::SendSessionSummary(const FString& UserId, const FString& AppId, const FString& AppVersion, const FString& SessionId, const TArray<FAnalyticsEventAttribute>& Properties)
{
TArray<FAnalyticsEventAttribute> AnalyticsAttributes;
// Track which app/user is sending the summary (summary can be sent by another process (CrashReportClient) or another instance in case of crash/abnormal terminaison.
AnalyticsAttributes.Emplace(TEXT("SummarySenderAppId"), AnalyticsProvider.GetAppID());
AnalyticsAttributes.Emplace(TEXT("SummarySenderAppVersion"), AnalyticsProvider.GetAppVersion());
AnalyticsAttributes.Emplace(TEXT("SummarySenderEngineVersion"), FEngineVersion::Current().ToString(EVersionComponent::Changelist)); // Same as in EditorSessionSummaryWriter.cpp
AnalyticsAttributes.Emplace(TEXT("SummarySenderUserId"), AnalyticsProvider.GetUserID());
AnalyticsAttributes.Emplace(TEXT("SummarySenderSessionId"), AnalyticsProvider.GetSessionID()); // Not stripping the {} around the GUID like EditorSessionSummaryWriter does with SessionId.
for (const FAnalyticsEventAttribute& Property : Properties)
{
// Function is not bound or returns true.
if (!ShouldEmitPropFunc || ShouldEmitPropFunc(Property))
{
AnalyticsAttributes.Emplace(Property);
}
}
// Sort the keys to makes it easier to find specific ones when inspecting the network payload (mainly for testing/debugging purpose).
AnalyticsAttributes.Sort([](const FAnalyticsEventAttribute& Lhs, const FAnalyticsEventAttribute& Rhs){ return Lhs.GetName() < Rhs.GetName(); });
// Sending the summary event of the current process analytic session?
if (AnalyticsProvider.GetSessionID().Contains(SessionId)) // The string (GUID) returned by GetSessionID() is surrounded with braces like "{3FEA3232-...}" while Session.SessionId is not -> "3FEA3232-..."
{
AnalyticsProvider.RecordEvent(TEXT("SessionSummary"), AnalyticsAttributes);
}
else // The summary was created by another process/instance in a different session. (Ex: Editor sending a summary of a previoulsy crashed instance or CrashReportClient sending it on behalf of the Editor)
{
// The provider sending a 'summary event' created by another instance/process must parametrize its post request 'as if' it was sent from the instance/session that created it (backend expectation).
// Create a new provider to avoid interfering with the current session events. (ex. if another thread sends telemetry at the same time, don't accidently tag it with the wrong SessionID, AppID, etc.).
TSharedPtr<IAnalyticsProviderET> TempSummaryProvider = FAnalyticsET::Get().CreateAnalyticsProvider(AnalyticsProvider.GetConfig());
// Reconfigure the analytics provider to sent the summary event 'as if' it was sent by the process that created it. This is required by the analytics backend.
FGuid SessionGuid;
FGuid::Parse(*SessionId, SessionGuid);
TempSummaryProvider->SetUserID(CopyTemp(*UserId));
TempSummaryProvider->SetAppID(CopyTemp(*AppId));
TempSummaryProvider->SetAppVersion(CopyTemp(*AppVersion));
TempSummaryProvider->SetSessionID(SessionGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces)); // Ensure to put back the {} around the GUID.
// Send the summary.
TempSummaryProvider->RecordEvent(TEXT("SessionSummary"), AnalyticsAttributes);
// The temporary provider is about to be deleted (going out of scope), ensure it sents its report.
TempSummaryProvider->BlockUntilFlushed(2.0f);
}
// For debugging.
//for (const FAnalyticsEventAttribute& Att : AnalyticsAttributes)
//{
// UE_LOG(LogAnalyticsSessionSummarySender, Display, TEXT("Attr %s = %s"), *Att.GetName(), *Att.GetValue());
//}
UE_LOG(LogAnalyticsSessionSummarySender, Log, TEXT("Sent summary session report for: AppId=%s SessionId=%s"), *AppId, *SessionId);
return true;
}