initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
@ -0,0 +1,120 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.Services.Core.Configuration.Internal;
|
||||
using Unity.Services.Core.Environments.Internal;
|
||||
using Unity.Services.Core.Scheduler.Internal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Services.Core.Telemetry.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles common logic between all <see cref="Diagnostics"/> instances.
|
||||
/// </summary>
|
||||
class DiagnosticsHandler : TelemetryHandler<DiagnosticsPayload, Diagnostic>
|
||||
{
|
||||
class SendState
|
||||
{
|
||||
public DiagnosticsHandler Self;
|
||||
|
||||
public CachedPayload<DiagnosticsPayload> Payload;
|
||||
}
|
||||
|
||||
public DiagnosticsHandler(
|
||||
TelemetryConfig config, CachedPayload<DiagnosticsPayload> cache, IActionScheduler scheduler,
|
||||
ICachePersister<DiagnosticsPayload> cachePersister, TelemetrySender sender)
|
||||
: base(config, cache, scheduler, cachePersister, sender) {}
|
||||
|
||||
internal override void SendPersistedCache(CachedPayload<DiagnosticsPayload> persistedCache)
|
||||
{
|
||||
var sendAsync = m_Sender.SendAsync(persistedCache.Payload);
|
||||
|
||||
m_CachePersister.Delete();
|
||||
|
||||
var localState = new SendState
|
||||
{
|
||||
Self = this,
|
||||
Payload = new CachedPayload<DiagnosticsPayload>
|
||||
{
|
||||
TimeOfOccurenceTicks = persistedCache.TimeOfOccurenceTicks,
|
||||
Payload = persistedCache.Payload,
|
||||
},
|
||||
};
|
||||
sendAsync.ContinueWith(OnSendAsyncCompleted, localState, TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
|
||||
static void OnSendAsyncCompleted(Task sendOperation, object state)
|
||||
{
|
||||
if (!(state is SendState castState))
|
||||
{
|
||||
throw new ArgumentException("The given state is invalid.");
|
||||
}
|
||||
|
||||
switch (sendOperation.Status)
|
||||
{
|
||||
case TaskStatus.Canceled:
|
||||
case TaskStatus.Faulted:
|
||||
{
|
||||
castState.Self.Cache.AddRangeFrom(castState.Payload);
|
||||
break;
|
||||
}
|
||||
case TaskStatus.RanToCompletion:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(sendOperation.Status), "Can't continue without the send operation being completed.");
|
||||
}
|
||||
}
|
||||
|
||||
internal override void FetchSpecificCommonTags(ICloudProjectId cloudProjectId, IEnvironments environments)
|
||||
{
|
||||
var commonTags = Cache.Payload.DiagnosticsCommonTags;
|
||||
commonTags.Clear();
|
||||
|
||||
commonTags[TagKeys.ApplicationVersion] = Application.version;
|
||||
commonTags[TagKeys.ProductName] = Application.productName;
|
||||
commonTags[TagKeys.CloudProjectId] = cloudProjectId.GetCloudProjectId();
|
||||
commonTags[TagKeys.EnvironmentName] = environments.Current;
|
||||
commonTags[TagKeys.ApplicationGenuine] = Application.genuineCheckAvailable
|
||||
? Application.genuine.ToString(CultureInfo.InvariantCulture)
|
||||
: "unavailable";
|
||||
commonTags[TagKeys.InternetReachability] = Application.internetReachability.ToString();
|
||||
}
|
||||
|
||||
internal override void SendCachedPayload()
|
||||
{
|
||||
if (Cache.IsEmpty())
|
||||
return;
|
||||
|
||||
var sendAsync = m_Sender.SendAsync(Cache.Payload);
|
||||
|
||||
var localState = new SendState
|
||||
{
|
||||
Self = this,
|
||||
Payload = new CachedPayload<DiagnosticsPayload>
|
||||
{
|
||||
TimeOfOccurenceTicks = Cache.TimeOfOccurenceTicks,
|
||||
Payload = new DiagnosticsPayload
|
||||
{
|
||||
Diagnostics = new List<Diagnostic>(Cache.Payload.Diagnostics),
|
||||
CommonTags = new Dictionary<string, string>(Cache.Payload.CommonTags),
|
||||
DiagnosticsCommonTags = new Dictionary<string, string>(Cache.Payload.DiagnosticsCommonTags),
|
||||
},
|
||||
},
|
||||
};
|
||||
Cache.TimeOfOccurenceTicks = 0;
|
||||
Cache.Payload.Diagnostics.Clear();
|
||||
|
||||
if (m_CachePersister.CanPersist)
|
||||
{
|
||||
m_CachePersister.Delete();
|
||||
}
|
||||
|
||||
sendAsync.ContinueWith(OnSendAsyncCompleted, localState, TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 34f5fe0d07586744aa92a02821c71e8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using Unity.Services.Core.Configuration.Internal;
|
||||
using Unity.Services.Core.Environments.Internal;
|
||||
using Unity.Services.Core.Scheduler.Internal;
|
||||
|
||||
namespace Unity.Services.Core.Telemetry.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles common logic between all <see cref="Metrics"/> instances.
|
||||
/// </summary>
|
||||
class MetricsHandler : TelemetryHandler<MetricsPayload, Metric>
|
||||
{
|
||||
public MetricsHandler(
|
||||
TelemetryConfig config, CachedPayload<MetricsPayload> cache, IActionScheduler scheduler,
|
||||
ICachePersister<MetricsPayload> cachePersister, TelemetrySender sender)
|
||||
: base(config, cache, scheduler, cachePersister, sender)
|
||||
{
|
||||
// prevent .ctor of StringEnumConverter from being stripped
|
||||
AotHelper.EnsureType<StringEnumConverter>();
|
||||
}
|
||||
|
||||
internal override void SendPersistedCache(CachedPayload<MetricsPayload> persistedCache)
|
||||
{
|
||||
if (!AreMetricsOutdated())
|
||||
{
|
||||
m_Sender.SendAsync(persistedCache.Payload);
|
||||
}
|
||||
|
||||
m_CachePersister.Delete();
|
||||
|
||||
bool AreMetricsOutdated()
|
||||
{
|
||||
var differenceFromUtcNow = DateTime.UtcNow - new DateTime(persistedCache.TimeOfOccurenceTicks);
|
||||
return differenceFromUtcNow.TotalSeconds > Config.PayloadExpirationSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void FetchSpecificCommonTags(ICloudProjectId cloudProjectId, IEnvironments environments)
|
||||
{
|
||||
Cache.Payload.MetricsCommonTags.Clear();
|
||||
}
|
||||
|
||||
internal override void SendCachedPayload()
|
||||
{
|
||||
if (Cache.Payload.Metrics.Count <= 0)
|
||||
return;
|
||||
|
||||
m_Sender.SendAsync(Cache.Payload);
|
||||
|
||||
Cache.Payload.Metrics.Clear();
|
||||
Cache.TimeOfOccurenceTicks = 0;
|
||||
|
||||
if (m_CachePersister.CanPersist)
|
||||
{
|
||||
m_CachePersister.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 19ff1201e729ddc4d8128534ec9c435c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,168 @@
|
|||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
using System;
|
||||
#endif
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Services.Core.Configuration.Internal;
|
||||
using Unity.Services.Core.Environments.Internal;
|
||||
using Unity.Services.Core.Internal;
|
||||
using Unity.Services.Core.Scheduler.Internal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Services.Core.Telemetry.Internal
|
||||
{
|
||||
/// <remarks>
|
||||
/// A non-generic version of the class to hold non-generic static code in order to
|
||||
/// avoid unnecessary duplication that happens with static members in generic classes.
|
||||
/// </remarks>
|
||||
abstract class TelemetryHandler
|
||||
{
|
||||
internal static string FormatOperatingSystemInfo(string rawOsInfo)
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
//Android's os data is formatted as follow:
|
||||
//"<Device system name> <Device system version> / API-<API level> (<ID>/<Version incremental>)"
|
||||
//eg. "Android OS 10 / API-29 (HONORHRY-LX1T/10.0.0.200C636)"
|
||||
var trimmedOsInfoSize = rawOsInfo.LastIndexOf(" (", StringComparison.Ordinal);
|
||||
if (trimmedOsInfoSize < 0)
|
||||
return rawOsInfo;
|
||||
|
||||
var osTag = rawOsInfo.Substring(0, trimmedOsInfoSize);
|
||||
return osTag;
|
||||
#else
|
||||
return rawOsInfo;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TelemetryHandler<TPayload, TEvent> : TelemetryHandler
|
||||
where TPayload : ITelemetryPayload
|
||||
where TEvent : ITelemetryEvent
|
||||
{
|
||||
readonly IActionScheduler m_Scheduler;
|
||||
|
||||
protected readonly ICachePersister<TPayload> m_CachePersister;
|
||||
|
||||
protected readonly TelemetrySender m_Sender;
|
||||
|
||||
internal long SendingLoopScheduleId;
|
||||
|
||||
internal long PersistenceLoopScheduleId;
|
||||
|
||||
public TelemetryConfig Config { get; }
|
||||
|
||||
public CachedPayload<TPayload> Cache { get; }
|
||||
|
||||
protected TelemetryHandler(
|
||||
TelemetryConfig config, CachedPayload<TPayload> cache, IActionScheduler scheduler,
|
||||
ICachePersister<TPayload> cachePersister, TelemetrySender sender)
|
||||
{
|
||||
Config = config;
|
||||
Cache = cache;
|
||||
m_Scheduler = scheduler;
|
||||
m_CachePersister = cachePersister;
|
||||
m_Sender = sender;
|
||||
}
|
||||
|
||||
public void Initialize(ICloudProjectId cloudProjectId, IEnvironments environments)
|
||||
{
|
||||
HandlePersistedCache();
|
||||
FetchAllCommonTags(cloudProjectId, environments);
|
||||
ScheduleSendingLoop();
|
||||
|
||||
if (m_CachePersister.CanPersist)
|
||||
{
|
||||
SchedulePersistenceLoop();
|
||||
}
|
||||
}
|
||||
|
||||
internal void HandlePersistedCache()
|
||||
{
|
||||
if (!m_CachePersister.CanPersist
|
||||
|| !m_CachePersister.TryFetch(out var persistedCache))
|
||||
return;
|
||||
|
||||
if (persistedCache.IsEmpty())
|
||||
{
|
||||
m_CachePersister.Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
SendPersistedCache(persistedCache);
|
||||
}
|
||||
|
||||
internal abstract void SendPersistedCache(CachedPayload<TPayload> persistedCache);
|
||||
|
||||
void FetchAllCommonTags(ICloudProjectId cloudProjectId, IEnvironments environments)
|
||||
{
|
||||
FetchTelemetryCommonTags();
|
||||
FetchSpecificCommonTags(cloudProjectId, environments);
|
||||
}
|
||||
|
||||
internal abstract void FetchSpecificCommonTags(ICloudProjectId cloudProjectId, IEnvironments environments);
|
||||
|
||||
internal void FetchTelemetryCommonTags()
|
||||
{
|
||||
var commonTags = Cache.Payload.CommonTags;
|
||||
commonTags.Clear();
|
||||
commonTags[TagKeys.ApplicationInstallMode] = Application.installMode.ToString();
|
||||
commonTags[TagKeys.OperatingSystem] = FormatOperatingSystemInfo(SystemInfo.operatingSystem);
|
||||
commonTags[TagKeys.Platform] = Application.platform.ToString();
|
||||
commonTags[TagKeys.Engine] = "Unity";
|
||||
commonTags[TagKeys.UnityVersion] = Application.unityVersion;
|
||||
}
|
||||
|
||||
internal void ScheduleSendingLoop()
|
||||
{
|
||||
SendingLoopScheduleId = m_Scheduler.ScheduleAction(SendingLoop, Config.PayloadSendingMaxIntervalSeconds);
|
||||
|
||||
void SendingLoop()
|
||||
{
|
||||
ScheduleSendingLoop();
|
||||
SendCachedPayload();
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract void SendCachedPayload();
|
||||
|
||||
internal void SchedulePersistenceLoop()
|
||||
{
|
||||
PersistenceLoopScheduleId = m_Scheduler.ScheduleAction(
|
||||
PersistenceLoop, Config.SafetyPersistenceIntervalSeconds);
|
||||
|
||||
void PersistenceLoop()
|
||||
{
|
||||
SchedulePersistenceLoop();
|
||||
PersistCache();
|
||||
}
|
||||
}
|
||||
|
||||
internal void PersistCache()
|
||||
{
|
||||
if (!m_CachePersister.CanPersist
|
||||
|| Cache.TimeOfOccurenceTicks <= 0
|
||||
|| Cache.Payload.Count <= 0)
|
||||
return;
|
||||
|
||||
m_CachePersister.Persist(Cache);
|
||||
}
|
||||
|
||||
public void Register(TEvent telemetryEvent)
|
||||
{
|
||||
CoreLogger.LogTelemetry(
|
||||
$"Cached the {typeof(TEvent).Name} event: {JsonConvert.SerializeObject(telemetryEvent)}");
|
||||
Cache.Add(telemetryEvent);
|
||||
|
||||
if (!IsCacheFull())
|
||||
return;
|
||||
|
||||
SendCachedPayload();
|
||||
m_Scheduler.CancelAction(SendingLoopScheduleId);
|
||||
ScheduleSendingLoop();
|
||||
|
||||
bool IsCacheFull()
|
||||
{
|
||||
return Cache.Payload.Count >= Config.MaxMetricCountPerPayload;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cafed3ef1baf3db47aac0e065c7edee4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue