You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
172 lines
6.3 KiB
C++
172 lines
6.3 KiB
C++
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "HttpServiceTracker.h"
|
|
#include "HAL/PlatformTime.h"
|
|
#include "AnalyticsEventAttribute.h"
|
|
#include "IAnalyticsProviderET.h"
|
|
#include "AnalyticsET.h"
|
|
#include "Interfaces/IHttpResponse.h"
|
|
#include "Analytics.h"
|
|
|
|
bool FHttpServiceTracker::Tick(float DeltaTime)
|
|
{
|
|
// flush events at the specified interval.
|
|
if (FPlatformTime::Seconds() > NextFlushTime)
|
|
{
|
|
if (AnalyticsProvider.IsValid())
|
|
{
|
|
TArray<FAnalyticsEventAttribute> Attrs;
|
|
Attrs.Reserve(10);
|
|
// one event per endpoint.
|
|
for (const auto& MetricsMapPair : EndpointMetricsMap)
|
|
{
|
|
Attrs.Reset();
|
|
Attrs.Emplace(TEXT("DomainName"), MetricsMapPair.Value.LastAnalyticsName);
|
|
Attrs.Emplace(TEXT("FailCount"), MetricsMapPair.Value.FailCount);
|
|
Attrs.Emplace(TEXT("SuccessCount"), MetricsMapPair.Value.SuccessCount);
|
|
// We may have had no successful requests, so these values would be undefined.
|
|
if (MetricsMapPair.Value.SuccessCount > 0)
|
|
{
|
|
Attrs.Emplace(TEXT("DownloadBytesSuccessTotal"), MetricsMapPair.Value.DownloadBytesSuccessTotal);
|
|
Attrs.Emplace(TEXT("ElapsedTimeSuccessTotal"), MetricsMapPair.Value.ElapsedTimeSuccessTotal);
|
|
Attrs.Emplace(TEXT("ElapsedTimeSuccessMin"), MetricsMapPair.Value.ElapsedTimeSuccessMin);
|
|
Attrs.Emplace(TEXT("ElapsedTimeSuccessMax"), MetricsMapPair.Value.ElapsedTimeSuccessMax);
|
|
}
|
|
if (MetricsMapPair.Value.FailCount > 0)
|
|
{
|
|
Attrs.Emplace(TEXT("DownloadBytesFailTotal"), MetricsMapPair.Value.DownloadBytesFailTotal);
|
|
Attrs.Emplace(TEXT("ElapsedTimeFailTotal"), MetricsMapPair.Value.ElapsedTimeFailTotal);
|
|
Attrs.Emplace(TEXT("ElapsedTimeFailMin"), MetricsMapPair.Value.ElapsedTimeFailMin);
|
|
Attrs.Emplace(TEXT("ElapsedTimeFailMax"), MetricsMapPair.Value.ElapsedTimeFailMax);
|
|
}
|
|
// one attribute per response code.
|
|
for (const auto& ResponseCodeMapPair : MetricsMapPair.Value.ResponseCodes)
|
|
{
|
|
Attrs.Emplace(FString(TEXT("Code-")) + LexToString(ResponseCodeMapPair.Key), ResponseCodeMapPair.Value);
|
|
}
|
|
AnalyticsProvider->RecordEvent(MetricsMapPair.Key.ToString(), MoveTemp(Attrs));
|
|
}
|
|
// force an immediate flush always. We already summarized.
|
|
AnalyticsProvider->FlushEvents();
|
|
}
|
|
EndpointMetricsMap.Reset();
|
|
NextFlushTime += FlushIntervalSec;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FHttpServiceTracker::TrackRequest(const FHttpRequestPtr& Request, FName EndpointName)
|
|
{
|
|
auto& Metrics = EndpointMetricsMap.FindOrAdd(EndpointName);
|
|
Metrics.TrackRequest(Request);
|
|
}
|
|
|
|
FHttpServiceTracker::FHttpServiceTracker(const FHttpServiceTrackerConfig& Config)
|
|
: FlushIntervalSec((float)Config.AggregationInterval.GetTotalSeconds())
|
|
, NextFlushTime(FPlatformTime::Seconds() + FlushIntervalSec)
|
|
{
|
|
AnalyticsProvider = FAnalyticsET::Get().CreateAnalyticsProvider(FAnalyticsET::Config(Config.APIKey, Config.APIServer, Config.ApiVersion, false, TEXT("unknown"), TEXT("qosmetrics")));
|
|
// Use the standard UserID
|
|
AnalyticsProvider->SetUserID(FString::Printf(TEXT("%s|%s|%s"), *FPlatformMisc::GetLoginId(), *FPlatformMisc::GetEpicAccountId(), *FPlatformMisc::GetOperatingSystemId()));
|
|
// Note we also don't start/stop the session. The AnalyticsET provider allows this, and this enables our collector
|
|
// to receive ONLY monitoring events.
|
|
}
|
|
|
|
bool FHttpServiceTracker::EndpointMetrics::IsSuccessfulResponse(int32 ResponseCode)
|
|
{
|
|
return ResponseCode >= 200 && ResponseCode < 400;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
/**
|
|
* @brief Returns name of the endpoint for analytics.
|
|
*
|
|
* @param FullURL actual URL used
|
|
* @return Name for analytics (currently this is a domain name).
|
|
*/
|
|
FString GetAnalyticsName(const FString & FullURL)
|
|
{
|
|
// use the first part of address
|
|
int DomainNameBegin = FullURL.Find(TEXT("://"), ESearchCase::CaseSensitive);
|
|
|
|
if (DomainNameBegin == INDEX_NONE)
|
|
{
|
|
UE_LOG(LogAnalytics, Warning, TEXT("Could not find protocol in URL '%s', analytics name will likely be incorrect"), *FullURL);
|
|
return FullURL;
|
|
}
|
|
|
|
DomainNameBegin += 3; // length of "://"
|
|
|
|
int DomainNameEnd = FullURL.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromStart, DomainNameBegin);
|
|
|
|
if (DomainNameEnd == INDEX_NONE || DomainNameEnd <= DomainNameBegin)
|
|
{
|
|
UE_LOG(LogAnalytics, Warning, TEXT("Could not determine domain name in URL '%s', analytics name will likely be incorrect"), *FullURL);
|
|
return FullURL;
|
|
}
|
|
|
|
return FullURL.Mid(DomainNameBegin, DomainNameEnd - DomainNameBegin);
|
|
}
|
|
}
|
|
|
|
|
|
void FHttpServiceTracker::EndpointMetrics::TrackRequest(const FHttpRequestPtr& HttpRequest)
|
|
{
|
|
if(HttpRequest.IsValid())
|
|
{
|
|
// keep a histogram of response codes
|
|
const FHttpResponsePtr HttpResponse = HttpRequest->GetResponse();
|
|
|
|
const int32 ResponseCode = HttpResponse.IsValid() ? HttpResponse->GetResponseCode() : 0;
|
|
// track all responses in a histogram
|
|
ResponseCodes.FindOrAdd(ResponseCode)++;
|
|
const float ElapsedTime = HttpRequest->GetElapsedTime();
|
|
const int64 DownloadBytes = HttpResponse.IsValid() ? HttpResponse->GetContent().Num() : 0;
|
|
// track successes/fails separately
|
|
if (IsSuccessfulResponse(ResponseCode))
|
|
{
|
|
++SuccessCount;
|
|
// sum elapsed time for average calc
|
|
ElapsedTimeSuccessTotal += ElapsedTime;
|
|
ElapsedTimeSuccessMax = FMath::Max(ElapsedTimeSuccessMax, ElapsedTime);
|
|
ElapsedTimeSuccessMin = FMath::Min(ElapsedTimeSuccessMin, ElapsedTime);
|
|
// sum download rate for average calc
|
|
DownloadBytesSuccessTotal += DownloadBytes;
|
|
}
|
|
else
|
|
{
|
|
++FailCount;
|
|
// sum elapsed time for average calc
|
|
ElapsedTimeFailTotal += ElapsedTime;
|
|
ElapsedTimeFailMax = FMath::Max(ElapsedTimeFailMax, ElapsedTime);
|
|
ElapsedTimeFailMin = FMath::Min(ElapsedTimeFailMin, ElapsedTime);
|
|
// sum download rate for average calc
|
|
DownloadBytesFailTotal += DownloadBytes;
|
|
}
|
|
|
|
FString AnalyticsName = GetAnalyticsName(HttpRequest->GetURL());
|
|
if (LastAnalyticsName.Len() > 0 && AnalyticsName != LastAnalyticsName)
|
|
{
|
|
UE_LOG(LogAnalytics, Warning, TEXT("Endpoint analytics name has changed from '%s' to '%s', aggregated stats will be incorrect"),
|
|
*LastAnalyticsName, *AnalyticsName);
|
|
}
|
|
|
|
LastAnalyticsName = AnalyticsName;
|
|
}
|
|
}
|
|
|
|
FHttpServiceTracker::EndpointMetrics::EndpointMetrics() : DownloadBytesSuccessTotal(0L)
|
|
, ElapsedTimeSuccessTotal(0.0f)
|
|
, ElapsedTimeSuccessMin(FLT_MAX)
|
|
, ElapsedTimeSuccessMax(-FLT_MAX)
|
|
, DownloadBytesFailTotal(0L)
|
|
, ElapsedTimeFailTotal(0.0f)
|
|
, ElapsedTimeFailMin(FLT_MAX)
|
|
, ElapsedTimeFailMax(-FLT_MAX)
|
|
, SuccessCount(0)
|
|
, FailCount(0)
|
|
{
|
|
|
|
}
|