Skip to content

Commit

Permalink
アプリケーションの利用状況可視化をできるようにする (#8)
Browse files Browse the repository at this point in the history
Co-authored-by: sus-taguchi-t <[email protected]>
  • Loading branch information
kiyohome and sus-taguchi-t authored Jun 13, 2023
1 parent e8b9ae3 commit b136d89
Show file tree
Hide file tree
Showing 40 changed files with 2,427 additions and 28 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ dotnet_naming_rule.parameters_rule.style = camel_case_style
dotnet_naming_rule.parameters_rule.severity = warning

# Disable
# Variable declarations can be broken down
dotnet_diagnostic.IDE0042.severity = none
# Make field readonly
dotnet_diagnostic.IDE0044.severity = none
# Move using directory into the namespace
Expand All @@ -424,6 +426,8 @@ dotnet_diagnostic.IDE0044.severity = none
dotnet_diagnostic.IDE0039.severity = none
# Simplify 'new' expression
dotnet_diagnostic.IDE0090.severity = none
# Possible JSON string detected
dotnet_diagnostic.JSON002.severity = none
# 'Xxxxx' should call GC.SuppressFinalize inside the Dispose method.
dotnet_diagnostic.CC0029.severity = none
# Ordering member inside this type.
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ crashlytics-build.properties
# Application config scriptable object
ChatConfig.asset*
MultiplayConfig.asset*
AppUsageConfig.asset*

# Addressables connection server config
SecretVariables.cs*
Expand All @@ -83,3 +84,6 @@ Assets/Mixamo/*/mat/*
Assets/Mixamo/*/tex/*
AvatarAmy.prefab*
AvatarMichelle.prefab*

# Docker data
Servers/VisualizationOfAppUsage/.data
6 changes: 3 additions & 3 deletions Assets/AddressableAssetsData/AddressableAssetSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ MonoBehaviour:
- {fileID: 11400000, guid: 6297d17b6b94106439bceeb97db9cf1a, type: 2}
- {fileID: 11400000, guid: 08331fb23997c7a4d8ae67fc5b6cf12a, type: 2}
- {fileID: 11400000, guid: ede7bec8b8ddaf549bb6847dbaeada3d, type: 2}
m_ActiveProfileId: 7d9061380a310da4e8fd41818589eeea
m_ActiveProfileId: 4f014b7c1b6ae4f4cb27b832046bb0bb
m_HostingServicesManager:
m_HostingServiceInfos:
- classRef: UnityEditor.AddressableAssets.HostingServices.HttpHostingService,
Expand All @@ -145,11 +145,11 @@ MonoBehaviour:
m_Key: HostingServiceUploadSpeed
- m_AssemblyName: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
m_ClassName: System.String
m_Data: ServerData/0.1.0/Android
m_Data: ServerData/0.1.0/StandaloneWindows64
m_Key: ContentRoot
- m_AssemblyName: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
m_ClassName: System.Boolean
m_Data: True
m_Data: False
m_Key: IsEnabled
- m_AssemblyName: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
m_ClassName: System.String
Expand Down
1 change: 1 addition & 0 deletions Assets/Holiday/App/App.unity
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ MonoBehaviour:
appConfig: {fileID: 11400000, guid: 1db807f7f1224324eab1d80f4b9cba67, type: 2}
loggingConfig: {fileID: 11400000, guid: 4ea8b9c6d5a9395468e5ddfeb77fc270, type: 2}
stageConfig: {fileID: 11400000, guid: d1b93e8ee48890443a2040ea71dba396, type: 2}
appUsageConfig: {fileID: 0}
--- !u!4 &1287753623
Transform:
m_ObjectHideFlags: 0
Expand Down
12 changes: 11 additions & 1 deletion Assets/Holiday/App/AppPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Cysharp.Threading.Tasks;
using Extreal.Core.Common.System;
using Extreal.Core.StageNavigation;
using Extreal.SampleApp.Holiday.App.AppUsage;
using Extreal.SampleApp.Holiday.App.AssetWorkflow;
using Extreal.SampleApp.Holiday.App.Config;
using UniRx;
Expand All @@ -16,6 +17,7 @@ public class AppPresenter : DisposableBase, IInitializable, IAsyncStartable
private readonly StageNavigator<StageName, SceneName> stageNavigator;
private readonly AssetHelper assetHelper;
private readonly AppState appState;
private readonly AppUsageManager appUsageManager;

[SuppressMessage("Usage", "CC0033")]
private readonly CompositeDisposable disposables = new CompositeDisposable();
Expand All @@ -24,12 +26,14 @@ public AppPresenter(
AppConfig appConfig,
StageNavigator<StageName, SceneName> stageNavigator,
AppState appState,
AssetHelper assetHelper)
AssetHelper assetHelper,
AppUsageManager appUsageManager)
{
this.appConfig = appConfig;
this.stageNavigator = stageNavigator;
this.assetHelper = assetHelper;
this.appState = appState;
this.appUsageManager = appUsageManager;
}

public void Initialize()
Expand All @@ -48,6 +52,12 @@ public void Initialize()
appConfig.DownloadRetrySuccessMessage,
appConfig.DownloadRetryFailureMessage))
.AddTo(disposables);

stageNavigator.OnStageTransitioned
.Subscribe(appState.SetStage)
.AddTo(disposables);

appUsageManager.CollectAppUsage();
}

public async UniTask StartAsync(CancellationToken cancellation)
Expand Down
34 changes: 28 additions & 6 deletions Assets/Holiday/App/AppScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using Extreal.Core.Logging;
using Extreal.Core.StageNavigation;
using Extreal.SampleApp.Holiday.App.AppUsage;
using Extreal.SampleApp.Holiday.App.AssetWorkflow;
using Extreal.SampleApp.Holiday.App.Config;
using Extreal.SampleApp.Holiday.Common.Config;
Expand All @@ -22,6 +23,7 @@ public class AppScope : LifetimeScope
[SerializeField] private AppConfig appConfig;
[SerializeField] private LoggingConfig loggingConfig;
[SerializeField] private StageConfig stageConfig;
[SerializeField] private AppUsageConfig appUsageConfig;

private void InitializeApp()
{
Expand All @@ -30,7 +32,7 @@ private void InitializeApp()
var timeout = appConfig.DownloadTimeoutSeconds;
Addressables.ResourceManager.WebRequestOverride = unityWebRequest => unityWebRequest.timeout = timeout;

ClearAssetBundleCacheOnDev();
ClearCacheOnDev();

var logLevel = InitializeLogging();
InitializeMicrophone();
Expand All @@ -47,16 +49,31 @@ private LogLevel InitializeLogging()
{
#if HOLIDAY_PROD
const LogLevel logLevel = LogLevel.Info;
LoggingManager.Initialize(logLevel: logLevel);
LoggingManager.Initialize(logLevel: logLevel, writer: new AppUsageLogWriter(appUsageConfig, appStateProvider));
#else
const LogLevel logLevel = LogLevel.Debug;
var checker = new LogLevelLogOutputChecker(loggingConfig.CategoryFilters);
var writer = new UnityDebugLogWriter(loggingConfig.LogFormats);
var defaultWriter = new UnityDebugLogWriter(loggingConfig.LogFormats);
var writer = new AppUsageLogWriter(appUsageConfig, appStateProvider, defaultWriter);
LoggingManager.Initialize(logLevel, checker, writer);
#endif
return logLevel;
}

private readonly AppStateProvider appStateProvider = new AppStateProvider();

// The provider is added to pass AppState to LogWriter. AppState gets the logger to output logs.
// Therefore, if AppState is created before log output is initialized,
// only AppState acquires the logger before initialization, resulting in inconsistency.
// In order to resolve this issue, the provider is introduced and AppState is passed to LogWriter
// while delaying the timing of AppState creation.
public class AppStateProvider
{
public AppState AppState { get; private set; }
internal AppStateProvider() { }
internal void Init() => AppState = new AppState();
}

private static void InitializeMicrophone()
{
#if UNITY_IOS
Expand All @@ -74,11 +91,12 @@ private static void InitializeMicrophone()
#endif
}

[SuppressMessage("Design", "IDE0022")]
private static void ClearAssetBundleCacheOnDev()
[SuppressMessage("Design", "IDE0022"), SuppressMessage("Design", "CC0091")]
private void ClearCacheOnDev()
{
#if !HOLIDAY_PROD
Caching.ClearCache();
PlayerPrefs.DeleteKey(appUsageConfig.ClientIdKey);
#endif
}

Expand All @@ -95,10 +113,14 @@ protected override void Configure(IContainerBuilder builder)
builder.RegisterComponent(stageConfig).AsImplementedInterfaces();
builder.Register<StageNavigator<StageName, SceneName>>(Lifetime.Singleton);

builder.Register<AppState>(Lifetime.Singleton);
appStateProvider.Init();
builder.RegisterComponent(appStateProvider.AppState);

builder.Register<AssetHelper>(Lifetime.Singleton);

builder.RegisterComponent(appUsageConfig);
builder.Register<AppUsageManager>(Lifetime.Singleton);

builder.RegisterEntryPoint<AppPresenter>();
}
}
Expand Down
8 changes: 4 additions & 4 deletions Assets/Holiday/App/AppState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class AppState : DisposableBase

private readonly CompositeDisposable disposables = new CompositeDisposable();

public StageState StageState { get; private set; }

public AppState()
{
multiplayReady.AddTo(disposables);
Expand Down Expand Up @@ -101,13 +103,11 @@ private void LogWaitingStatus()
public void SetTextChatReady(bool ready) => textChatReady.Value = ready;
public void SetVoiceChatReady(bool ready) => voiceChatReady.Value = ready;
public void SetSpaceReady(bool ready) => spaceReady.Value = ready;
public void SetStage(StageName stageName) => StageState = new StageState(stageName);

public void Notify(string message)
{
if (Logger.IsDebug())
{
Logger.LogDebug($"Notification received: {message}");
}
Logger.LogError(message);
onNotificationReceived.OnNext(message);
}

Expand Down
3 changes: 3 additions & 0 deletions Assets/Holiday/App/AppUsage.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Assets/Holiday/App/AppUsage/AppUsageBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Diagnostics.CodeAnalysis;

namespace Extreal.SampleApp.Holiday.App.AppUsage
{
[SuppressMessage("Usage", "IDE1006")]
public class AppUsageBase
{
public string ClientId;
public string UsageId;
public string StageName;
}
}
3 changes: 3 additions & 0 deletions Assets/Holiday/App/AppUsage/AppUsageBase.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 108 additions & 0 deletions Assets/Holiday/App/AppUsage/AppUsageLogWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Cysharp.Threading.Tasks;
using Extreal.Core.Logging;
using Extreal.SampleApp.Holiday.App.Config;
using UnityEngine;
using UnityEngine.Networking;

namespace Extreal.SampleApp.Holiday.App.AppUsage
{
public class AppUsageLogWriter : ILogWriter
{
private readonly AppUsageConfig appUsageConfig;
private readonly AppScope.AppStateProvider appStateProvider;
private readonly ILogWriter defaultLogWriter;

public AppUsageLogWriter(
AppUsageConfig appUsageConfig,
AppScope.AppStateProvider appStateProvider,
ILogWriter defaultLogWriter = null)
{
this.appUsageConfig = appUsageConfig;
this.appStateProvider = appStateProvider;
this.defaultLogWriter = defaultLogWriter ?? new UnityDebugLogWriter();
}

private const string AppUsageCategory = nameof(AppUsage);

public void Log(LogLevel logLevel, string logCategory, string message, Exception exception = null)
{
if (!appUsageConfig.Enable)
{
defaultLogWriter.Log(logLevel, logCategory, message, exception);
return;
}

if (AppUsageCategory == logCategory)
{
SendAppUsage(message);
}
else if (LogLevel.Error == logLevel)
{
SendErrorLog(message, exception);
}
else
{
defaultLogWriter.Log(logLevel, logCategory, message, exception);
}
}

private void SendAppUsage(string jsonLogLine) => PostAsync(jsonLogLine).Forget();

[SuppressMessage("Usage", "CC0022"), SuppressMessage("Design", "CC0004"), SuppressMessage("Usage", "RS0030")]
private async UniTask PostAsync(string jsonLogLine)
{
var statusCode = default(long);
var exception = default(Exception);
try
{
var body = ToPostBody(jsonLogLine);
using var request = new UnityWebRequest(appUsageConfig.PushUrl, UnityWebRequest.kHttpVerbPOST)
{
uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(body)),
downloadHandler = new DownloadHandlerBuffer(),
timeout = appUsageConfig.TimeoutSeconds
};
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("X-Scope-OrgID", appUsageConfig.OrgId);
await request.SendWebRequest();
statusCode = request.responseCode;
}
catch (Exception e)
{
exception = e;
}
#if !HOLIDAY_PROD
// Logging for debugging during development.
// ELogger cannot be used because of the infinite loop.
if (statusCode != 0)
{
Debug.Log($"{nameof(AppUsageLogWriter)}:{statusCode}");
Debug.Log(jsonLogLine);
}

if (exception != null)
{
Debug.Log(exception.Message + Environment.NewLine + exception.StackTrace);
}
#endif
}

private static readonly string JsonPostBody =
"{\"streams\":[{\"stream\":{\"app\":\"@value@\"},\"values\":[[\"@epochNS@\",\"@logLine@\"]]}]}";

private static string ToPostBody(string jsonLogLine) =>
JsonPostBody
.Replace("@value@", nameof(Holiday))
.Replace("@epochNS@", (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 1000000).ToString())
.Replace("@logLine@", jsonLogLine.Replace("\"", "\\\""));

private void SendErrorLog(string message, Exception exception = null)
{
var errorStatus = ErrorStatus.Of(message, exception?.Message, exception?.StackTrace, LogType.Error, appUsageConfig);
SendAppUsage(AppUsageUtils.ToJson(errorStatus, appUsageConfig, appStateProvider.AppState));
}
}
}
3 changes: 3 additions & 0 deletions Assets/Holiday/App/AppUsage/AppUsageLogWriter.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b136d89

Please sign in to comment.