Files
UnrealEngine/Engine/Source/Runtime/Analytics/AnalyticsET/Private/AnalyticsSessionSummarySender.cpp
2025-05-18 13:04:45 +08: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(*UserId);
TempSummaryProvider->SetAppID(*AppId);
TempSummaryProvider->SetAppVersion(*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;
}