Simplify Editor analytics code
This commit is contained in:
@@ -1,19 +1,20 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "EditorAnalytics.h"
|
#include "EditorAnalytics.h"
|
||||||
#include "EditorAnalyticsController.h"
|
#include "Editor/Editor.h"
|
||||||
|
#include "Editor/ProjectInfo.h"
|
||||||
|
#include "Editor/Cooker/GameCooker.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
#include "Engine/Platform/FileSystem.h"
|
#include "Engine/Platform/FileSystem.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Core/Math/Vector2.h"
|
#include "Engine/Core/Math/Vector2.h"
|
||||||
#include "Engine/Core/Types/DateTime.h"
|
#include "Engine/Core/Types/DateTime.h"
|
||||||
#include "Engine/Core/Types/TimeSpan.h"
|
#include "Engine/Core/Types/TimeSpan.h"
|
||||||
#include "Editor/Editor.h"
|
|
||||||
#include "Editor/ProjectInfo.h"
|
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Engine/Globals.h"
|
#include "Engine/Engine/Globals.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
#include "Engine/Utilities/StringConverter.h"
|
#include "Engine/Utilities/StringConverter.h"
|
||||||
|
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
#include <ThirdParty/UniversalAnalytics/universal-analytics.h>
|
#include <ThirdParty/UniversalAnalytics/universal-analytics.h>
|
||||||
|
|
||||||
@@ -34,8 +35,53 @@ namespace EditorAnalyticsImpl
|
|||||||
|
|
||||||
CriticalSection Locker;
|
CriticalSection Locker;
|
||||||
bool IsSessionActive = false;
|
bool IsSessionActive = false;
|
||||||
EditorAnalyticsController Controller;
|
}
|
||||||
Array<char> TmpBuffer;
|
|
||||||
|
void RegisterGameCookingStart(GameCooker::EventType type)
|
||||||
|
{
|
||||||
|
auto& data = *GameCooker::GetCurrentData();
|
||||||
|
auto platform = ToString(data.Platform);
|
||||||
|
if (type == GameCooker::EventType::BuildStarted)
|
||||||
|
{
|
||||||
|
EditorAnalytics::SendEvent("Actions", "GameCooker.Start", platform);
|
||||||
|
}
|
||||||
|
else if (type == GameCooker::EventType::BuildFailed)
|
||||||
|
{
|
||||||
|
EditorAnalytics::SendEvent("Actions", "GameCooker.Failed", platform);
|
||||||
|
}
|
||||||
|
else if (type == GameCooker::EventType::BuildDone)
|
||||||
|
{
|
||||||
|
EditorAnalytics::SendEvent("Actions", "GameCooker.End", platform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterLightmapsBuildingStart()
|
||||||
|
{
|
||||||
|
EditorAnalytics::SendEvent("Actions", "ShadowsOfMordor.Build", "ShadowsOfMordor.Build");
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterError(LogType type, const StringView& msg)
|
||||||
|
{
|
||||||
|
if (type == LogType::Error && false)
|
||||||
|
{
|
||||||
|
String value = msg.ToString();
|
||||||
|
const int32 MaxLength = 300;
|
||||||
|
if (msg.Length() > MaxLength)
|
||||||
|
value = value.Substring(0, MaxLength);
|
||||||
|
value.Replace('\n', ' ');
|
||||||
|
value.Replace('\r', ' ');
|
||||||
|
EditorAnalytics::SendEvent("Errors", "Log.Error", value);
|
||||||
|
}
|
||||||
|
else if (type == LogType::Fatal)
|
||||||
|
{
|
||||||
|
String value = msg.ToString();
|
||||||
|
const int32 MaxLength = 300;
|
||||||
|
if (msg.Length() > MaxLength)
|
||||||
|
value = value.Substring(0, MaxLength);
|
||||||
|
value.Replace('\n', ' ');
|
||||||
|
value.Replace('\r', ' ');
|
||||||
|
EditorAnalytics::SendEvent("Errors", "Log.Fatal", value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace EditorAnalyticsImpl;
|
using namespace EditorAnalyticsImpl;
|
||||||
@@ -43,7 +89,6 @@ using namespace EditorAnalyticsImpl;
|
|||||||
class EditorAnalyticsService : public EngineService
|
class EditorAnalyticsService : public EngineService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EditorAnalyticsService()
|
EditorAnalyticsService()
|
||||||
: EngineService(TEXT("Editor Analytics"))
|
: EngineService(TEXT("Editor Analytics"))
|
||||||
{
|
{
|
||||||
@@ -63,7 +108,6 @@ bool EditorAnalytics::IsSessionActive()
|
|||||||
void EditorAnalytics::StartSession()
|
void EditorAnalytics::StartSession()
|
||||||
{
|
{
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
if (EditorAnalyticsImpl::IsSessionActive)
|
if (EditorAnalyticsImpl::IsSessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -140,7 +184,10 @@ void EditorAnalytics::StartSession()
|
|||||||
|
|
||||||
EditorAnalyticsImpl::IsSessionActive = true;
|
EditorAnalyticsImpl::IsSessionActive = true;
|
||||||
|
|
||||||
Controller.Init();
|
// Bind events
|
||||||
|
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||||
|
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||||
|
Log::Logger::OnError.Bind<RegisterError>();
|
||||||
|
|
||||||
// Report GPU model
|
// Report GPU model
|
||||||
if (GPU.HasChars())
|
if (GPU.HasChars())
|
||||||
@@ -152,11 +199,13 @@ void EditorAnalytics::StartSession()
|
|||||||
void EditorAnalytics::EndSession()
|
void EditorAnalytics::EndSession()
|
||||||
{
|
{
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Controller.Cleanup();
|
// Unbind events
|
||||||
|
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||||
|
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||||
|
Log::Logger::OnError.Unbind<RegisterError>();
|
||||||
|
|
||||||
StringAnsi sessionLength = StringAnsi::Format("{0}", (int32)(DateTime::Now() - SessionStartTime).GetTotalSeconds());
|
StringAnsi sessionLength = StringAnsi::Format("{0}", (int32)(DateTime::Now() - SessionStartTime).GetTotalSeconds());
|
||||||
|
|
||||||
@@ -197,7 +246,6 @@ void EditorAnalytics::EndSession()
|
|||||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const char* label)
|
void EditorAnalytics::SendEvent(const char* category, const char* name, const char* label)
|
||||||
{
|
{
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -209,7 +257,6 @@ void EditorAnalytics::SendEvent(const char* category, const char* name, const ch
|
|||||||
{ UA_EVENT_LABEL, 0, (char*)label },
|
{ UA_EVENT_LABEL, 0, (char*)label },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sendTracking(Tracker, UA_EVENT, &opts);
|
sendTracking(Tracker, UA_EVENT, &opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,28 +268,10 @@ void EditorAnalytics::SendEvent(const char* category, const char* name, const St
|
|||||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const Char* label)
|
void EditorAnalytics::SendEvent(const char* category, const char* name, const Char* label)
|
||||||
{
|
{
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||||
return;
|
return;
|
||||||
|
const StringAsANSI<> labelAnsi(label);
|
||||||
ASSERT(category && name && label);
|
SendEvent(category, name, labelAnsi.Get());
|
||||||
|
|
||||||
const int32 labelLength = StringUtils::Length(label);
|
|
||||||
TmpBuffer.Clear();
|
|
||||||
TmpBuffer.Resize(labelLength + 1);
|
|
||||||
StringUtils::ConvertUTF162ANSI(label, TmpBuffer.Get(), labelLength);
|
|
||||||
TmpBuffer[labelLength] = 0;
|
|
||||||
|
|
||||||
UAOptions opts =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
{ UA_EVENT_CATEGORY, 0, (char*)category },
|
|
||||||
{ UA_EVENT_ACTION, 0, (char*)name },
|
|
||||||
{ UA_EVENT_LABEL, 0, (char*)TmpBuffer.Get() },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sendTracking(Tracker, UA_EVENT, &opts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorAnalyticsService::Init()
|
bool EditorAnalyticsService::Init()
|
||||||
@@ -265,7 +294,6 @@ bool EditorAnalyticsService::Init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG(Info, "Editor analytics service is enabled. Curl version: {0}", TEXT(LIBCURL_VERSION));
|
LOG(Info, "Editor analytics service is enabled. Curl version: {0}", TEXT(LIBCURL_VERSION));
|
||||||
|
|
||||||
EditorAnalytics::StartSession();
|
EditorAnalytics::StartSession();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -10,11 +10,9 @@
|
|||||||
class EditorAnalytics
|
class EditorAnalytics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether analytics session is active.
|
/// Determines whether analytics session is active.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns><c>true</c> if there is active analytics session running; otherwise, <c>false</c>.</returns>
|
|
||||||
static bool IsSessionActive();
|
static bool IsSessionActive();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
|
||||||
|
|
||||||
#include "EditorAnalyticsController.h"
|
|
||||||
#include "Editor/Cooker/GameCooker.h"
|
|
||||||
#include "EditorAnalytics.h"
|
|
||||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
|
||||||
|
|
||||||
void RegisterGameCookingStart(GameCooker::EventType type)
|
|
||||||
{
|
|
||||||
auto& data = *GameCooker::GetCurrentData();
|
|
||||||
auto platform = ToString(data.Platform);
|
|
||||||
if (type == GameCooker::EventType::BuildStarted)
|
|
||||||
{
|
|
||||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Start", platform);
|
|
||||||
}
|
|
||||||
else if (type == GameCooker::EventType::BuildFailed)
|
|
||||||
{
|
|
||||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Failed", platform);
|
|
||||||
}
|
|
||||||
else if (type == GameCooker::EventType::BuildDone)
|
|
||||||
{
|
|
||||||
EditorAnalytics::SendEvent("Actions", "GameCooker.End", platform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterLightmapsBuildingStart()
|
|
||||||
{
|
|
||||||
EditorAnalytics::SendEvent("Actions", "ShadowsOfMordor.Build", "ShadowsOfMordor.Build");
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterError(LogType type, const StringView& msg)
|
|
||||||
{
|
|
||||||
if (type == LogType::Error && false)
|
|
||||||
{
|
|
||||||
String value = msg.ToString();
|
|
||||||
const int32 MaxLength = 300;
|
|
||||||
if (msg.Length() > MaxLength)
|
|
||||||
value = value.Substring(0, MaxLength);
|
|
||||||
value.Replace('\n', ' ');
|
|
||||||
value.Replace('\r', ' ');
|
|
||||||
|
|
||||||
EditorAnalytics::SendEvent("Errors", "Log.Error", value);
|
|
||||||
}
|
|
||||||
else if (type == LogType::Fatal)
|
|
||||||
{
|
|
||||||
String value = msg.ToString();
|
|
||||||
const int32 MaxLength = 300;
|
|
||||||
if (msg.Length() > MaxLength)
|
|
||||||
value = value.Substring(0, MaxLength);
|
|
||||||
value.Replace('\n', ' ');
|
|
||||||
value.Replace('\r', ' ');
|
|
||||||
|
|
||||||
EditorAnalytics::SendEvent("Errors", "Log.Fatal", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorAnalyticsController::Init()
|
|
||||||
{
|
|
||||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
|
||||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
|
||||||
Log::Logger::OnError.Bind<RegisterError>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorAnalyticsController::Cleanup()
|
|
||||||
{
|
|
||||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
|
||||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
|
||||||
Log::Logger::OnError.Unbind<RegisterError>();
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The controller object for the tracking events for the editor analytics.
|
|
||||||
/// </summary>
|
|
||||||
class EditorAnalyticsController
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Starts the service (registers to event handlers).
|
|
||||||
/// </summary>
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ends the service (unregisters to event handlers).
|
|
||||||
/// </summary>
|
|
||||||
void Cleanup();
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user