2019-12-26 15:32:37 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-03 16:26:48 -04:00
# include "EditorAnalyticsSession.h"
# include "Modules/ModuleManager.h"
2020-03-20 17:10:14 -04:00
# include "Internationalization/Regex.h"
2020-03-20 17:25:16 -04:00
# include "HAL/PlatformProcess.h"
# include "HAL/FileManager.h"
2021-01-18 10:45:38 -04:00
# include "Misc/EngineVersion.h"
2021-01-20 13:41:51 -04:00
# include "Misc/Guid.h"
2020-03-20 17:25:16 -04:00
# include "Misc/Paths.h"
2019-10-03 16:26:48 -04:00
IMPLEMENT_MODULE ( FEditorAnalyticsSessionModule , EditorAnalyticsSession ) ;
namespace EditorAnalyticsDefs
{
static const FString FalseValueString ( TEXT ( " 0 " ) ) ;
static const FString TrueValueString ( TEXT ( " 1 " ) ) ;
static const FString DefaultUserActivity ( TEXT ( " Unknown " ) ) ;
static const FString UnknownProjectValueString ( TEXT ( " UnknownProject " ) ) ;
2020-02-18 15:12:51 -05:00
static const FString UnknownAppIdString ( TEXT ( " UnknownAppId " ) ) ;
static const FString UnknownAppVersionString ( TEXT ( " UnknownAppVersion " ) ) ;
static const FString UnknownUserIdString ( TEXT ( " UnknownUserID " ) ) ;
2020-06-23 18:40:00 -04:00
// The storage location is used to version the different data format. This is to prevent one version of the Editor/CRC to send sessions produced by another incompatible version.
// Version 1_0 : Used from creation up to 4.25.0 release (included).
2020-08-11 01:36:57 -04:00
// Version 1_1 : To avoid public API changes in 4.25.1, TotalUserInactivitySeconds was repurposed to contain the SessionDuration read from FPlatformTime::Seconds() to detect cases where the user system date time is unreliable.
// Version 1_2 : Removed TotalUserInactivitySeconds and added SessionDuration.
2020-09-24 00:43:27 -04:00
// Version 1_3 : Added SessionTickCount, UserInteractionCount, IsCrcExeMissing, IsUserLoggingOut, MonitorExitCode and readded lost code to save/load/delete IsLowDriveSpace for 4.26.0.
2020-11-24 18:42:39 -04:00
// Version 1_4 : Added CommandLine, EngineTickCount, LastTickTimestamp, DeathTimestamp and IsDebuggerIgnored for 4.26.0.
2021-02-02 16:47:04 -04:00
// Version 1_5 : Added Stall Detector stats for 5.0.
2019-10-03 16:26:48 -04:00
static const FString StoreId ( TEXT ( " Epic Games " ) ) ;
2020-08-11 01:36:57 -04:00
static const FString SessionSummaryRoot ( TEXT ( " Unreal Engine/Session Summary " ) ) ;
static const FString SessionSummarySection_1_0 = SessionSummaryRoot / TEXT ( " 1_0 " ) ; // The session format used by older versions.
static const FString SessionSummarySection_1_1 = SessionSummaryRoot / TEXT ( " 1_1 " ) ;
2020-09-24 00:43:27 -04:00
static const FString SessionSummarySection_1_2 = SessionSummaryRoot / TEXT ( " 1_2 " ) ;
2020-11-24 18:42:39 -04:00
static const FString SessionSummarySection_1_3 = SessionSummaryRoot / TEXT ( " 1_3 " ) ;
2021-02-02 16:47:04 -04:00
static const FString SessionSummarySection_1_4 = SessionSummaryRoot / TEXT ( " 1_4 " ) ;
static const FString SessionSummarySection = SessionSummaryRoot / TEXT ( " 1_5 " ) ; // The current session format.
2019-10-03 16:26:48 -04:00
static const FString GlobalLockName ( TEXT ( " UE4_SessionSummary_Lock " ) ) ;
static const FString SessionListStoreKey ( TEXT ( " SessionList " ) ) ;
2020-02-18 15:12:51 -05:00
// capture context
static const FString AppIdStoreKey ( TEXT ( " AppId " ) ) ;
static const FString AppVersionStoreKey ( TEXT ( " AppVersion " ) ) ;
static const FString UserIdStoreKey ( TEXT ( " UserId " ) ) ;
2019-10-03 16:26:48 -04:00
// general values
static const FString ProjectNameStoreKey ( TEXT ( " ProjectName " ) ) ;
static const FString ProjectIDStoreKey ( TEXT ( " ProjectID " ) ) ;
static const FString ProjectDescriptionStoreKey ( TEXT ( " ProjectDescription " ) ) ;
static const FString ProjectVersionStoreKey ( TEXT ( " ProjectVersion " ) ) ;
static const FString EngineVersionStoreKey ( TEXT ( " EngineVersion " ) ) ;
static const FString PlatformProcessIDStoreKey ( TEXT ( " PlatformProcessID " ) ) ;
2020-04-03 16:23:51 -04:00
static const FString MonitorProcessIDStoreKey ( TEXT ( " MonitorProcessID " ) ) ;
static const FString ExitCodeStoreKey ( TEXT ( " ExitCode " ) ) ;
2020-04-14 16:52:27 -04:00
static const FString MonitorExceptCodeStoreKey ( TEXT ( " MonitorExceptCode " ) ) ;
2020-09-24 00:43:27 -04:00
static const FString MonitorExitCodeStoreKey ( TEXT ( " MonitorExitCode " ) ) ;
static const FString SessionTickCountStoreKey ( TEXT ( " SessionTickCount " ) ) ;
2020-11-24 18:42:39 -04:00
static const FString EngineTickCountStoreKey ( TEXT ( " EngineTickCount " ) ) ;
2020-09-24 00:43:27 -04:00
static const FString UserInteractionCountStoreKey ( TEXT ( " UserInteractionCount " ) ) ;
2020-11-24 18:42:39 -04:00
static const FString CommandLineStoreKey ( TEXT ( " CommandLine " ) ) ;
2019-10-03 16:26:48 -04:00
2021-02-02 16:47:04 -04:00
// stall detector
static const FString TotalStallCountStoreKey ( TEXT ( " TotalStallCount " ) ) ;
static const FString TotalStallReportedStoreKey ( TEXT ( " TotalStallReported " ) ) ;
static const FString TopStallNameStoreKey ( TEXT ( " TopStallName " ) ) ;
static const FString TopStallBudgetSecondsStoreKey ( TEXT ( " TopStallBudgetSeconds " ) ) ;
static const FString TopStallOverageSecondsStoreKey ( TEXT ( " TopStallOverageSeconds " ) ) ;
static const FString TopStallTriggerCountStoreKey ( TEXT ( " TopStallTriggerCount " ) ) ;
2019-10-03 16:26:48 -04:00
// timestamps
static const FString StartupTimestampStoreKey ( TEXT ( " StartupTimestamp " ) ) ;
static const FString TimestampStoreKey ( TEXT ( " Timestamp " ) ) ;
2019-11-13 11:28:09 -05:00
static const FString SessionDurationStoreKey ( TEXT ( " SessionDuration " ) ) ;
2019-10-03 16:26:48 -04:00
static const FString Idle1MinStoreKey ( TEXT ( " Idle1Min " ) ) ;
static const FString Idle5MinStoreKey ( TEXT ( " Idle5Min " ) ) ;
static const FString Idle30MinStoreKey ( TEXT ( " Idle30Min " ) ) ;
2020-04-14 16:52:27 -04:00
static const FString TotalEditorInactivitySecondsStoreKey ( TEXT ( " TotalEditorInactivitySecs " ) ) ;
2019-10-03 16:26:48 -04:00
static const FString CurrentUserActivityStoreKey ( TEXT ( " CurrentUserActivity " ) ) ;
static const FString PluginsStoreKey ( TEXT ( " Plugins " ) ) ;
static const FString AverageFPSStoreKey ( TEXT ( " AverageFPS " ) ) ;
2020-11-24 18:42:39 -04:00
static const FString LastTickTimestampStoreKey ( TEXT ( " LastTickTimestamp " ) ) ;
static const FString DeathTimestampStoreKey ( TEXT ( " DeathTimestamp " ) ) ;
2019-10-03 16:26:48 -04:00
// GPU details
static const FString DesktopGPUAdapterStoreKey ( TEXT ( " DesktopGPUAdapter " ) ) ;
static const FString RenderingGPUAdapterStoreKey ( TEXT ( " RenderingGPUAdapter " ) ) ;
static const FString GPUVendorIDStoreKey ( TEXT ( " GPUVendorID " ) ) ;
static const FString GPUDeviceIDStoreKey ( TEXT ( " GPUDeviceID " ) ) ;
static const FString GRHIDeviceRevisionStoreKey ( TEXT ( " GRHIDeviceRevision " ) ) ;
static const FString GRHIAdapterInternalDriverVersionStoreKey ( TEXT ( " GRHIAdapterInternalDriverVersion " ) ) ;
static const FString GRHIAdapterUserDriverVersionStoreKey ( TEXT ( " GRHIAdapterUserDriverVersion " ) ) ;
2020-09-24 00:43:27 -04:00
static const FString GRHINameStoreKey ( TEXT ( " GRHIName " ) ) ;
2019-10-03 16:26:48 -04:00
// CPU details
static const FString TotalPhysicalRAMStoreKey ( TEXT ( " TotalPhysicalRAM " ) ) ;
static const FString CPUPhysicalCoresStoreKey ( TEXT ( " CPUPhysicalCores " ) ) ;
static const FString CPULogicalCoresStoreKey ( TEXT ( " CPULogicalCores " ) ) ;
static const FString CPUVendorStoreKey ( TEXT ( " CPUVendor " ) ) ;
static const FString CPUBrandStoreKey ( TEXT ( " CPUBrand " ) ) ;
// OS details
static const FString OSMajorStoreKey ( TEXT ( " OSMajor " ) ) ;
static const FString OSMinorStoreKey ( TEXT ( " OSMinor " ) ) ;
static const FString OSVersionStoreKey ( TEXT ( " OSVersion " ) ) ;
static const FString bIs64BitOSStoreKey ( TEXT ( " bIs64BitOS " ) ) ;
// boolean flags
static const FString IsCrashStoreKey ( TEXT ( " IsCrash " ) ) ;
static const FString IsGPUCrashStoreKey ( TEXT ( " IsGPUCrash " ) ) ;
static const FString IsDebuggerStoreKey ( TEXT ( " IsDebugger " ) ) ;
2020-11-24 18:42:39 -04:00
static const FString IsDebuggerIgnoredStoreKey ( TEXT ( " IsDebuggerIgnored " ) ) ;
2019-10-03 16:26:48 -04:00
static const FString WasDebuggerStoreKey ( TEXT ( " WasEverDebugger " ) ) ;
static const FString IsVanillaStoreKey ( TEXT ( " IsVanilla " ) ) ;
2020-11-24 18:42:39 -04:00
static const FString IsTerminatingStoreKey ( TEXT ( " Terminating " ) ) ;
2019-10-03 16:26:48 -04:00
static const FString WasShutdownStoreKey ( TEXT ( " WasShutdown " ) ) ;
2020-09-24 00:43:27 -04:00
static const FString IsUserLoggingOutStoreKey ( TEXT ( " IsUserLoggingOut " ) ) ;
2019-10-03 16:26:48 -04:00
static const FString IsInPIEStoreKey ( TEXT ( " IsInPIE " ) ) ;
static const FString IsInEnterpriseStoreKey ( TEXT ( " IsInEnterprise " ) ) ;
static const FString IsInVRModeStoreKey ( TEXT ( " IsInVRMode " ) ) ;
2020-09-24 00:43:27 -04:00
static const FString IsCrcExeMissingStoreKey ( TEXT ( " IsCrcExeMissing " ) ) ;
static const FString IsLowDriveSpaceStoreKey ( TEXT ( " IsLowDriveSpace " ) ) ;
2019-10-03 16:26:48 -04:00
}
// Utilities for writing to stored values
namespace EditorAnalyticsUtils
{
static FString TimestampToString ( FDateTime InTimestamp )
{
return LexToString ( InTimestamp . ToUnixTimestamp ( ) ) ;
}
static FDateTime StringToTimestamp ( FString InString )
{
int64 TimestampUnix ;
if ( LexTryParseString ( TimestampUnix , * InString ) )
{
return FDateTime : : FromUnixTimestamp ( TimestampUnix ) ;
}
return FDateTime : : MinValue ( ) ;
}
static FString BoolToStoredString ( bool bInValue )
{
return bInValue ? EditorAnalyticsDefs : : TrueValueString : EditorAnalyticsDefs : : FalseValueString ;
}
static bool GetStoredBool ( const FString & SectionName , const FString & StoredKey )
{
FString StoredString = EditorAnalyticsDefs : : FalseValueString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , StoredKey , StoredString ) ;
return StoredString = = EditorAnalyticsDefs : : TrueValueString ;
}
static FString GetSessionStorageLocation ( const FString & SessionID )
{
return EditorAnalyticsDefs : : SessionSummarySection + TEXT ( " / " ) + SessionID ;
}
2020-03-20 17:10:14 -04:00
static FString GetSessionEventLogDir ( )
{
return FString : : Printf ( TEXT ( " %sAnalytics " ) , FPlatformProcess : : ApplicationSettingsDir ( ) ) ;
}
2020-11-24 18:42:39 -04:00
static bool IsSavingIndividualFieldFastAndThreadSafe ( )
{
# if PLATFORM_WINDOWS
return true ; // Saving individual field to registry on Windows is fast and thread safe.
# else
return false ; // On other platforms, we load/update/save an entire .ini file. This is not fast and not thread safe.
# endif
}
2020-03-20 17:10:14 -04:00
static void LogSessionEvent ( FEditorAnalyticsSession & Session , FEditorAnalyticsSession : : EEventType InEventType , const FDateTime & InTimestamp )
{
2020-11-24 18:42:39 -04:00
// This is primary logging mechanims. It works across all platforms and is rather robust. It uses the robustness of the file system to log events. It creates a file
// (a directory) for each event and encodes the event payload in the file name. This doesn't require any fancy synchronization or complicated concurrent file IO
// implementation. Since the number of events is low (0 to 5 per session), that's a straight forward working solution. The files are deleted when the session is
// deleted. Also avoid memory allocation, this can be called when the heap is corrupted.
2020-03-20 17:10:14 -04:00
TCHAR TimestampStr [ 256 ] ;
FCString : : Sprintf ( TimestampStr , TFormatSpecifier < decltype ( InTimestamp . ToUnixTimestamp ( ) ) > : : GetFormatSpecifier ( ) , InTimestamp . ToUnixTimestamp ( ) ) ;
TCHAR Pathname [ 512 ] ;
2020-06-23 18:40:00 -04:00
FCString : : Sprintf ( Pathname , TEXT ( " %s/%s_%d_%d_%d_%d_%d_%s " ) ,
2020-03-20 17:10:14 -04:00
* EditorAnalyticsUtils : : GetSessionEventLogDir ( ) ,
* Session . SessionId ,
2020-06-23 18:40:00 -04:00
static_cast < int32 > ( InEventType ) ,
2020-03-20 17:10:14 -04:00
FPlatformAtomics : : AtomicRead ( & Session . Idle1Min ) ,
FPlatformAtomics : : AtomicRead ( & Session . Idle5Min ) ,
FPlatformAtomics : : AtomicRead ( & Session . Idle30Min ) ,
2020-08-11 01:36:57 -04:00
FPlatformAtomics : : AtomicRead ( & Session . SessionDuration ) ,
2020-03-20 17:10:14 -04:00
TimestampStr ) ;
IFileManager : : Get ( ) . MakeDirectory ( Pathname , /*Tree*/ true ) ;
2020-11-24 18:42:39 -04:00
// As a secondary/backup mechanism, directly save the info in the session if this is fast and safe. This allocate memory, so that's not perfect in case of crash.
if ( IsSavingIndividualFieldFastAndThreadSafe ( ) )
{
const FString StorageLocation = EditorAnalyticsUtils : : GetSessionStorageLocation ( Session . SessionId ) ;
switch ( InEventType )
{
case FEditorAnalyticsSession : : EEventType : : Crashed :
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : IsCrashStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( true ) ) ;
break ;
case FEditorAnalyticsSession : : EEventType : : GpuCrashed :
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : IsGPUCrashStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( true ) ) ;
break ;
case FEditorAnalyticsSession : : EEventType : : Terminated :
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : IsTerminatingStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( true ) ) ;
break ;
case FEditorAnalyticsSession : : EEventType : : Shutdown :
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : WasShutdownStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( true ) ) ;
break ;
case FEditorAnalyticsSession : : EEventType : : LogOut :
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : IsUserLoggingOutStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( true ) ) ;
break ;
default :
break ;
}
// Save the timestamps.
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : Idle1MinStoreKey , FString : : FromInt ( FPlatformAtomics : : AtomicRead ( & Session . Idle1Min ) ) ) ;
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : Idle5MinStoreKey , FString : : FromInt ( FPlatformAtomics : : AtomicRead ( & Session . Idle5Min ) ) ) ;
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : Idle30MinStoreKey , FString : : FromInt ( FPlatformAtomics : : AtomicRead ( & Session . Idle30Min ) ) ) ;
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : SessionDurationStoreKey , FString : : FromInt ( FPlatformAtomics : : AtomicRead ( & Session . SessionDuration ) ) ) ;
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : TimestampStoreKey , EditorAnalyticsUtils : : TimestampToString ( InTimestamp ) ) ;
}
2020-03-20 17:10:14 -04:00
}
/** Analyze the events logged with LogEvent() and update the session fields to reflect the last state of the session. */
static void UpdateSessionFromLogAnalysis ( FEditorAnalyticsSession & Session )
{
// Read and aggregate the log events. The event data is encoded in the directory names created by the logger
2020-06-23 18:40:00 -04:00
FRegexPattern Pattern ( TEXT ( R " ((^[a-fA-F0-9-]+) _ ( [ 0 - 9 ] + ) _ ( [ 0 - 9 ] + ) _ ( [ 0 - 9 ] + ) _ ( [ 0 - 9 ] + ) _ ( [ 0 - 9 ] + ) _ ( [ 0 - 9 ] + ) ) " )) ; // Need help with regex? Try https://regex101.com/
2020-03-20 17:10:14 -04:00
IFileManager : : Get ( ) . IterateDirectoryRecursively ( * EditorAnalyticsUtils : : GetSessionEventLogDir ( ) , [ & Session , & Pattern ] ( const TCHAR * Pathname , bool bIsDir )
{
if ( bIsDir )
{
FRegexMatcher Matcher ( Pattern , FPaths : : GetCleanFilename ( Pathname ) ) ;
if ( Matcher . FindNext ( ) & & Matcher . GetCaptureGroup ( 1 ) = = Session . SessionId )
{
FEditorAnalyticsSession : : EEventType EventType = static_cast < FEditorAnalyticsSession : : EEventType > ( FCString : : Atoi ( * Matcher . GetCaptureGroup ( 2 ) ) ) ; // Event
switch ( EventType )
{
2020-09-24 00:43:27 -04:00
case FEditorAnalyticsSession : : EEventType : : Crashed : Session . bCrashed = true ; break ;
case FEditorAnalyticsSession : : EEventType : : GpuCrashed : Session . bGPUCrashed = true ; break ;
case FEditorAnalyticsSession : : EEventType : : Terminated : Session . bIsTerminating = true ; break ;
case FEditorAnalyticsSession : : EEventType : : Shutdown : Session . bWasShutdown = true ; break ;
case FEditorAnalyticsSession : : EEventType : : LogOut : Session . bIsUserLoggingOut = true ; break ;
2020-03-20 17:10:14 -04:00
default : break ;
}
2020-06-23 18:40:00 -04:00
int32 ParsedTime = FCString : : Atoi ( * Matcher . GetCaptureGroup ( 3 ) ) ; // Idle1Min.
if ( ParsedTime > Session . Idle1Min )
2020-03-20 17:10:14 -04:00
{
2020-06-23 18:40:00 -04:00
Session . Idle1Min = ParsedTime ; // No concurrency expected when reloading (no need for atomic compare exchange)
2020-03-20 17:10:14 -04:00
}
2020-06-23 18:40:00 -04:00
ParsedTime = FCString : : Atoi ( * Matcher . GetCaptureGroup ( 4 ) ) ; // Idle5Min.
if ( ParsedTime > Session . Idle5Min )
2020-03-20 17:10:14 -04:00
{
2020-06-23 18:40:00 -04:00
Session . Idle5Min = ParsedTime ;
2020-03-20 17:10:14 -04:00
}
2020-06-23 18:40:00 -04:00
ParsedTime = FCString : : Atoi ( * Matcher . GetCaptureGroup ( 5 ) ) ; // Idle30Min.
if ( ParsedTime > Session . Idle30Min )
2020-03-20 17:10:14 -04:00
{
2020-06-23 18:40:00 -04:00
Session . Idle30Min = ParsedTime ;
}
2020-08-11 01:36:57 -04:00
ParsedTime = FCString : : Atoi ( * Matcher . GetCaptureGroup ( 6 ) ) ; // SessionDuration.
if ( ParsedTime > Session . SessionDuration )
2020-06-23 18:40:00 -04:00
{
2020-08-11 01:36:57 -04:00
Session . SessionDuration = ParsedTime ;
2020-03-20 17:10:14 -04:00
}
FDateTime ParsedTimestamp = FDateTime : : FromUnixTimestamp ( FCString : : Atoi64 ( * Matcher . GetCaptureGroup ( 6 ) ) ) ; // Unix timestamp (UTC)
if ( ParsedTimestamp > Session . Timestamp )
{
Session . Timestamp = ParsedTimestamp ;
}
}
}
return true ;
} ) ;
}
static void DeleteLogEvents ( const FEditorAnalyticsSession & Session )
{
// Gather the list of files
TArray < FString > SessionEventPaths ;
IFileManager : : Get ( ) . IterateDirectoryRecursively ( * EditorAnalyticsUtils : : GetSessionEventLogDir ( ) , [ & Session , & SessionEventPaths ] ( const TCHAR * Pathname , bool bIsDir )
{
if ( bIsDir )
{
if ( FPaths : : GetCleanFilename ( Pathname ) . StartsWith ( Session . SessionId ) )
{
SessionEventPaths . Emplace ( Pathname ) ;
}
}
return true ; // Continue
} ) ;
// Delete the session files.
for ( const FString & EventPathname : SessionEventPaths )
{
IFileManager : : Get ( ) . DeleteDirectory ( * EventPathname , /*RequiredExist*/ false , /*Tree*/ false ) ;
}
}
2019-10-03 16:26:48 -04:00
// Utility macros to make it easier to check that all fields are being written to.
2021-02-02 16:47:04 -04:00
# define GET_STORED_STRING(FieldName) \
{ \
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : FieldName # # StoreKey , Session . FieldName ) ; \
}
2019-10-03 16:26:48 -04:00
# define GET_STORED_INT(FieldName) \
{ \
FString FieldName # # Temp ; \
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : FieldName # # StoreKey , FieldName # # Temp ) ; \
Session . FieldName = FCString : : Atoi ( * FieldName # # Temp ) ; \
}
2021-02-02 16:47:04 -04:00
# define GET_STORED_FLOAT(FieldName) \
{ \
FString FieldName # # Temp ; \
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : FieldName # # StoreKey , FieldName # # Temp ) ; \
Session . FieldName = FCString : : Atof ( * FieldName # # Temp ) ; \
}
2019-10-03 16:26:48 -04:00
static void LoadInternal ( FEditorAnalyticsSession & Session , const FString & InSessionId )
{
Session . SessionId = InSessionId ;
FString SectionName = EditorAnalyticsUtils : : GetSessionStorageLocation ( Session . SessionId ) ;
2020-02-18 15:12:51 -05:00
GET_STORED_STRING ( AppId ) ;
GET_STORED_STRING ( AppVersion ) ;
GET_STORED_STRING ( UserId ) ;
2019-10-03 16:26:48 -04:00
GET_STORED_STRING ( ProjectName ) ;
GET_STORED_STRING ( ProjectID ) ;
GET_STORED_STRING ( ProjectDescription ) ;
GET_STORED_STRING ( ProjectVersion ) ;
GET_STORED_STRING ( EngineVersion ) ;
2020-11-24 18:42:39 -04:00
GET_STORED_STRING ( CommandLine ) ;
2019-10-03 16:26:48 -04:00
GET_STORED_INT ( PlatformProcessID ) ;
2020-04-03 16:23:51 -04:00
GET_STORED_INT ( MonitorProcessID ) ;
{
FString ExitCodeString ;
if ( FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : ExitCodeStoreKey , ExitCodeString ) )
{
Session . ExitCode . Emplace ( FCString : : Atoi ( * ExitCodeString ) ) ;
}
}
2019-10-03 16:26:48 -04:00
2020-04-14 16:52:27 -04:00
{
FString MonitorExceptCodeString ;
if ( FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : MonitorExceptCodeStoreKey , MonitorExceptCodeString ) )
{
Session . MonitorExceptCode . Emplace ( FCString : : Atoi ( * MonitorExceptCodeString ) ) ;
}
}
2020-09-24 00:43:27 -04:00
{
FString MonitorExitCodeString ;
if ( FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : MonitorExitCodeStoreKey , MonitorExitCodeString ) )
{
Session . MonitorExitCode . Emplace ( FCString : : Atoi ( * MonitorExitCodeString ) ) ;
}
}
2019-10-03 16:26:48 -04:00
// scope is just to isolate the temporary value
{
FString StartupTimestampString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : StartupTimestampStoreKey , StartupTimestampString ) ;
Session . StartupTimestamp = EditorAnalyticsUtils : : StringToTimestamp ( StartupTimestampString ) ;
}
{
FString TimestampString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TimestampStoreKey , TimestampString ) ;
Session . Timestamp = EditorAnalyticsUtils : : StringToTimestamp ( TimestampString ) ;
}
2020-11-24 18:42:39 -04:00
{
FString LastTickTimestampString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : LastTickTimestampStoreKey , LastTickTimestampString ) ;
Session . LastTickTimestamp = EditorAnalyticsUtils : : StringToTimestamp ( LastTickTimestampString ) ;
}
{
FString DeathTimestampString ;
if ( FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : DeathTimestampStoreKey , DeathTimestampString ) )
{
Session . DeathTimestamp . Emplace ( EditorAnalyticsUtils : : StringToTimestamp ( DeathTimestampString ) ) ;
}
}
2020-08-11 01:36:57 -04:00
GET_STORED_INT ( SessionDuration ) ;
2019-10-03 16:26:48 -04:00
GET_STORED_INT ( Idle1Min ) ;
GET_STORED_INT ( Idle5Min ) ;
GET_STORED_INT ( Idle30Min ) ;
2020-04-14 16:52:27 -04:00
GET_STORED_INT ( TotalEditorInactivitySeconds ) ;
2019-10-03 16:26:48 -04:00
GET_STORED_STRING ( CurrentUserActivity ) ;
{
FString PluginsString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : PluginsStoreKey , PluginsString ) ;
PluginsString . ParseIntoArray ( Session . Plugins , TEXT ( " , " ) ) ;
}
2021-02-02 16:47:04 -04:00
GET_STORED_FLOAT ( AverageFPS ) ;
2019-10-03 16:26:48 -04:00
2020-09-24 00:43:27 -04:00
GET_STORED_INT ( SessionTickCount ) ;
2020-11-24 18:42:39 -04:00
GET_STORED_INT ( EngineTickCount ) ;
2020-09-24 00:43:27 -04:00
GET_STORED_INT ( UserInteractionCount ) ;
2021-02-02 16:47:04 -04:00
GET_STORED_INT ( TotalStallCount ) ;
GET_STORED_INT ( TotalStallReported ) ;
GET_STORED_STRING ( TopStallName ) ;
GET_STORED_FLOAT ( TopStallBudgetSeconds ) ;
GET_STORED_FLOAT ( TopStallOverageSeconds ) ;
GET_STORED_INT ( TopStallTriggerCount ) ;
2019-10-03 16:26:48 -04:00
GET_STORED_STRING ( DesktopGPUAdapter ) ;
GET_STORED_STRING ( RenderingGPUAdapter ) ;
GET_STORED_INT ( GPUVendorID ) ;
GET_STORED_INT ( GPUDeviceID ) ;
GET_STORED_INT ( GRHIDeviceRevision ) ;
GET_STORED_STRING ( GRHIAdapterInternalDriverVersion ) ;
GET_STORED_STRING ( GRHIAdapterUserDriverVersion ) ;
2020-09-24 00:43:27 -04:00
GET_STORED_STRING ( GRHIName ) ;
2019-10-03 16:26:48 -04:00
{
FString TotalPhysicalRAMString ;
2020-03-12 13:36:47 -04:00
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TotalPhysicalRAMStoreKey , TotalPhysicalRAMString ) ;
2019-10-03 16:26:48 -04:00
Session . TotalPhysicalRAM = FCString : : Atoi64 ( * TotalPhysicalRAMString ) ;
}
GET_STORED_INT ( CPUPhysicalCores ) ;
GET_STORED_INT ( CPULogicalCores ) ;
GET_STORED_STRING ( CPUVendor ) ;
GET_STORED_STRING ( CPUBrand ) ;
GET_STORED_STRING ( OSMajor ) ;
GET_STORED_STRING ( OSMinor ) ;
GET_STORED_STRING ( OSVersion ) ;
Session . bIs64BitOS = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : bIs64BitOSStoreKey ) ;
Session . bCrashed = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsCrashStoreKey ) ;
Session . bGPUCrashed = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsGPUCrashStoreKey ) ;
Session . bIsDebugger = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsDebuggerStoreKey ) ;
2020-11-24 18:42:39 -04:00
Session . bIsDebuggerIgnored = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsDebuggerIgnoredStoreKey ) ;
2019-10-03 16:26:48 -04:00
Session . bWasEverDebugger = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : WasDebuggerStoreKey ) ;
Session . bIsVanilla = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsVanillaStoreKey ) ;
2020-11-24 18:42:39 -04:00
Session . bIsTerminating = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsTerminatingStoreKey ) ;
2019-10-03 16:26:48 -04:00
Session . bWasShutdown = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : WasShutdownStoreKey ) ;
2020-09-24 00:43:27 -04:00
Session . bIsUserLoggingOut = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsUserLoggingOutStoreKey ) ;
2019-10-03 16:26:48 -04:00
Session . bIsInPIE = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsInPIEStoreKey ) ;
Session . bIsInVRMode = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsInVRModeStoreKey ) ;
Session . bIsInEnterprise = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsInEnterpriseStoreKey ) ;
2020-09-24 00:43:27 -04:00
Session . bIsLowDriveSpace = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsLowDriveSpaceStoreKey ) ;
Session . bIsCrcExeMissing = EditorAnalyticsUtils : : GetStoredBool ( SectionName , EditorAnalyticsDefs : : IsCrcExeMissingStoreKey ) ;
2020-03-20 17:10:14 -04:00
// Analyze the logged events and update corresponding fields in the session.
UpdateSessionFromLogAnalysis ( Session ) ;
2019-10-03 16:26:48 -04:00
}
# undef GET_STORED_INT
# undef GET_STORED_STRING
static TArray < FString > GetSessionList ( )
{
FString SessionListString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , EditorAnalyticsDefs : : SessionSummarySection , EditorAnalyticsDefs : : SessionListStoreKey , SessionListString ) ;
TArray < FString > SessionIDs ;
SessionListString . ParseIntoArray ( SessionIDs , TEXT ( " , " ) ) ;
return MoveTemp ( SessionIDs ) ;
}
}
2020-12-09 16:15:57 -04:00
TUniquePtr < FSystemWideCriticalSection > FEditorAnalyticsSession : : StoredValuesLock ;
std : : atomic < uint64 > FEditorAnalyticsSession : : StoredValuesLockOwnerInfo ( 0 ) ;
2019-10-03 16:26:48 -04:00
FEditorAnalyticsSession : : FEditorAnalyticsSession ( )
{
2020-02-18 15:12:51 -05:00
AppId = EditorAnalyticsDefs : : UnknownAppIdString ;
AppVersion = EditorAnalyticsDefs : : UnknownAppVersionString ;
UserId = EditorAnalyticsDefs : : UnknownUserIdString ;
2019-10-03 16:26:48 -04:00
ProjectName = EditorAnalyticsDefs : : UnknownProjectValueString ;
StartupTimestamp = FDateTime : : MinValue ( ) ;
Timestamp = FDateTime : : MinValue ( ) ;
CurrentUserActivity = EditorAnalyticsDefs : : DefaultUserActivity ;
bIs64BitOS = false ;
bCrashed = false ;
bGPUCrashed = false ;
bIsDebugger = false ;
bWasEverDebugger = false ;
bIsVanilla = false ;
bIsTerminating = false ;
bWasShutdown = false ;
2020-09-24 00:43:27 -04:00
bIsUserLoggingOut = false ;
2019-10-03 16:26:48 -04:00
bIsInPIE = false ;
bIsInEnterprise = false ;
bIsInVRMode = false ;
2019-10-31 05:49:24 -04:00
bAlreadySaved = false ;
2019-10-21 06:13:29 -04:00
bIsLowDriveSpace = false ;
2020-09-24 00:43:27 -04:00
bIsCrcExeMissing = false ;
2020-11-24 18:42:39 -04:00
bIsDebuggerIgnored = false ;
2019-10-03 16:26:48 -04:00
}
bool FEditorAnalyticsSession : : Lock ( FTimespan Timeout )
{
2020-12-09 16:15:57 -04:00
// If Lock() is called recursively from a thread already owning the lock, fire an ensure. FSystemWideCriticalSection doesn't support recursive locking correctly.
if ( ! ensure ( ! IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return true ;
}
2020-12-09 16:15:57 -04:00
// Try to acquire the lock.
TUniquePtr < FSystemWideCriticalSection > TempLock = MakeUnique < FSystemWideCriticalSection > ( EditorAnalyticsDefs : : GlobalLockName , Timeout ) ;
// If the lock is acquired.
if ( TempLock & & TempLock - > IsValid ( ) )
2019-10-03 16:26:48 -04:00
{
2020-12-09 16:15:57 -04:00
// The lock was successfully acquired by this thread, keep it until Unlock() is called.
StoredValuesLock = MoveTemp ( TempLock ) ;
static_assert ( sizeof ( FPlatformTLS : : GetCurrentThreadId ( ) ) = = sizeof ( uint32 ) , " Encoding below assume the thread Id only uses 32 bits " ) ;
2020-12-14 09:35:27 -04:00
StoredValuesLockOwnerInfo . store ( ( ( 1ull < < ( sizeof ( uint32 ) * 8 ) ) ) | FPlatformTLS : : GetCurrentThreadId ( ) ) ; // 32 bits for thread id, 1 bit for 'is taken' so that threadId 0 is supported.
2020-12-09 16:15:57 -04:00
return true ;
2019-10-03 16:26:48 -04:00
}
2020-12-09 16:15:57 -04:00
return false ; // Failed to get the lock within the allowed time.
2019-10-03 16:26:48 -04:00
}
void FEditorAnalyticsSession : : Unlock ( )
{
2020-12-09 16:15:57 -04:00
// If Unlock() is called from a non-owning thread or recursively from an owning thread, fire an ensure. FSystemWideCriticalSection doesn't support recursive locking correctly.
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return ;
}
2020-12-09 16:15:57 -04:00
StoredValuesLock . Reset ( ) ;
StoredValuesLockOwnerInfo . store ( 0 ) ;
2019-10-03 16:26:48 -04:00
}
2020-12-09 16:15:57 -04:00
bool FEditorAnalyticsSession : : IsLockedBy ( uint32 ThreadId )
2019-10-03 16:26:48 -04:00
{
2020-12-09 16:15:57 -04:00
// Check if the calling thread has the lock.
uint64 LockInfo = StoredValuesLockOwnerInfo . load ( ) ;
return LockInfo ! = 0 & & ( LockInfo & 0xFFFFFFFF ) = = ThreadId ;
2019-10-03 16:26:48 -04:00
}
bool FEditorAnalyticsSession : : Save ( )
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return false ;
}
2019-10-31 05:49:24 -04:00
const FString StorageLocation = EditorAnalyticsUtils : : GetSessionStorageLocation ( SessionId ) ;
if ( ! bAlreadySaved )
{
const FString PluginsString = FString : : Join ( Plugins , TEXT ( " , " ) ) ;
2020-03-06 12:23:58 -05:00
TMap < FString , FString > KeyValues = {
{ EditorAnalyticsDefs : : EngineVersionStoreKey , EngineVersion } ,
2020-11-24 18:42:39 -04:00
{ EditorAnalyticsDefs : : CommandLineStoreKey , CommandLine } ,
2020-03-06 12:23:58 -05:00
{ EditorAnalyticsDefs : : PlatformProcessIDStoreKey , FString : : FromInt ( PlatformProcessID ) } ,
2020-04-03 16:23:51 -04:00
{ EditorAnalyticsDefs : : MonitorProcessIDStoreKey , FString : : FromInt ( MonitorProcessID ) } ,
2020-03-06 12:23:58 -05:00
{ EditorAnalyticsDefs : : DesktopGPUAdapterStoreKey , DesktopGPUAdapter } ,
{ EditorAnalyticsDefs : : RenderingGPUAdapterStoreKey , RenderingGPUAdapter } ,
{ EditorAnalyticsDefs : : GPUVendorIDStoreKey , FString : : FromInt ( GPUVendorID ) } ,
{ EditorAnalyticsDefs : : GPUDeviceIDStoreKey , FString : : FromInt ( GPUDeviceID ) } ,
{ EditorAnalyticsDefs : : GRHIDeviceRevisionStoreKey , FString : : FromInt ( GRHIDeviceRevision ) } ,
{ EditorAnalyticsDefs : : GRHIAdapterInternalDriverVersionStoreKey , GRHIAdapterUserDriverVersion } ,
{ EditorAnalyticsDefs : : GRHIAdapterUserDriverVersionStoreKey , GRHIAdapterUserDriverVersion } ,
2020-09-24 00:43:27 -04:00
{ EditorAnalyticsDefs : : GRHINameStoreKey , GRHIName } ,
2020-03-06 12:23:58 -05:00
{ EditorAnalyticsDefs : : TotalPhysicalRAMStoreKey , FString : : Printf ( TEXT ( " %llu " ) , TotalPhysicalRAM ) } ,
{ EditorAnalyticsDefs : : CPUPhysicalCoresStoreKey , FString : : FromInt ( CPUPhysicalCores ) } ,
{ EditorAnalyticsDefs : : CPULogicalCoresStoreKey , FString : : FromInt ( CPULogicalCores ) } ,
{ EditorAnalyticsDefs : : CPUVendorStoreKey , CPUVendor } ,
{ EditorAnalyticsDefs : : CPUBrandStoreKey , CPUBrand } ,
{ EditorAnalyticsDefs : : StartupTimestampStoreKey , EditorAnalyticsUtils : : TimestampToString ( StartupTimestamp ) } ,
{ EditorAnalyticsDefs : : OSMajorStoreKey , OSMajor } ,
{ EditorAnalyticsDefs : : OSMinorStoreKey , OSMinor } ,
{ EditorAnalyticsDefs : : OSVersionStoreKey , OSVersion } ,
{ EditorAnalyticsDefs : : bIs64BitOSStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIs64BitOS ) } ,
2020-09-24 00:43:27 -04:00
{ EditorAnalyticsDefs : : IsCrcExeMissingStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsCrcExeMissing ) } ,
2020-03-06 12:23:58 -05:00
{ EditorAnalyticsDefs : : PluginsStoreKey , PluginsString } ,
{ EditorAnalyticsDefs : : AppIdStoreKey , AppId } ,
{ EditorAnalyticsDefs : : AppVersionStoreKey , AppVersion } ,
{ EditorAnalyticsDefs : : UserIdStoreKey , UserId } ,
} ;
FPlatformMisc : : SetStoredValues ( EditorAnalyticsDefs : : StoreId , StorageLocation , KeyValues ) ;
2019-10-31 05:49:24 -04:00
bAlreadySaved = true ;
}
2019-10-03 16:26:48 -04:00
2020-03-06 12:23:58 -05:00
{
TMap < FString , FString > KeyValues = {
{ EditorAnalyticsDefs : : ProjectNameStoreKey , ProjectName } ,
{ EditorAnalyticsDefs : : ProjectIDStoreKey , ProjectID } ,
{ EditorAnalyticsDefs : : ProjectDescriptionStoreKey , ProjectDescription } ,
{ EditorAnalyticsDefs : : ProjectVersionStoreKey , ProjectVersion } ,
2020-11-24 18:42:39 -04:00
{ EditorAnalyticsDefs : : TimestampStoreKey , EditorAnalyticsUtils : : TimestampToString ( Timestamp ) } ,
{ EditorAnalyticsDefs : : LastTickTimestampStoreKey , EditorAnalyticsUtils : : TimestampToString ( LastTickTimestamp ) } ,
2020-08-11 01:36:57 -04:00
{ EditorAnalyticsDefs : : SessionDurationStoreKey , FString : : FromInt ( SessionDuration ) } ,
2020-03-06 12:23:58 -05:00
{ EditorAnalyticsDefs : : Idle1MinStoreKey , FString : : FromInt ( Idle1Min ) } ,
{ EditorAnalyticsDefs : : Idle5MinStoreKey , FString : : FromInt ( Idle5Min ) } ,
{ EditorAnalyticsDefs : : Idle30MinStoreKey , FString : : FromInt ( Idle30Min ) } ,
2020-04-14 16:52:27 -04:00
{ EditorAnalyticsDefs : : TotalEditorInactivitySecondsStoreKey , FString : : FromInt ( TotalEditorInactivitySeconds ) } ,
2020-03-06 12:23:58 -05:00
{ EditorAnalyticsDefs : : CurrentUserActivityStoreKey , CurrentUserActivity } ,
2020-09-24 00:43:27 -04:00
{ EditorAnalyticsDefs : : AverageFPSStoreKey , FString : : SanitizeFloat ( AverageFPS ) } ,
{ EditorAnalyticsDefs : : SessionTickCountStoreKey , FString : : FromInt ( SessionTickCount ) } ,
2020-11-24 18:42:39 -04:00
{ EditorAnalyticsDefs : : EngineTickCountStoreKey , FString : : FromInt ( EngineTickCount ) } ,
2020-09-24 00:43:27 -04:00
{ EditorAnalyticsDefs : : UserInteractionCountStoreKey , FString : : FromInt ( UserInteractionCount ) } ,
2021-02-02 16:47:04 -04:00
{ EditorAnalyticsDefs : : TotalStallCountStoreKey , FString : : FromInt ( TotalStallCount ) } ,
{ EditorAnalyticsDefs : : TotalStallReportedStoreKey , FString : : FromInt ( TotalStallReported ) } ,
{ EditorAnalyticsDefs : : TopStallNameStoreKey , TopStallName } ,
{ EditorAnalyticsDefs : : TopStallBudgetSecondsStoreKey , FString : : SanitizeFloat ( TopStallBudgetSeconds ) } ,
{ EditorAnalyticsDefs : : TopStallOverageSecondsStoreKey , FString : : SanitizeFloat ( TopStallOverageSeconds ) } ,
{ EditorAnalyticsDefs : : TopStallTriggerCountStoreKey , FString : : FromInt ( TopStallTriggerCount ) } ,
2020-09-24 00:43:27 -04:00
{ EditorAnalyticsDefs : : IsDebuggerStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsDebugger ) } ,
2020-11-24 18:42:39 -04:00
{ EditorAnalyticsDefs : : IsDebuggerIgnoredStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsDebuggerIgnored ) } ,
2020-09-24 00:43:27 -04:00
{ EditorAnalyticsDefs : : WasDebuggerStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bWasEverDebugger ) } ,
{ EditorAnalyticsDefs : : IsVanillaStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsVanilla ) } ,
{ EditorAnalyticsDefs : : WasShutdownStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bWasShutdown ) } ,
{ EditorAnalyticsDefs : : IsUserLoggingOutStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsUserLoggingOut ) } ,
{ EditorAnalyticsDefs : : IsInPIEStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsInPIE ) } ,
{ EditorAnalyticsDefs : : IsInEnterpriseStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsInEnterprise ) } ,
{ EditorAnalyticsDefs : : IsInVRModeStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsInVRMode ) } ,
{ EditorAnalyticsDefs : : IsLowDriveSpaceStoreKey , EditorAnalyticsUtils : : BoolToStoredString ( bIsLowDriveSpace ) } ,
2020-03-06 12:23:58 -05:00
} ;
2019-10-03 16:26:48 -04:00
2020-04-03 16:23:51 -04:00
if ( ExitCode . IsSet ( ) )
{
KeyValues . Emplace ( EditorAnalyticsDefs : : ExitCodeStoreKey , FString : : FromInt ( ExitCode . GetValue ( ) ) ) ;
}
2020-04-14 16:52:27 -04:00
if ( MonitorExceptCode . IsSet ( ) )
{
KeyValues . Emplace ( EditorAnalyticsDefs : : MonitorExceptCodeStoreKey , FString : : FromInt ( MonitorExceptCode . GetValue ( ) ) ) ;
}
2020-09-24 00:43:27 -04:00
if ( MonitorExitCode . IsSet ( ) )
{
KeyValues . Emplace ( EditorAnalyticsDefs : : MonitorExitCodeStoreKey , FString : : FromInt ( MonitorExitCode . GetValue ( ) ) ) ;
}
2020-11-24 18:42:39 -04:00
if ( DeathTimestamp . IsSet ( ) )
{
KeyValues . Emplace ( EditorAnalyticsDefs : : DeathTimestampStoreKey , EditorAnalyticsUtils : : TimestampToString ( DeathTimestamp . GetValue ( ) ) ) ;
}
2020-09-24 00:43:27 -04:00
2020-03-06 12:23:58 -05:00
FPlatformMisc : : SetStoredValues ( EditorAnalyticsDefs : : StoreId , StorageLocation , KeyValues ) ;
}
2019-10-03 16:26:48 -04:00
return true ;
}
bool FEditorAnalyticsSession : : Load ( const FString & InSessionID )
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return false ;
}
EditorAnalyticsUtils : : LoadInternal ( * this , InSessionID ) ;
2019-11-13 11:28:09 -05:00
bAlreadySaved = false ;
2019-10-03 16:26:48 -04:00
return true ;
}
bool FEditorAnalyticsSession : : Delete ( ) const
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return false ;
}
FString SectionName = EditorAnalyticsUtils : : GetSessionStorageLocation ( SessionId ) ;
2020-02-18 15:12:51 -05:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : AppIdStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : AppVersionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : UserIdStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : ProjectNameStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : ProjectIDStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : ProjectDescriptionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : ProjectVersionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : EngineVersionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : PlatformProcessIDStoreKey ) ;
2020-04-03 16:23:51 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : MonitorProcessIDStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : ExitCodeStoreKey ) ;
2020-04-14 16:52:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : MonitorExceptCodeStoreKey ) ;
2020-09-24 00:43:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : MonitorExitCodeStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : StartupTimestampStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TimestampStoreKey ) ;
2020-11-24 18:42:39 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : LastTickTimestampStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : DeathTimestampStoreKey ) ;
2019-11-13 11:28:09 -05:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : SessionDurationStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : Idle1MinStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : Idle5MinStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : Idle30MinStoreKey ) ;
2020-04-14 16:52:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TotalEditorInactivitySecondsStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : CurrentUserActivityStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : PluginsStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : AverageFPSStoreKey ) ;
2020-09-24 00:43:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : SessionTickCountStoreKey ) ;
2020-11-24 18:42:39 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : EngineTickCountStoreKey ) ;
2020-09-24 00:43:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : UserInteractionCountStoreKey ) ;
2020-11-24 18:42:39 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : CommandLineStoreKey ) ;
2019-10-03 16:26:48 -04:00
2021-02-02 16:47:04 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TotalStallCountStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TotalStallReportedStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TopStallNameStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TopStallBudgetSecondsStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TopStallOverageSecondsStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TopStallTriggerCountStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : DesktopGPUAdapterStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : RenderingGPUAdapterStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : GPUVendorIDStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : GPUDeviceIDStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : GRHIDeviceRevisionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : GRHIAdapterInternalDriverVersionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : GRHIAdapterUserDriverVersionStoreKey ) ;
2020-09-24 00:43:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : GRHINameStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : TotalPhysicalRAMStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : CPUPhysicalCoresStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : CPULogicalCoresStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : CPUVendorStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : CPUBrandStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : OSMajorStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : OSMinorStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : OSVersionStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : bIs64BitOSStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsCrashStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsGPUCrashStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsDebuggerStoreKey ) ;
2020-11-24 18:42:39 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsDebuggerIgnoredStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : WasDebuggerStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsVanillaStoreKey ) ;
2020-11-24 18:42:39 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsTerminatingStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : WasShutdownStoreKey ) ;
2020-09-24 00:43:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsUserLoggingOutStoreKey ) ;
2019-10-03 16:26:48 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsInPIEStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsInEnterpriseStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsInVRModeStoreKey ) ;
2020-09-24 00:43:27 -04:00
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsLowDriveSpaceStoreKey ) ;
FPlatformMisc : : DeleteStoredValue ( EditorAnalyticsDefs : : StoreId , SectionName , EditorAnalyticsDefs : : IsCrcExeMissingStoreKey ) ;
2019-10-03 16:26:48 -04:00
2020-03-20 17:10:14 -04:00
// Delete the log files.
EditorAnalyticsUtils : : DeleteLogEvents ( * this ) ;
2019-10-03 16:26:48 -04:00
return true ;
}
bool FEditorAnalyticsSession : : GetStoredSessionIDs ( TArray < FString > & OutSessions )
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return false ;
}
OutSessions = EditorAnalyticsUtils : : GetSessionList ( ) ;
return true ;
}
bool FEditorAnalyticsSession : : LoadAllStoredSessions ( TArray < FEditorAnalyticsSession > & OutSessions )
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return false ;
}
TArray < FString > SessionIDs = EditorAnalyticsUtils : : GetSessionList ( ) ;
// Retrieve all the sessions in the list from storage
for ( const FString & Id : SessionIDs )
{
FEditorAnalyticsSession NewSession ;
EditorAnalyticsUtils : : LoadInternal ( NewSession , Id ) ;
2019-10-31 05:49:24 -04:00
OutSessions . Add ( MoveTemp ( NewSession ) ) ;
2019-10-03 16:26:48 -04:00
}
return true ;
}
bool FEditorAnalyticsSession : : SaveStoredSessionIDs ( const TArray < FString > & InSessions )
{
// build up a new SessionList string
FString SessionListString ;
for ( const FString & Session : InSessions )
{
if ( ! SessionListString . IsEmpty ( ) )
{
SessionListString . Append ( TEXT ( " , " ) ) ;
}
SessionListString . Append ( Session ) ;
}
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2019-10-03 16:26:48 -04:00
{
return false ;
}
FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , EditorAnalyticsDefs : : SessionSummarySection , EditorAnalyticsDefs : : SessionListStoreKey , SessionListString ) ;
return true ;
}
2020-03-20 17:10:14 -04:00
2020-08-11 01:36:57 -04:00
void FEditorAnalyticsSession : : CleanupOutdatedIncompatibleSessions ( const FTimespan & MaxAge )
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2020-08-11 01:36:57 -04:00
{
return ;
}
// Helper function to scan and clear sessions stored in sections corresponding to format version '1_0' and '1_1'.
auto CleanupVersionedSection = [ & MaxAge ] ( const FString & SectionVersion )
{
// Try to retreive the session list corresponding the specified session format.
FString SessionListString ;
FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SectionVersion , EditorAnalyticsDefs : : SessionListStoreKey , SessionListString ) ;
if ( ! SessionListString . IsEmpty ( ) )
{
TArray < FString > SessionIDs ;
SessionListString . ParseIntoArray ( SessionIDs , TEXT ( " , " ) ) ;
for ( const FString & SessionID : SessionIDs )
{
// All versions (1_0, 1_1 and 1_2) have a 'Timestamp' field. If it is not found, the session was partially deleted and should be cleaned up.
FString SessionSectionName = SectionVersion / SessionID ;
FString TimestampStr ;
if ( FPlatformMisc : : GetStoredValue ( EditorAnalyticsDefs : : StoreId , SessionSectionName , EditorAnalyticsDefs : : TimestampStoreKey , TimestampStr ) )
{
const FTimespan SessionAge = FDateTime : : UtcNow ( ) - EditorAnalyticsUtils : : StringToTimestamp ( TimestampStr ) ;
if ( SessionAge < MaxAge )
{
// Don't delete the section yet, it contains a session young enough that could be sent if the user launch the Editor corresponding to this session format again.
return ;
}
}
}
}
// Nothing in the section is worth keeping, delete it entirely.
FPlatformMisc : : DeleteStoredSection ( EditorAnalyticsDefs : : StoreId , SectionVersion ) ;
} ;
2020-09-24 00:43:27 -04:00
// The current section format is 1_3. The older sections are considered incompatible and will be trimmed unless it contains a valid session young enough that would be picked up
2020-08-11 01:36:57 -04:00
// if an older Editor with compatible format was launched again.
CleanupVersionedSection ( EditorAnalyticsDefs : : SessionSummarySection_1_0 ) ;
CleanupVersionedSection ( EditorAnalyticsDefs : : SessionSummarySection_1_1 ) ;
2020-09-24 00:43:27 -04:00
CleanupVersionedSection ( EditorAnalyticsDefs : : SessionSummarySection_1_2 ) ;
2020-11-24 18:42:39 -04:00
CleanupVersionedSection ( EditorAnalyticsDefs : : SessionSummarySection_1_3 ) ;
2021-02-02 16:47:04 -04:00
CleanupVersionedSection ( EditorAnalyticsDefs : : SessionSummarySection_1_4 ) ;
2020-08-11 01:36:57 -04:00
}
2020-03-20 17:10:14 -04:00
void FEditorAnalyticsSession : : LogEvent ( EEventType InEventType , const FDateTime & InTimestamp )
{
EditorAnalyticsUtils : : LogSessionEvent ( * this , InEventType , InTimestamp ) ;
}
2020-04-03 16:23:51 -04:00
bool FEditorAnalyticsSession : : FindSession ( const uint32 InSessionProcessId , FEditorAnalyticsSession & OutSession )
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2020-04-03 16:23:51 -04:00
{
return false ;
}
TArray < FString > SessionIDs = EditorAnalyticsUtils : : GetSessionList ( ) ;
// Retrieve all the sessions in the list from storage
for ( const FString & Id : SessionIDs )
{
FEditorAnalyticsSession Session ;
EditorAnalyticsUtils : : LoadInternal ( Session , Id ) ;
if ( Session . PlatformProcessID = = InSessionProcessId )
{
OutSession = MoveTemp ( Session ) ;
return true ;
}
}
return false ;
}
2020-11-24 18:42:39 -04:00
bool FEditorAnalyticsSession : : SaveExitCode ( int32 InExitCode , const FDateTime & ApproximativeEditorDeathTime )
2020-04-03 16:23:51 -04:00
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2020-04-03 16:23:51 -04:00
{
2020-10-29 13:38:15 -04:00
return false ;
2020-04-03 16:23:51 -04:00
}
ExitCode . Emplace ( InExitCode ) ;
2020-11-24 18:42:39 -04:00
DeathTimestamp . Emplace ( ApproximativeEditorDeathTime ) ;
2020-04-03 16:23:51 -04:00
const FString StorageLocation = EditorAnalyticsUtils : : GetSessionStorageLocation ( SessionId ) ;
2020-11-24 18:42:39 -04:00
return FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : ExitCodeStoreKey , FString : : FromInt ( InExitCode ) )
& & FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : DeathTimestampStoreKey , EditorAnalyticsUtils : : TimestampToString ( ApproximativeEditorDeathTime ) ) ;
2020-04-03 16:23:51 -04:00
}
2020-04-14 16:52:27 -04:00
2020-10-29 13:38:15 -04:00
bool FEditorAnalyticsSession : : SaveMonitorExceptCode ( int32 InExceptCode )
2020-04-14 16:52:27 -04:00
{
2020-12-09 16:15:57 -04:00
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) )
2020-04-14 16:52:27 -04:00
{
2020-10-29 13:38:15 -04:00
return false ;
2020-04-14 16:52:27 -04:00
}
MonitorExceptCode . Emplace ( InExceptCode ) ;
const FString StorageLocation = EditorAnalyticsUtils : : GetSessionStorageLocation ( SessionId ) ;
2020-11-24 18:42:39 -04:00
return FPlatformMisc : : SetStoredValue ( EditorAnalyticsDefs : : StoreId , StorageLocation , EditorAnalyticsDefs : : MonitorExceptCodeStoreKey , FString : : FromInt ( InExceptCode ) ) ;
2020-04-14 16:52:27 -04:00
}
2021-01-18 10:45:38 -04:00
void FEditorAnalyticsSession : : CreateMinimalCrashSession ( const TOptional < int32 > & ExitCode )
{
if ( ! ensure ( IsLockedBy ( FPlatformTLS : : GetCurrentThreadId ( ) ) ) ) // Caller needs to own the session lock.
{
return ;
}
FEditorAnalyticsSession MinimalSession ;
MinimalSession . SessionId = FGuid : : NewGuid ( ) . ToString ( EGuidFormats : : DigitsWithHyphens ) ; // To have a unique session id used as key in the storage.
MinimalSession . bCrashed = true ;
MinimalSession . ExitCode = ExitCode ;
MinimalSession . StartupTimestamp = FDateTime : : UtcNow ( ) ;
MinimalSession . Timestamp = MinimalSession . StartupTimestamp ; // To enable session 'expiration'.
MinimalSession . EngineVersion = FEngineVersion : : Current ( ) . ToString ( EVersionComponent : : Changelist ) ; // To account the crash for the corresponding engine version.
MinimalSession . Save ( ) ;
// Update the session list.
TArray < FString > StoredSessions ;
GetStoredSessionIDs ( StoredSessions ) ;
StoredSessions . Add ( MinimalSession . SessionId ) ;
SaveStoredSessionIDs ( StoredSessions ) ;
}
bool FEditorAnalyticsSession : : IsMinimalCrashSession ( ) const
{
return AppId = = EditorAnalyticsDefs : : UnknownAppIdString & & ProjectID . IsEmpty ( ) & & Plugins . Num ( ) = = 0 ; // Check fields values that are not expected when the session is fully initialized.
}