From 8f5d218a75a428b07f1d61c5a232fa07d6e17f62 Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 10:18:45 +0900 Subject: [PATCH 01/14] Mod logger settings to pluggable --- Editor/Localization/ja.po | 19 ++++++++ Editor/UI/Loggers.meta | 3 ++ Editor/UI/Loggers/ConsoleLoggerEditor.cs | 30 +++++++++++++ Editor/UI/Loggers/ConsoleLoggerEditor.cs.meta | 3 ++ Editor/UI/Settings/AutopilotSettingsEditor.cs | 6 +++ Runtime/Autopilot.cs | 20 ++++++--- Runtime/Loggers.meta | 3 ++ Runtime/Loggers/AbstractLogger.cs | 25 +++++++++++ Runtime/Loggers/AbstractLogger.cs.meta | 3 ++ Runtime/Loggers/ConsoleLogger.cs | 19 ++++++++ Runtime/Loggers/ConsoleLogger.cs.meta | 2 + .../ConsoleLoggerImpl.cs} | 6 +-- .../ConsoleLoggerImpl.cs.meta} | 0 Runtime/Settings/AutopilotSettings.cs | 8 +++- Tests/Runtime/AgentDispatcherTest.cs | 2 +- Tests/Runtime/Agents/DoNothingAgentTest.cs | 4 +- .../Runtime/Agents/EmergencyExitAgentTest.cs | 6 +-- Tests/Runtime/Agents/OneTimeAgentTest.cs | 8 ++-- .../Agents/ParallelCompositeAgentTest.cs | 6 +-- Tests/Runtime/Agents/RepeatAgentTest.cs | 6 +-- .../Agents/SerialCompositeAgentTest.cs | 6 +-- Tests/Runtime/Agents/TimeBombAgentTest.cs | 6 +-- Tests/Runtime/Agents/UGUIMonkeyAgentTest.cs | 6 +-- Tests/Runtime/Agents/UGUIPlaybackAgentTest.cs | 4 +- Tests/Runtime/AutopilotTest.cs | 44 +++++++++++++++++++ Tests/Runtime/AutopilotTest.cs.meta | 3 ++ Tests/Runtime/TestDoubles/SpyLogger.cs | 36 +++++++++++++++ Tests/Runtime/TestDoubles/SpyLogger.cs.meta | 3 ++ 28 files changed, 251 insertions(+), 36 deletions(-) create mode 100644 Editor/UI/Loggers.meta create mode 100644 Editor/UI/Loggers/ConsoleLoggerEditor.cs create mode 100644 Editor/UI/Loggers/ConsoleLoggerEditor.cs.meta create mode 100644 Runtime/Loggers.meta create mode 100644 Runtime/Loggers/AbstractLogger.cs create mode 100644 Runtime/Loggers/AbstractLogger.cs.meta create mode 100644 Runtime/Loggers/ConsoleLogger.cs create mode 100644 Runtime/Loggers/ConsoleLogger.cs.meta rename Runtime/{Utilities/ConsoleLogger.cs => Loggers/ConsoleLoggerImpl.cs} (96%) rename Runtime/{Utilities/ConsoleLogger.cs.meta => Loggers/ConsoleLoggerImpl.cs.meta} (100%) create mode 100644 Tests/Runtime/AutopilotTest.cs create mode 100644 Tests/Runtime/AutopilotTest.cs.meta create mode 100644 Tests/Runtime/TestDoubles/SpyLogger.cs create mode 100644 Tests/Runtime/TestDoubles/SpyLogger.cs.meta diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index dbcd845..b5bd79e 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -87,6 +87,14 @@ msgstr "JUnitレポート出力パス" msgid "JUnit report output path" msgstr "JUnit形式のレポートファイル出力パス(省略時は出力されない)" +# logger +msgid "Logger" +msgstr "ロガー" + +# logger tooltip +msgid "Logger used for this autopilot settings. If omitted, Debug.unityLogger will be used as default." +msgstr "オートパイロットが使用するロガー。 省略時は Debug.unityLogger がデフォルトとして使用されます" + # reporter msgid "Reporter" msgstr "レポータ" @@ -429,3 +437,14 @@ msgstr "Automated QAパッケージのRecorded Playbackウィンドウで記録 # composite reporters msgid "Reporters" msgstr "レポータ" + + +#: Editor/UI/Loggers/ 共通 + +# description (same as AutopilotSettingsEditor.cs) +msgid "Description" +msgstr "説明" + +# description tooltip +msgid "Description about this logger instance" +msgstr "このLoggerインスタンスの説明" diff --git a/Editor/UI/Loggers.meta b/Editor/UI/Loggers.meta new file mode 100644 index 0000000..0691f8e --- /dev/null +++ b/Editor/UI/Loggers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 88a22ed087bb4e048f747deb0e18a426 +timeCreated: 1714865499 \ No newline at end of file diff --git a/Editor/UI/Loggers/ConsoleLoggerEditor.cs b/Editor/UI/Loggers/ConsoleLoggerEditor.cs new file mode 100644 index 0000000..13dea30 --- /dev/null +++ b/Editor/UI/Loggers/ConsoleLoggerEditor.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using DeNA.Anjin.Loggers; +using UnityEditor; +using UnityEngine; + +namespace DeNA.Anjin.Editor.UI.Loggers +{ + /// + /// Editor GUI for ConsoleLogger. + /// + [CustomEditor(typeof(ConsoleLogger))] + public class ConsoleLoggerEditor : UnityEditor.Editor + { + private static readonly string s_description = L10n.Tr("Description"); + private static readonly string s_descriptionTooltip = L10n.Tr("Description about this logger instance"); + + /// + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLogger.description)), + new GUIContent(s_description, s_descriptionTooltip)); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Editor/UI/Loggers/ConsoleLoggerEditor.cs.meta b/Editor/UI/Loggers/ConsoleLoggerEditor.cs.meta new file mode 100644 index 0000000..6f4098b --- /dev/null +++ b/Editor/UI/Loggers/ConsoleLoggerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 148502be9aa7474cab0d904b74c2aee4 +timeCreated: 1714865512 \ No newline at end of file diff --git a/Editor/UI/Settings/AutopilotSettingsEditor.cs b/Editor/UI/Settings/AutopilotSettingsEditor.cs index 734c508..fab612d 100644 --- a/Editor/UI/Settings/AutopilotSettingsEditor.cs +++ b/Editor/UI/Settings/AutopilotSettingsEditor.cs @@ -42,6 +42,10 @@ public class AutopilotSettingsEditor : UnityEditor.Editor private static readonly string s_junitReportPath = L10n.Tr("JUnit Report Path"); private static readonly string s_junitReportPathTooltip = L10n.Tr("JUnit report output path"); + + private static readonly string s_logger = L10n.Tr("Logger"); + private static readonly string s_loggerTooltip = L10n.Tr("Logger used for this autopilot settings. If omitted, Debug.unityLogger will be used as default."); + private static readonly string s_reporter = L10n.Tr("Reporter"); private static readonly string s_reporterTooltip = L10n.Tr("Reporter that called when some errors occurred in target application"); @@ -111,6 +115,8 @@ public override void OnInspectorGUI() new GUIContent(s_timeScale, s_timeScaleTooltip)); EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.junitReportPath)), new GUIContent(s_junitReportPath, s_junitReportPathTooltip)); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.logger)), + new GUIContent(s_logger, s_loggerTooltip)); EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.reporter)), new GUIContent(s_reporter, s_reporterTooltip)); EditorGUILayout.HelpBox(s_obsoletedSlackParamsHelpBox, MessageType.Warning); diff --git a/Runtime/Autopilot.cs b/Runtime/Autopilot.cs index 252013e..cea7b54 100644 --- a/Runtime/Autopilot.cs +++ b/Runtime/Autopilot.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Threading; using Cysharp.Threading.Tasks; +using DeNA.Anjin.Loggers; using DeNA.Anjin.Settings; using DeNA.Anjin.Utilities; using UnityEngine; @@ -32,7 +33,14 @@ private void Start() _settings = _state.settings; Assert.IsNotNull(_settings); - _logger = CreateLogger(); + if (_settings.logger != null) + { + _logger = _settings.logger.LoggerImpl; + } + else + { + _logger = CreateDefaultLogger(); + } if (!int.TryParse(_settings.randomSeed, out var seed)) { @@ -61,15 +69,17 @@ private void Start() } _startTime = Time.realtimeSinceStartup; + _logger.Log("Launched autopilot"); } /// - /// Returns an agent dispatcher that autopilot uses. You can change a logger by overriding this method + /// Returns an logger that autopilot uses. You can change a logger by overriding this method. + /// Default logger is that write to console. /// - /// A new logger - protected virtual ILogger CreateLogger() + /// A new logger that write to console + protected virtual ILogger CreateDefaultLogger() { - return new ConsoleLogger(Debug.unityLogger.logHandler); + return new ConsoleLoggerImpl(Debug.unityLogger.logHandler); } /// diff --git a/Runtime/Loggers.meta b/Runtime/Loggers.meta new file mode 100644 index 0000000..20ba159 --- /dev/null +++ b/Runtime/Loggers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 333ef1bee73a4afeb213d974170d69f7 +timeCreated: 1714805458 \ No newline at end of file diff --git a/Runtime/Loggers/AbstractLogger.cs b/Runtime/Loggers/AbstractLogger.cs new file mode 100644 index 0000000..cf1bb05 --- /dev/null +++ b/Runtime/Loggers/AbstractLogger.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using UnityEngine; + +namespace DeNA.Anjin.Loggers +{ + /// + /// Abstract logger settings used for autopilot. + /// + public abstract class AbstractLogger : ScriptableObject + { +#if UNITY_EDITOR + /// + /// Description about this agent instance. + /// + [Multiline] public string description; +#endif + + /// + /// Logger implementation used for autopilot. + /// + public ILogger LoggerImpl { get; protected set; } + } +} diff --git a/Runtime/Loggers/AbstractLogger.cs.meta b/Runtime/Loggers/AbstractLogger.cs.meta new file mode 100644 index 0000000..a0f5626 --- /dev/null +++ b/Runtime/Loggers/AbstractLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09c42462b5c84179ad2e8060a77ddd2a +timeCreated: 1714805641 \ No newline at end of file diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLogger.cs new file mode 100644 index 0000000..5381c55 --- /dev/null +++ b/Runtime/Loggers/ConsoleLogger.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using UnityEngine; + +namespace DeNA.Anjin.Loggers +{ + /// + /// Logger using Debug.unityLogger + /// + [CreateAssetMenu(fileName = "New ConsoleLogger", menuName = "Anjin/Console Logger", order = 71)] + public class ConsoleLogger : AbstractLogger + { + public ConsoleLogger() + { + LoggerImpl = new ConsoleLoggerImpl(Debug.unityLogger.logHandler); + } + } +} diff --git a/Runtime/Loggers/ConsoleLogger.cs.meta b/Runtime/Loggers/ConsoleLogger.cs.meta new file mode 100644 index 0000000..b58e9e5 --- /dev/null +++ b/Runtime/Loggers/ConsoleLogger.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e5b0f8b0450fb478d95fe8ea52ea83ff \ No newline at end of file diff --git a/Runtime/Utilities/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLoggerImpl.cs similarity index 96% rename from Runtime/Utilities/ConsoleLogger.cs rename to Runtime/Loggers/ConsoleLoggerImpl.cs index 2732926..7f0cd0b 100644 --- a/Runtime/Utilities/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLoggerImpl.cs @@ -5,12 +5,12 @@ using UnityEngine; using Object = UnityEngine.Object; -namespace DeNA.Anjin.Utilities +namespace DeNA.Anjin.Loggers { /// /// Logger using Debug.unityLogger /// - public class ConsoleLogger : ILogger + public class ConsoleLoggerImpl : ILogger { private readonly ILogger _loggerImpl = Debug.unityLogger; @@ -27,7 +27,7 @@ public class ConsoleLogger : ILogger /// Constructor /// /// - public ConsoleLogger(ILogHandler handler) + public ConsoleLoggerImpl(ILogHandler handler) { this.logHandler = handler; this.logEnabled = true; diff --git a/Runtime/Utilities/ConsoleLogger.cs.meta b/Runtime/Loggers/ConsoleLoggerImpl.cs.meta similarity index 100% rename from Runtime/Utilities/ConsoleLogger.cs.meta rename to Runtime/Loggers/ConsoleLoggerImpl.cs.meta diff --git a/Runtime/Settings/AutopilotSettings.cs b/Runtime/Settings/AutopilotSettings.cs index 78279a0..df6a754 100644 --- a/Runtime/Settings/AutopilotSettings.cs +++ b/Runtime/Settings/AutopilotSettings.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using DeNA.Anjin.Agents; +using DeNA.Anjin.Loggers; using DeNA.Anjin.Reporters; using UnityEngine; @@ -125,11 +126,16 @@ public class AutopilotSettings : ScriptableObject /// public string[] ignoreMessages; + /// + /// Logger used for this autopilot settings. + /// + public AbstractLogger logger; + /// /// Reporter that called when some errors occurred /// public AbstractReporter reporter; - + /// /// Overwrites specified values in the command line arguments /// diff --git a/Tests/Runtime/AgentDispatcherTest.cs b/Tests/Runtime/AgentDispatcherTest.cs index 9d88356..7686a5e 100644 --- a/Tests/Runtime/AgentDispatcherTest.cs +++ b/Tests/Runtime/AgentDispatcherTest.cs @@ -58,7 +58,7 @@ private static SpyAliveCountAgent CreateSpyAliveCountAgent(string name = nameof( private void SetUpDispatcher(AutopilotSettings settings) { - var logger = new ConsoleLogger(Debug.unityLogger.logHandler); + var logger = Debug.unityLogger; var randomFactory = new RandomFactory(0); _dispatcher = new AgentDispatcher(settings, logger, randomFactory); diff --git a/Tests/Runtime/Agents/DoNothingAgentTest.cs b/Tests/Runtime/Agents/DoNothingAgentTest.cs index 8e4f48e..6ea92a9 100644 --- a/Tests/Runtime/Agents/DoNothingAgentTest.cs +++ b/Tests/Runtime/Agents/DoNothingAgentTest.cs @@ -18,7 +18,7 @@ public class DoNothingAgentTest public async Task Run_cancelTask_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.lifespanSec = 0; // Expect indefinite execution @@ -41,7 +41,7 @@ public async Task Run_cancelTask_stopAgent() public async Task Run_lifespanPassed_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_lifespanPassed_stopAgent); agent.lifespanSec = 1; diff --git a/Tests/Runtime/Agents/EmergencyExitAgentTest.cs b/Tests/Runtime/Agents/EmergencyExitAgentTest.cs index dbff6b2..6c92ca6 100644 --- a/Tests/Runtime/Agents/EmergencyExitAgentTest.cs +++ b/Tests/Runtime/Agents/EmergencyExitAgentTest.cs @@ -23,7 +23,7 @@ public class EmergencyExitAgentTest public async Task Run_cancelTask_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); @@ -53,7 +53,7 @@ private static SpyButton CreateButtonWithEmergencyExitAnnotation(bool interactab public async Task Run_existEmergencyExitButton_ClickEmergencyExitButton() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); @@ -81,7 +81,7 @@ public async Task Run_existEmergencyExitButton_ClickEmergencyExitButton() public async Task Run_existNotInteractableEmergencyExitButton_DoesNotClickEmergencyExitButton() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); diff --git a/Tests/Runtime/Agents/OneTimeAgentTest.cs b/Tests/Runtime/Agents/OneTimeAgentTest.cs index 6c619f0..eab1cf6 100644 --- a/Tests/Runtime/Agents/OneTimeAgentTest.cs +++ b/Tests/Runtime/Agents/OneTimeAgentTest.cs @@ -33,7 +33,7 @@ public async Task Run_cancelTask_stopAgent() var childAgent = CreateChildAgent(5000); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; @@ -58,7 +58,7 @@ public async Task Run_markWasExecuted() var childAgent = CreateChildAgent(100); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; @@ -83,7 +83,7 @@ public async Task Run_wasExecuted_notExecuteChildAgent() var childAgent = CreateChildAgent(100); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; @@ -108,7 +108,7 @@ public async Task Run_setLoggerAndRandomInstanceToChildAgent() var childAgent = CreateChildAgent(100); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; diff --git a/Tests/Runtime/Agents/ParallelCompositeAgentTest.cs b/Tests/Runtime/Agents/ParallelCompositeAgentTest.cs index 8a0d652..f181178 100644 --- a/Tests/Runtime/Agents/ParallelCompositeAgentTest.cs +++ b/Tests/Runtime/Agents/ParallelCompositeAgentTest.cs @@ -35,7 +35,7 @@ public async Task Run_cancelTask_stopAgent() var lastChildAgent = CreateChildAgent(500); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agents = new List() { firstChildAgent, secondChildAgent, lastChildAgent }; @@ -67,7 +67,7 @@ public async Task Run_lifespanPassed_stopAgent() var lastChildAgent = CreateChildAgent(500); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_lifespanPassed_stopAgent); agent.agents = new List() { firstChildAgent, secondChildAgent, lastChildAgent }; @@ -96,7 +96,7 @@ public async Task Run_setLoggerAndRandomInstanceToChildAgent() var lastChildAgent = CreateChildAgent(500); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_setLoggerAndRandomInstanceToChildAgent); agent.agents = new List() { firstChildAgent, secondChildAgent, lastChildAgent }; diff --git a/Tests/Runtime/Agents/RepeatAgentTest.cs b/Tests/Runtime/Agents/RepeatAgentTest.cs index 7565b00..9637d2f 100644 --- a/Tests/Runtime/Agents/RepeatAgentTest.cs +++ b/Tests/Runtime/Agents/RepeatAgentTest.cs @@ -31,7 +31,7 @@ public async Task Run_cancelTask_stopAgent() var childAgent = CreateChildAgent(100); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; @@ -56,7 +56,7 @@ public async Task Run_childAgentRunRepeating() var childAgent = CreateChildAgent(100); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; @@ -82,7 +82,7 @@ public async Task Run_setLoggerAndRandomInstanceToChildAgent() var childAgent = CreateChildAgent(100); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agent = childAgent; diff --git a/Tests/Runtime/Agents/SerialCompositeAgentTest.cs b/Tests/Runtime/Agents/SerialCompositeAgentTest.cs index 2f4fdda..7d3b947 100644 --- a/Tests/Runtime/Agents/SerialCompositeAgentTest.cs +++ b/Tests/Runtime/Agents/SerialCompositeAgentTest.cs @@ -35,7 +35,7 @@ public async Task Run_cancelTask_stopAgent() var lastChildAgent = CreateChildAgent(500); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.agents = new List() { firstChildAgent, secondChildAgent, lastChildAgent }; @@ -67,7 +67,7 @@ public async Task Run_lifespanPassed_stopAgent() var lastChildAgent = CreateChildAgent(500); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_lifespanPassed_stopAgent); agent.agents = new List() { firstChildAgent, secondChildAgent, lastChildAgent }; @@ -96,7 +96,7 @@ public async Task Run_setLoggerAndRandomInstanceToChildAgent() var lastChildAgent = CreateChildAgent(500); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_setLoggerAndRandomInstanceToChildAgent); agent.agents = new List() { firstChildAgent, secondChildAgent, lastChildAgent }; diff --git a/Tests/Runtime/Agents/TimeBombAgentTest.cs b/Tests/Runtime/Agents/TimeBombAgentTest.cs index b4b749f..07b1379 100644 --- a/Tests/Runtime/Agents/TimeBombAgentTest.cs +++ b/Tests/Runtime/Agents/TimeBombAgentTest.cs @@ -42,7 +42,7 @@ public async Task Run_CancelTask_StopAgent() { var monkeyAgent = CreateMonkeyAgent(5); var agent = CreateTimeBombAgent(monkeyAgent, "^Never match!$"); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); using (var cts = new CancellationTokenSource()) @@ -68,7 +68,7 @@ public async Task Run_Defuse_StopAgent() { var monkeyAgent = CreateMonkeyAgent(5); var agent = CreateTimeBombAgent(monkeyAgent, "^Tutorial Completed!$"); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); using (var cts = new CancellationTokenSource()) @@ -89,7 +89,7 @@ public async Task Run_NotDefuse_ThrowsTimeoutException() { var monkeyAgent = CreateMonkeyAgent(1); var agent = CreateTimeBombAgent(monkeyAgent, "^Never match!$"); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); using (var cts = new CancellationTokenSource()) diff --git a/Tests/Runtime/Agents/UGUIMonkeyAgentTest.cs b/Tests/Runtime/Agents/UGUIMonkeyAgentTest.cs index e8cd1ae..a4b1f97 100644 --- a/Tests/Runtime/Agents/UGUIMonkeyAgentTest.cs +++ b/Tests/Runtime/Agents/UGUIMonkeyAgentTest.cs @@ -36,7 +36,7 @@ await EditorSceneManager.LoadSceneAsyncInPlayMode( public async Task Run_cancelTask_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.lifespanSec = 0; // Expect indefinite execution @@ -60,7 +60,7 @@ public async Task Run_cancelTask_stopAgent() public async Task Run_lifespanPassed_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_lifespanPassed_stopAgent); agent.lifespanSec = 1; @@ -94,7 +94,7 @@ public async Task Run_DefaultScreenshotFilenamePrefix_UseAgentName() Assume.That(path, Does.Not.Exist); var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = AgentName; agent.lifespanSec = 1; diff --git a/Tests/Runtime/Agents/UGUIPlaybackAgentTest.cs b/Tests/Runtime/Agents/UGUIPlaybackAgentTest.cs index 104a709..467c3ed 100644 --- a/Tests/Runtime/Agents/UGUIPlaybackAgentTest.cs +++ b/Tests/Runtime/Agents/UGUIPlaybackAgentTest.cs @@ -30,7 +30,7 @@ await EditorSceneManager.LoadSceneAsyncInPlayMode( public async Task Run_cancelTask_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_cancelTask_stopAgent); agent.recordedJson = AssetDatabase.LoadAssetAtPath( @@ -54,7 +54,7 @@ public async Task Run_cancelTask_stopAgent() public async Task Run_playbackFinished_stopAgent() { var agent = ScriptableObject.CreateInstance(); - agent.Logger = new ConsoleLogger(Debug.unityLogger.logHandler); + agent.Logger = Debug.unityLogger; agent.Random = new RandomFactory(0).CreateRandom(); agent.name = nameof(Run_playbackFinished_stopAgent); agent.recordedJson = AssetDatabase.LoadAssetAtPath( diff --git a/Tests/Runtime/AutopilotTest.cs b/Tests/Runtime/AutopilotTest.cs new file mode 100644 index 0000000..f13684f --- /dev/null +++ b/Tests/Runtime/AutopilotTest.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using System.Collections.Generic; +using System.Threading.Tasks; +using DeNA.Anjin.Settings; +using DeNA.Anjin.TestDoubles; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace DeNA.Anjin +{ + [TestFixture] + public class AutopilotTest + { + [Test] + public async Task Start_LoggerIsNotSet_UsingDefaultLogger() + { + var autopilotSettings = ScriptableObject.CreateInstance(); + autopilotSettings.sceneAgentMaps = new List(); + autopilotSettings.lifespanSec = 1; + + await LauncherFromTest.AutopilotAsync(autopilotSettings); + + LogAssert.Expect(LogType.Log, "Launched autopilot"); // using console logger + } + + [Test] + public async Task Start_LoggerSpecified_UsingSpecifiedLogger() + { + var autopilotSettings = ScriptableObject.CreateInstance(); + autopilotSettings.sceneAgentMaps = new List(); + autopilotSettings.lifespanSec = 1; + var spyLogger = ScriptableObject.CreateInstance(); + autopilotSettings.logger = spyLogger; + + await LauncherFromTest.AutopilotAsync(autopilotSettings); + + Assert.That(spyLogger.Logs, Does.Contain("Launched autopilot")); // using spy logger + LogAssert.NoUnexpectedReceived(); // not write to console + } + } +} diff --git a/Tests/Runtime/AutopilotTest.cs.meta b/Tests/Runtime/AutopilotTest.cs.meta new file mode 100644 index 0000000..4244c38 --- /dev/null +++ b/Tests/Runtime/AutopilotTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a14a91f9386146a5b97b92704bee4cfc +timeCreated: 1714869131 \ No newline at end of file diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs b/Tests/Runtime/TestDoubles/SpyLogger.cs new file mode 100644 index 0000000..81b2c74 --- /dev/null +++ b/Tests/Runtime/TestDoubles/SpyLogger.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using System; +using System.Collections.Generic; +using DeNA.Anjin.Loggers; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace DeNA.Anjin.TestDoubles +{ + public class SpyLogger : AbstractLogger + { + public List Logs => ((SpyLogHandler)((Logger)LoggerImpl).logHandler).Logs; + + public SpyLogger() + { + LoggerImpl = new Logger(new SpyLogHandler()); + } + + private class SpyLogHandler : ILogHandler + { + public readonly List Logs = new List(); + + public void LogFormat(LogType logType, Object context, string format, params object[] args) + { + Logs.Add(string.Format(format, args)); + } + + public void LogException(Exception exception, Object context) + { + Logs.Add(exception.ToString()); + } + } + } +} diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs.meta b/Tests/Runtime/TestDoubles/SpyLogger.cs.meta new file mode 100644 index 0000000..2d3ed95 --- /dev/null +++ b/Tests/Runtime/TestDoubles/SpyLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d16166bc06ee4dbdbab913e0ffd48c35 +timeCreated: 1714870143 \ No newline at end of file From e52207e832c02885520351f5e5831f61aa9a6067 Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 11:26:25 +0900 Subject: [PATCH 02/14] Refactor ConsoleLogger The `ILogHandler` specified in the constructor of `ConsoleLoggerImpl` was not used. --- Runtime/Autopilot.cs | 3 +- Runtime/Loggers/ConsoleLogger.cs | 3 +- Runtime/Loggers/ConsoleLoggerImpl.cs | 133 ---------------------- Runtime/Loggers/ConsoleLoggerImpl.cs.meta | 3 - 4 files changed, 3 insertions(+), 139 deletions(-) delete mode 100644 Runtime/Loggers/ConsoleLoggerImpl.cs delete mode 100644 Runtime/Loggers/ConsoleLoggerImpl.cs.meta diff --git a/Runtime/Autopilot.cs b/Runtime/Autopilot.cs index cea7b54..a6416ac 100644 --- a/Runtime/Autopilot.cs +++ b/Runtime/Autopilot.cs @@ -5,7 +5,6 @@ using System.Collections; using System.Threading; using Cysharp.Threading.Tasks; -using DeNA.Anjin.Loggers; using DeNA.Anjin.Settings; using DeNA.Anjin.Utilities; using UnityEngine; @@ -79,7 +78,7 @@ private void Start() /// A new logger that write to console protected virtual ILogger CreateDefaultLogger() { - return new ConsoleLoggerImpl(Debug.unityLogger.logHandler); + return Debug.unityLogger; } /// diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLogger.cs index 5381c55..18f1671 100644 --- a/Runtime/Loggers/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLogger.cs @@ -13,7 +13,8 @@ public class ConsoleLogger : AbstractLogger { public ConsoleLogger() { - LoggerImpl = new ConsoleLoggerImpl(Debug.unityLogger.logHandler); + LoggerImpl = new Logger(Debug.unityLogger.logHandler); + LoggerImpl.filterLogType = LogType.Log; } } } diff --git a/Runtime/Loggers/ConsoleLoggerImpl.cs b/Runtime/Loggers/ConsoleLoggerImpl.cs deleted file mode 100644 index 7f0cd0b..0000000 --- a/Runtime/Loggers/ConsoleLoggerImpl.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2023 DeNA Co., Ltd. -// This software is released under the MIT License. - -using System; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace DeNA.Anjin.Loggers -{ - /// - /// Logger using Debug.unityLogger - /// - public class ConsoleLoggerImpl : ILogger - { - private readonly ILogger _loggerImpl = Debug.unityLogger; - - /// - public ILogHandler logHandler { get; set; } - - /// - public bool logEnabled { get; set; } - - /// - public LogType filterLogType { get; set; } - - /// - /// Constructor - /// - /// - public ConsoleLoggerImpl(ILogHandler handler) - { - this.logHandler = handler; - this.logEnabled = true; - this.filterLogType = LogType.Log; - } - - /// - public void LogFormat(LogType logType, Object context, string format, params object[] args) - { - _loggerImpl.LogFormat(logType, context, format, args); - } - - /// - public void LogException(Exception exception, Object context) - { - _loggerImpl.LogException(exception, context); - } - - /// - public bool IsLogTypeAllowed(LogType logType) - { - return _loggerImpl.IsLogTypeAllowed(logType); - } - - /// - public void Log(LogType logType, object message) - { - _loggerImpl.Log(logType, message); - } - - /// - public void Log(LogType logType, object message, Object context) - { - _loggerImpl.Log(logType, message, context); - } - - /// - public void Log(LogType logType, string tag, object message) - { - _loggerImpl.Log(logType, tag, message); - } - - /// - public void Log(LogType logType, string tag, object message, Object context) - { - _loggerImpl.Log(logType, tag, message, context); - } - - /// - public void Log(object message) - { - _loggerImpl.Log(message); - } - - /// - public void Log(string tag, object message) - { - _loggerImpl.Log(tag, message); - } - - /// - public void Log(string tag, object message, Object context) - { - _loggerImpl.Log(tag, message, context); - } - - /// - public void LogWarning(string tag, object message) - { - _loggerImpl.LogWarning(tag, message); - } - - /// - public void LogWarning(string tag, object message, Object context) - { - _loggerImpl.LogWarning(tag, message, context); - } - - /// - public void LogError(string tag, object message) - { - _loggerImpl.LogError(tag, message); - } - - /// - public void LogError(string tag, object message, Object context) - { - _loggerImpl.LogError(tag, message, context); - } - - /// - public void LogFormat(LogType logType, string format, params object[] args) - { - _loggerImpl.LogFormat(logType, format, args); - } - - /// - public void LogException(Exception exception) - { - _loggerImpl.LogException(exception); - } - } -} diff --git a/Runtime/Loggers/ConsoleLoggerImpl.cs.meta b/Runtime/Loggers/ConsoleLoggerImpl.cs.meta deleted file mode 100644 index 9ff365a..0000000 --- a/Runtime/Loggers/ConsoleLoggerImpl.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 563470594a76466aa6a66ed3dbaa14f1 -timeCreated: 1618219385 \ No newline at end of file From 4a354a9059da4a9b9a438083e54276a1631d865d Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 11:47:11 +0900 Subject: [PATCH 03/14] Add filtering LogType option --- Editor/Localization/ja.po | 11 +++++ Editor/UI/Loggers/ConsoleLoggerEditor.cs | 5 +++ Runtime/Loggers/AbstractLogger.cs | 2 +- Runtime/Loggers/ConsoleLogger.cs | 13 +++--- Tests/Runtime/Loggers.meta | 3 ++ Tests/Runtime/Loggers/ConsoleLoggerTest.cs | 41 +++++++++++++++++++ .../Runtime/Loggers/ConsoleLoggerTest.cs.meta | 3 ++ Tests/Runtime/TestDoubles/SpyLogger.cs | 19 +++++++-- 8 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 Tests/Runtime/Loggers.meta create mode 100644 Tests/Runtime/Loggers/ConsoleLoggerTest.cs create mode 100644 Tests/Runtime/Loggers/ConsoleLoggerTest.cs.meta diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index b5bd79e..3f4810d 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -448,3 +448,14 @@ msgstr "説明" # description tooltip msgid "Description about this logger instance" msgstr "このLoggerインスタンスの説明" + + +#: Editor/UI/Loggers/ConsoleLoggerEditor.cs + +# Filter LogType +msgid "Filter LogType" +msgstr "フィルタリングLogType" + +# Filter LogType tooltip +msgid "To selective enable debug log message" +msgstr "選択したLogType以上のログ出力のみを有効にします" diff --git a/Editor/UI/Loggers/ConsoleLoggerEditor.cs b/Editor/UI/Loggers/ConsoleLoggerEditor.cs index 13dea30..640b2e8 100644 --- a/Editor/UI/Loggers/ConsoleLoggerEditor.cs +++ b/Editor/UI/Loggers/ConsoleLoggerEditor.cs @@ -16,6 +16,9 @@ public class ConsoleLoggerEditor : UnityEditor.Editor private static readonly string s_description = L10n.Tr("Description"); private static readonly string s_descriptionTooltip = L10n.Tr("Description about this logger instance"); + private static readonly string s_filterLogType = L10n.Tr("Filter LogType"); + private static readonly string s_filterLogTypeTooltip = L10n.Tr("To selective enable debug log message"); + /// public override void OnInspectorGUI() { @@ -23,6 +26,8 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLogger.description)), new GUIContent(s_description, s_descriptionTooltip)); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLogger.filterLogType)), + new GUIContent(s_filterLogType, s_filterLogTypeTooltip)); serializedObject.ApplyModifiedProperties(); } diff --git a/Runtime/Loggers/AbstractLogger.cs b/Runtime/Loggers/AbstractLogger.cs index cf1bb05..e62ac12 100644 --- a/Runtime/Loggers/AbstractLogger.cs +++ b/Runtime/Loggers/AbstractLogger.cs @@ -20,6 +20,6 @@ public abstract class AbstractLogger : ScriptableObject /// /// Logger implementation used for autopilot. /// - public ILogger LoggerImpl { get; protected set; } + public abstract ILogger LoggerImpl { get; } } } diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLogger.cs index 18f1671..798b609 100644 --- a/Runtime/Loggers/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLogger.cs @@ -11,10 +11,13 @@ namespace DeNA.Anjin.Loggers [CreateAssetMenu(fileName = "New ConsoleLogger", menuName = "Anjin/Console Logger", order = 71)] public class ConsoleLogger : AbstractLogger { - public ConsoleLogger() - { - LoggerImpl = new Logger(Debug.unityLogger.logHandler); - LoggerImpl.filterLogType = LogType.Log; - } + /// + /// To selective enable debug log message. + /// + public LogType filterLogType = LogType.Log; + + /// + public override ILogger LoggerImpl => + new Logger(Debug.unityLogger.logHandler) { filterLogType = filterLogType }; } } diff --git a/Tests/Runtime/Loggers.meta b/Tests/Runtime/Loggers.meta new file mode 100644 index 0000000..ab76f99 --- /dev/null +++ b/Tests/Runtime/Loggers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 29af5ac6a1de46fdb89fd8495a14e22b +timeCreated: 1714878353 \ No newline at end of file diff --git a/Tests/Runtime/Loggers/ConsoleLoggerTest.cs b/Tests/Runtime/Loggers/ConsoleLoggerTest.cs new file mode 100644 index 0000000..b448425 --- /dev/null +++ b/Tests/Runtime/Loggers/ConsoleLoggerTest.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace DeNA.Anjin.Loggers +{ + [TestFixture] + public class ConsoleLoggerTest + { + [Test] + public void FilterLogTypeIsNotSet_LogAsDefault() + { + var message = TestContext.CurrentContext.Test.Name; + var sut = ScriptableObject.CreateInstance(); + + sut.LoggerImpl.Log(message); + + LogAssert.Expect(LogType.Log, message); + LogAssert.NoUnexpectedReceived(); + } + + [Test] + public void FilterLogTypeSpecified( + [Values(LogType.Error, LogType.Assert, LogType.Warning, LogType.Exception)] + LogType logType) + { + var message = TestContext.CurrentContext.Test.Name; + var sut = ScriptableObject.CreateInstance(); + sut.filterLogType = logType; + + sut.LoggerImpl.Log(logType, message); + sut.LoggerImpl.Log("Not output message because LogType.Log"); + + LogAssert.Expect(logType, message); + LogAssert.NoUnexpectedReceived(); + } + } +} diff --git a/Tests/Runtime/Loggers/ConsoleLoggerTest.cs.meta b/Tests/Runtime/Loggers/ConsoleLoggerTest.cs.meta new file mode 100644 index 0000000..0c72e66 --- /dev/null +++ b/Tests/Runtime/Loggers/ConsoleLoggerTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0a237e9591494b6b92a3b8440dcec4d3 +timeCreated: 1714878397 \ No newline at end of file diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs b/Tests/Runtime/TestDoubles/SpyLogger.cs index 81b2c74..b9da316 100644 --- a/Tests/Runtime/TestDoubles/SpyLogger.cs +++ b/Tests/Runtime/TestDoubles/SpyLogger.cs @@ -11,13 +11,26 @@ namespace DeNA.Anjin.TestDoubles { public class SpyLogger : AbstractLogger { - public List Logs => ((SpyLogHandler)((Logger)LoggerImpl).logHandler).Logs; + private SpyLogHandler _handler; + private ILogger _logger; - public SpyLogger() + public override ILogger LoggerImpl { - LoggerImpl = new Logger(new SpyLogHandler()); + get + { + if (_logger != null) + { + return _logger; + } + + _handler = new SpyLogHandler(); + _logger = new Logger(_handler); + return _logger; + } } + public List Logs => _handler.Logs; + private class SpyLogHandler : ILogHandler { public readonly List Logs = new List(); From 20d6222a46c49a72e92d5e64fa02550c6048dddb Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 13:14:14 +0900 Subject: [PATCH 04/14] Add CompositeLogger --- Editor/Localization/ja.po | 11 ++++ Editor/UI/Loggers/CompositeLoggerEditor.cs | 35 +++++++++++++ .../UI/Loggers/CompositeLoggerEditor.cs.meta | 3 ++ Runtime/Loggers/CompositeLogger.cs | 51 +++++++++++++++++++ Runtime/Loggers/CompositeLogger.cs.meta | 3 ++ Tests/Runtime/Loggers/CompositeLoggerTest.cs | 30 +++++++++++ .../Loggers/CompositeLoggerTest.cs.meta | 3 ++ 7 files changed, 136 insertions(+) create mode 100644 Editor/UI/Loggers/CompositeLoggerEditor.cs create mode 100644 Editor/UI/Loggers/CompositeLoggerEditor.cs.meta create mode 100644 Runtime/Loggers/CompositeLogger.cs create mode 100644 Runtime/Loggers/CompositeLogger.cs.meta create mode 100644 Tests/Runtime/Loggers/CompositeLoggerTest.cs create mode 100644 Tests/Runtime/Loggers/CompositeLoggerTest.cs.meta diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index 3f4810d..df19508 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -450,6 +450,17 @@ msgid "Description about this logger instance" msgstr "このLoggerインスタンスの説明" +#: Editor/UI/Loggers/CompositeLoggerEditor.cs + +# Loggers +msgid "Loggers" +msgstr "Loggers" + +# Loggers tooltip +msgid "Loggers to delegates" +msgstr "出力を委譲するLoggerを指定します" + + #: Editor/UI/Loggers/ConsoleLoggerEditor.cs # Filter LogType diff --git a/Editor/UI/Loggers/CompositeLoggerEditor.cs b/Editor/UI/Loggers/CompositeLoggerEditor.cs new file mode 100644 index 0000000..0b39e4a --- /dev/null +++ b/Editor/UI/Loggers/CompositeLoggerEditor.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using DeNA.Anjin.Loggers; +using UnityEditor; +using UnityEngine; + +namespace DeNA.Anjin.Editor.UI.Loggers +{ + /// + /// Editor GUI for CompositeLogger. + /// + [CustomEditor(typeof(CompositeLogger))] + public class CompositeLoggerEditor : UnityEditor.Editor + { + private static readonly string s_description = L10n.Tr("Description"); + private static readonly string s_descriptionTooltip = L10n.Tr("Description about this logger instance"); + + private static readonly string s_loggers = L10n.Tr("Loggers"); + private static readonly string s_loggersTooltip = L10n.Tr("Loggers to delegates"); + + /// + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(CompositeLogger.description)), + new GUIContent(s_description, s_descriptionTooltip)); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(CompositeLogger.loggers)), + new GUIContent(s_loggers, s_loggersTooltip)); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Editor/UI/Loggers/CompositeLoggerEditor.cs.meta b/Editor/UI/Loggers/CompositeLoggerEditor.cs.meta new file mode 100644 index 0000000..82151f6 --- /dev/null +++ b/Editor/UI/Loggers/CompositeLoggerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 352e692ebfdd40a5827e212bf2d5bd2c +timeCreated: 1714883649 \ No newline at end of file diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLogger.cs new file mode 100644 index 0000000..36ee90b --- /dev/null +++ b/Runtime/Loggers/CompositeLogger.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using System; +using System.Collections.Generic; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace DeNA.Anjin.Loggers +{ + /// + /// A class for a logger that delegates to multiple loggers + /// + [CreateAssetMenu(fileName = "New CompositeLogger", menuName = "Anjin/Composite Logger", order = 70)] + public class CompositeLogger : AbstractLogger + { + /// + /// Loggers to delegates + /// + public List loggers = new List(); + + /// + public override ILogger LoggerImpl => new Logger(new CompositeLogHandler(loggers)); + + private class CompositeLogHandler : ILogHandler + { + private readonly List _loggers; + + public CompositeLogHandler(List loggers) + { + _loggers = loggers; + } + + public void LogFormat(LogType logType, Object context, string format, params object[] args) + { + foreach (var logger in _loggers) + { + logger.LoggerImpl.LogFormat(logType, context, format, args); + } + } + + public void LogException(Exception exception, Object context) + { + foreach (var logger in _loggers) + { + logger.LoggerImpl.LogException(exception, context); + } + } + } + } +} diff --git a/Runtime/Loggers/CompositeLogger.cs.meta b/Runtime/Loggers/CompositeLogger.cs.meta new file mode 100644 index 0000000..970dca3 --- /dev/null +++ b/Runtime/Loggers/CompositeLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a46fe0a596d461bb0d039469d2b9ab4 +timeCreated: 1714880656 \ No newline at end of file diff --git a/Tests/Runtime/Loggers/CompositeLoggerTest.cs b/Tests/Runtime/Loggers/CompositeLoggerTest.cs new file mode 100644 index 0000000..c1a42c5 --- /dev/null +++ b/Tests/Runtime/Loggers/CompositeLoggerTest.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace DeNA.Anjin.Loggers +{ + [TestFixture] + public class CompositeLoggerTest + { + [Test] + public void CompositeTwoLoggers_OutputBothLoggers() + { + var message = TestContext.CurrentContext.Test.Name; + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(logger1); + sut.loggers.Add(logger2); + + sut.LoggerImpl.Log(message); + + LogAssert.Expect(LogType.Log, message); + LogAssert.Expect(LogType.Log, message); // log output twice + LogAssert.NoUnexpectedReceived(); + } + } +} diff --git a/Tests/Runtime/Loggers/CompositeLoggerTest.cs.meta b/Tests/Runtime/Loggers/CompositeLoggerTest.cs.meta new file mode 100644 index 0000000..de358d1 --- /dev/null +++ b/Tests/Runtime/Loggers/CompositeLoggerTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 63cb26cf1f0441628dcb883967d1911f +timeCreated: 1714881859 \ No newline at end of file From 8857cff44698edc163dd9ba9b1fb0e84f3e285ef Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 14:26:23 +0900 Subject: [PATCH 05/14] Add FileLogger --- Editor/Localization/ja.po | 11 ++ Editor/UI/Loggers/FileLoggerEditor.cs | 40 +++++++ Editor/UI/Loggers/FileLoggerEditor.cs.meta | 3 + Runtime/Autopilot.cs | 12 +-- Runtime/Loggers/AbstractLogger.cs | 6 +- Runtime/Loggers/CompositeLogger.cs | 6 ++ Runtime/Loggers/ConsoleLogger.cs | 6 ++ Runtime/Loggers/FileLogger.cs | 94 +++++++++++++++++ Runtime/Loggers/FileLogger.cs.meta | 3 + Tests/Runtime/Loggers/FileLoggerTest.cs | 103 +++++++++++++++++++ Tests/Runtime/Loggers/FileLoggerTest.cs.meta | 3 + Tests/Runtime/TestDoubles/SpyLogger.cs | 5 + 12 files changed, 282 insertions(+), 10 deletions(-) create mode 100644 Editor/UI/Loggers/FileLoggerEditor.cs create mode 100644 Editor/UI/Loggers/FileLoggerEditor.cs.meta create mode 100644 Runtime/Loggers/FileLogger.cs create mode 100644 Runtime/Loggers/FileLogger.cs.meta create mode 100644 Tests/Runtime/Loggers/FileLoggerTest.cs create mode 100644 Tests/Runtime/Loggers/FileLoggerTest.cs.meta diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index df19508..b3fb296 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -470,3 +470,14 @@ msgstr "フィルタリングLogType" # Filter LogType tooltip msgid "To selective enable debug log message" msgstr "選択したLogType以上のログ出力のみを有効にします" + + +#: Editor/UI/Loggers/FileLoggerEditor.cs + +# Output Path +msgid "Output File Path" +msgstr "出力ファイルパス" + +# Output Path tooltip +msgid "Log output file path. Specify relative path from project root or absolute path." +msgstr "ログ出力ファイルのパス。プロジェクトルートからの相対パスまたは絶対パスを指定します" diff --git a/Editor/UI/Loggers/FileLoggerEditor.cs b/Editor/UI/Loggers/FileLoggerEditor.cs new file mode 100644 index 0000000..450309a --- /dev/null +++ b/Editor/UI/Loggers/FileLoggerEditor.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using DeNA.Anjin.Loggers; +using UnityEditor; +using UnityEngine; + +namespace DeNA.Anjin.Editor.UI.Loggers +{ + /// + /// Editor GUI for FileLogger. + /// + [CustomEditor(typeof(FileLogger))] + public class FileLoggerEditor : UnityEditor.Editor + { + private static readonly string s_description = L10n.Tr("Description"); + private static readonly string s_descriptionTooltip = L10n.Tr("Description about this logger instance"); + + private static readonly string s_outputPath = L10n.Tr("Output File Path"); + private static readonly string s_outputPathTooltip = L10n.Tr("Log output file path. Specify relative path from project root or absolute path."); + + private static readonly string s_filterLogType = L10n.Tr("Filter LogType"); + private static readonly string s_filterLogTypeTooltip = L10n.Tr("To selective enable debug log message"); + + /// + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.description)), + new GUIContent(s_description, s_descriptionTooltip)); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.outputPath)), + new GUIContent(s_outputPath, s_outputPathTooltip)); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.filterLogType)), + new GUIContent(s_filterLogType, s_filterLogTypeTooltip)); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Editor/UI/Loggers/FileLoggerEditor.cs.meta b/Editor/UI/Loggers/FileLoggerEditor.cs.meta new file mode 100644 index 0000000..8fce131 --- /dev/null +++ b/Editor/UI/Loggers/FileLoggerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 04311af07d024dc0a0f5573bce71c791 +timeCreated: 1714884721 \ No newline at end of file diff --git a/Runtime/Autopilot.cs b/Runtime/Autopilot.cs index a6416ac..b2baeee 100644 --- a/Runtime/Autopilot.cs +++ b/Runtime/Autopilot.cs @@ -97,15 +97,9 @@ private void OnDestroy() // Clear event listeners. // When play mode is stopped by the user, onDestroy calls without TerminateAsync. - if (_dispatcher != null) - { - _dispatcher.Dispose(); - } - - if (_logMessageHandler != null) - { - _logMessageHandler.Dispose(); - } + _dispatcher?.Dispose(); + _logMessageHandler?.Dispose(); + _settings.logger?.Dispose(); } /// diff --git a/Runtime/Loggers/AbstractLogger.cs b/Runtime/Loggers/AbstractLogger.cs index e62ac12..11bbc81 100644 --- a/Runtime/Loggers/AbstractLogger.cs +++ b/Runtime/Loggers/AbstractLogger.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023-2024 DeNA Co., Ltd. // This software is released under the MIT License. +using System; using UnityEngine; namespace DeNA.Anjin.Loggers @@ -8,7 +9,7 @@ namespace DeNA.Anjin.Loggers /// /// Abstract logger settings used for autopilot. /// - public abstract class AbstractLogger : ScriptableObject + public abstract class AbstractLogger : ScriptableObject, IDisposable { #if UNITY_EDITOR /// @@ -21,5 +22,8 @@ public abstract class AbstractLogger : ScriptableObject /// Logger implementation used for autopilot. /// public abstract ILogger LoggerImpl { get; } + + /// + public abstract void Dispose(); } } diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLogger.cs index 36ee90b..e271546 100644 --- a/Runtime/Loggers/CompositeLogger.cs +++ b/Runtime/Loggers/CompositeLogger.cs @@ -22,6 +22,12 @@ public class CompositeLogger : AbstractLogger /// public override ILogger LoggerImpl => new Logger(new CompositeLogHandler(loggers)); + /// + public override void Dispose() + { + // Nothing to dispose. + } + private class CompositeLogHandler : ILogHandler { private readonly List _loggers; diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLogger.cs index 798b609..6d30d0f 100644 --- a/Runtime/Loggers/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLogger.cs @@ -19,5 +19,11 @@ public class ConsoleLogger : AbstractLogger /// public override ILogger LoggerImpl => new Logger(Debug.unityLogger.logHandler) { filterLogType = filterLogType }; + + /// + public override void Dispose() + { + // Nothing to dispose. + } } } diff --git a/Runtime/Loggers/FileLogger.cs b/Runtime/Loggers/FileLogger.cs new file mode 100644 index 0000000..28265c9 --- /dev/null +++ b/Runtime/Loggers/FileLogger.cs @@ -0,0 +1,94 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using System; +using System.IO; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace DeNA.Anjin.Loggers +{ + /// + /// Logger that output to a file. + /// + /// + /// If you want more functionality in the future, consider using the Unity Logging package (com.unity.logging) or ZLogger. + /// + /// + /// + [CreateAssetMenu(fileName = "New FileLogger", menuName = "Anjin/File Logger", order = 72)] + public class FileLogger : AbstractLogger + { + /// + /// Log output file path. + /// Note: relative path from the project root directory. When run on player, it will be the Application.persistentDataPath. + /// + public string outputPath; + + /// + /// To selective enable debug log message. + /// + public LogType filterLogType = LogType.Log; + + private FileLogHandler _handler; + private ILogger _logger; + + /// + public override ILogger LoggerImpl + { + get + { + if (_logger != null) + { + return _logger; + } + + var directory = Path.GetDirectoryName(outputPath); + if (directory != null && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + _handler = new FileLogHandler(outputPath); + _logger = new Logger(_handler) { filterLogType = filterLogType }; + return _logger; + } + } + + /// + public override void Dispose() + { + _handler?.Dispose(); + } + + private class FileLogHandler : ILogHandler, IDisposable + { + private readonly StreamWriter _writer; + + public FileLogHandler(string outputPath) + { + _writer = new StreamWriter(outputPath, false); + _writer.AutoFlush = true; + } + + public void LogFormat(LogType logType, Object context, string format, params object[] args) + { + _writer.WriteLine(format, args); + } + + public void LogException(Exception exception, Object context) + { + _writer.WriteLine("{0}", new object[] { exception.ToString() }); + if (exception.StackTrace != null) + { + _writer.WriteLine("{0}", new object[] { exception.StackTrace }); + } + } + + public void Dispose() + { + _writer?.Dispose(); + } + } + } +} diff --git a/Runtime/Loggers/FileLogger.cs.meta b/Runtime/Loggers/FileLogger.cs.meta new file mode 100644 index 0000000..42a2923 --- /dev/null +++ b/Runtime/Loggers/FileLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1efc191684b0450db1298fe7a4c4f1b2 +timeCreated: 1714882848 \ No newline at end of file diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs b/Tests/Runtime/Loggers/FileLoggerTest.cs new file mode 100644 index 0000000..c762a19 --- /dev/null +++ b/Tests/Runtime/Loggers/FileLoggerTest.cs @@ -0,0 +1,103 @@ +// Copyright (c) 2023-2024 DeNA Co., Ltd. +// This software is released under the MIT License. + +using System; +using System.IO; +using System.Threading.Tasks; +using NUnit.Framework; +using UnityEngine; + +namespace DeNA.Anjin.Loggers +{ + [TestFixture] + public class FileLoggerTest + { + private const string LogsDirectoryPath = "Logs/FileLoggerTest"; + + private static string GetOutputPath() + { + return Path.Combine(LogsDirectoryPath, $"{TestContext.CurrentContext.Test.Name}.log"); + } + + [Test, Order(0)] + public async Task GetLoggerImpl_DirectoryDoesNotExist_CreateDirectoryAndWriteToFile() + { + Directory.Delete(LogsDirectoryPath, true); + + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + + sut.LoggerImpl.Log(message); + sut.Dispose(); + await Task.Yield(); + + var actual = await File.ReadAllTextAsync(path); + Assert.That(actual, Is.EqualTo(message + Environment.NewLine)); + } + + [Test] + public async Task GetLoggerImpl_FileExists_OverwrittenToFile() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + await File.WriteAllTextAsync(path, "Existing content"); + + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + + sut.LoggerImpl.Log(message); + sut.Dispose(); + await Task.Yield(); + + var actual = await File.ReadAllTextAsync(path); + Assert.That(actual, Is.EqualTo(message + Environment.NewLine)); + } + + [Test] + public async Task LogFormat_WriteToFile() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + + sut.LoggerImpl.Log(message); + sut.LoggerImpl.Log(message); + sut.Dispose(); + await Task.Yield(); + + var actual = await File.ReadAllTextAsync(path); + Assert.That(actual, Is.EqualTo(message + Environment.NewLine + message + Environment.NewLine)); + } + + [Test] + public async Task LogException_WriteToFile() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + + Exception exception; + try + { + throw new Exception(message); + } + catch (Exception e) + { + exception = e; + } + + sut.LoggerImpl.LogException(exception); + sut.Dispose(); + await Task.Yield(); + + var actual = await File.ReadAllTextAsync(path); + Assert.That(actual, Does.StartWith( + "System.Exception: " + message + Environment.NewLine + + " at DeNA.Anjin.Loggers.FileLoggerTest.LogException_WriteToFile")); + } + } +} diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs.meta b/Tests/Runtime/Loggers/FileLoggerTest.cs.meta new file mode 100644 index 0000000..525063f --- /dev/null +++ b/Tests/Runtime/Loggers/FileLoggerTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4952c4b4da4641dd946e54fcabd98de8 +timeCreated: 1714886802 \ No newline at end of file diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs b/Tests/Runtime/TestDoubles/SpyLogger.cs index b9da316..5ca9c16 100644 --- a/Tests/Runtime/TestDoubles/SpyLogger.cs +++ b/Tests/Runtime/TestDoubles/SpyLogger.cs @@ -31,6 +31,11 @@ public override ILogger LoggerImpl public List Logs => _handler.Logs; + public override void Dispose() + { + // Nothing to dispose. + } + private class SpyLogHandler : ILogHandler { public readonly List Logs = new List(); From 5609908b9d80ebd27fa69cd08387df4d8b12aadb Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 19:13:57 +0900 Subject: [PATCH 06/14] Add log abort reason in TerminateAsync --- Runtime/Autopilot.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Runtime/Autopilot.cs b/Runtime/Autopilot.cs index b2baeee..6a656c7 100644 --- a/Runtime/Autopilot.cs +++ b/Runtime/Autopilot.cs @@ -119,6 +119,11 @@ public async UniTask TerminateAsync(ExitCode exitCode, string logString = null, JUnitReporter.Output(_state.settings.junitReportPath, (int)exitCode, logString, stackTrace, time); } + if (exitCode != ExitCode.Normally) + { + _logger.Log(LogType.Error, logString + Environment.NewLine + stackTrace); + } + Destroy(this.gameObject); if (_state.IsLaunchFromPlayMode) From e2891cf682b2db3af8b02610274a42d48cc836ef Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 19:48:59 +0900 Subject: [PATCH 07/14] Add output timestamp into FileLogger --- Editor/Localization/ja.po | 8 +++++ Editor/UI/Loggers/FileLoggerEditor.cs | 5 +++ Runtime/Loggers/FileLogger.cs | 44 +++++++++++++++++++++++-- Tests/Runtime/Loggers/FileLoggerTest.cs | 29 ++++++++++++++++ 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index b3fb296..26aca1a 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -481,3 +481,11 @@ msgstr "出力ファイルパス" # Output Path tooltip msgid "Log output file path. Specify relative path from project root or absolute path." msgstr "ログ出力ファイルのパス。プロジェクトルートからの相対パスまたは絶対パスを指定します" + +# Timestamp +msgid "Timestamp" +msgstr "タイムスタンプ" + +# Timestamp tooltip +msgid "Output timestamp to log entities" +msgstr "ログエンティティにタイムスタンプを出力します" diff --git a/Editor/UI/Loggers/FileLoggerEditor.cs b/Editor/UI/Loggers/FileLoggerEditor.cs index 450309a..1ddb792 100644 --- a/Editor/UI/Loggers/FileLoggerEditor.cs +++ b/Editor/UI/Loggers/FileLoggerEditor.cs @@ -22,6 +22,9 @@ public class FileLoggerEditor : UnityEditor.Editor private static readonly string s_filterLogType = L10n.Tr("Filter LogType"); private static readonly string s_filterLogTypeTooltip = L10n.Tr("To selective enable debug log message"); + private static readonly string s_timestamp = L10n.Tr("Timestamp"); + private static readonly string s_timestampTooltip = L10n.Tr("Output timestamp to log entities"); + /// public override void OnInspectorGUI() { @@ -33,6 +36,8 @@ public override void OnInspectorGUI() new GUIContent(s_outputPath, s_outputPathTooltip)); EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.filterLogType)), new GUIContent(s_filterLogType, s_filterLogTypeTooltip)); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.timestamp)), + new GUIContent(s_timestamp, s_timestampTooltip)); serializedObject.ApplyModifiedProperties(); } diff --git a/Runtime/Loggers/FileLogger.cs b/Runtime/Loggers/FileLogger.cs index 28265c9..2d095fc 100644 --- a/Runtime/Loggers/FileLogger.cs +++ b/Runtime/Loggers/FileLogger.cs @@ -30,6 +30,11 @@ public class FileLogger : AbstractLogger /// public LogType filterLogType = LogType.Log; + /// + /// Output timestamp to log entities. + /// + public bool timestamp = true; + private FileLogHandler _handler; private ILogger _logger; @@ -49,7 +54,7 @@ public override ILogger LoggerImpl Directory.CreateDirectory(directory); } - _handler = new FileLogHandler(outputPath); + _handler = new FileLogHandler(outputPath, timestamp); _logger = new Logger(_handler) { filterLogType = filterLogType }; return _logger; } @@ -61,24 +66,59 @@ public override void Dispose() _handler?.Dispose(); } + internal class TimestampCache + { + private string _timestampCache; + private int _timestampCacheFrame; + + public string GetTimestamp() + { + if (Time.frameCount != _timestampCacheFrame) + { + _timestampCache = DateTime.Now.ToString("[HH:mm:ss.fff] "); + _timestampCacheFrame = Time.frameCount; + } + + return _timestampCache; + } + } + private class FileLogHandler : ILogHandler, IDisposable { private readonly StreamWriter _writer; + private readonly bool _timestamp; + private readonly TimestampCache _timestampCache; - public FileLogHandler(string outputPath) + public FileLogHandler(string outputPath, bool timestamp) { _writer = new StreamWriter(outputPath, false); _writer.AutoFlush = true; + _timestamp = timestamp; + if (_timestamp) + { + _timestampCache = new TimestampCache(); + } } public void LogFormat(LogType logType, Object context, string format, params object[] args) { + if (_timestamp) + { + _writer.Write(_timestampCache.GetTimestamp()); + } + _writer.WriteLine(format, args); } public void LogException(Exception exception, Object context) { + if (_timestamp) + { + _writer.Write(_timestampCache.GetTimestamp()); + } + _writer.WriteLine("{0}", new object[] { exception.ToString() }); + if (exception.StackTrace != null) { _writer.WriteLine("{0}", new object[] { exception.StackTrace }); diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs b/Tests/Runtime/Loggers/FileLoggerTest.cs index c762a19..68965d1 100644 --- a/Tests/Runtime/Loggers/FileLoggerTest.cs +++ b/Tests/Runtime/Loggers/FileLoggerTest.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Cysharp.Threading.Tasks; using NUnit.Framework; using UnityEngine; @@ -28,6 +29,7 @@ public async Task GetLoggerImpl_DirectoryDoesNotExist_CreateDirectoryAndWriteToF var path = GetOutputPath(); var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; + sut.timestamp = false; sut.LoggerImpl.Log(message); sut.Dispose(); @@ -46,6 +48,7 @@ public async Task GetLoggerImpl_FileExists_OverwrittenToFile() var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; + sut.timestamp = false; sut.LoggerImpl.Log(message); sut.Dispose(); @@ -62,6 +65,7 @@ public async Task LogFormat_WriteToFile() var path = GetOutputPath(); var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; + sut.timestamp = false; sut.LoggerImpl.Log(message); sut.LoggerImpl.Log(message); @@ -79,6 +83,7 @@ public async Task LogException_WriteToFile() var path = GetOutputPath(); var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; + sut.timestamp = false; Exception exception; try @@ -99,5 +104,29 @@ public async Task LogException_WriteToFile() "System.Exception: " + message + Environment.NewLine + " at DeNA.Anjin.Loggers.FileLoggerTest.LogException_WriteToFile")); } + + [Test] + public async Task LogFormat_WithTimestamp_WriteTimestamp() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + sut.timestamp = true; + + sut.LoggerImpl.Log(message); + await UniTask.NextFrame(); + sut.LoggerImpl.Log(message); + sut.LoggerImpl.Log(message); // using cache + sut.Dispose(); + await Task.Yield(); + + var actual = await File.ReadAllTextAsync(path); + var timestampFormat = @"\[\d{2}:\d{2}:\d{2}\.\d{3}\] "; + var expected = timestampFormat + message + Environment.NewLine + + timestampFormat + message + Environment.NewLine + + timestampFormat + message + Environment.NewLine; + Assert.That(actual, Does.Match(expected)); + } } } From ed4e169ea47ce6e65d36727d22dc49bbe17f358f Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 21:27:29 +0900 Subject: [PATCH 08/14] Fix REAMDEs about Loggers and Reporters --- Editor/Localization/ja.po | 6 +- README.md | 112 ++++++++++++++++++++++++++----- README_ja.md | 107 +++++++++++++++++++++++++---- Runtime/Loggers/ConsoleLogger.cs | 1 + Runtime/Loggers/FileLogger.cs | 2 +- 5 files changed, 195 insertions(+), 33 deletions(-) diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index 26aca1a..e39a2b0 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -93,7 +93,7 @@ msgstr "ロガー" # logger tooltip msgid "Logger used for this autopilot settings. If omitted, Debug.unityLogger will be used as default." -msgstr "オートパイロットが使用するロガー。 省略時は Debug.unityLogger がデフォルトとして使用されます" +msgstr "オートパイロットが使用するロガー指定します。省略時は Debug.unityLogger がデフォルトとして使用されます" # reporter msgid "Reporter" @@ -101,7 +101,7 @@ msgstr "レポータ" # reporter tooltip msgid "Reporter that called when some errors occurred in target application" -msgstr "対象のアプリケーションで発生したエラーを通知するレポータ" +msgstr "対象のアプリケーションで発生したエラーを通知するレポータを指定します" # obsolete slack settings msgid "Slack settings will be moved to SlackReporter" @@ -484,7 +484,7 @@ msgstr "ログ出力ファイルのパス。プロジェクトルートからの # Timestamp msgid "Timestamp" -msgstr "タイムスタンプ" +msgstr "タイムスタンプを追加" # Timestamp tooltip msgid "Output timestamp to log entities" diff --git a/README.md b/README.md index 0106efe..3e97e81 100644 --- a/README.md +++ b/README.md @@ -121,17 +121,8 @@ This item can also be overridden from the commandline (see below).
Random Seed
Specify when you want to fix the seed given to the pseudo-random number generator (optional). This is a setting related to the pseudo-random number generator used by the autopilot. To fix the seed of the pseudo-random number generator in the game itself, it is necessary to implement this setting on the game title side.
Time Scale
Time.timeScale. Default is 1.0
JUnit Report Path
Specifies the JUnit format report file output path (optional). If there are zero errors and zero failures, the autopilot run is considered to have completed successfully.
-
Slack Token
Web API token used for Slack notifications (if omitted, no notifications will be sent)
-
Slack Channels
Channels to send Slack notifications (not notified if omitted. Multiple channels can be specified by separating them with commas)
- - -#### Slack Mention Settings - -Set the mentions to be given to Slack notifications. - -
-
Mention Sub Team IDs
Comma Separated Team IDs to Mention in Slack Notification Message
-
Add Here In Slack Message
Add @here to Slack notification message. Default is off
+
Logger
Logger used for this autopilot settings. If omitted, Debug.unityLogger will be used as default.
+
Reporter
Reporter that called when some errors occurred in target application
#### Error Handling Settings @@ -152,10 +143,29 @@ Set up a filter to catch abnormal log messages and notify Slack. Whether you use the built-in Agent or implement custom Agent, you must create an instance (.asset file) of it in the Unity editor. Instances are created by right-clicking in the Project window of the Unity editor to open the context menu, then selecting -**Create > Anjin > Agent name**. +**Create > Anjin > Agent type name**. Select the generated file, Agent-specific settings are displayed in the inspector and can be customized. -You can prepare multiple Agents with different settings for the same Agent and use them in different Scenes. +You can prepare multiple Agents with different settings for the same Agent type and use them in different Scenes. + + +### Generate and configure the Logger setting file (.asset) + +Logger instances are created by right-clicking in the Project window of the Unity editor to open the context menu, then selecting +**Create > Anjin > Logger type name**. + +Select the generated file, Logger-specific settings are displayed in the inspector and can be customized. +You can prepare multiple Loggers with different settings for the same Logger type. + + +### Generate and configure the Reporter setting file (.asset) + +Reporter instances are created by right-clicking in the Project window of the Unity editor to open the context menu, then selecting +**Create > Anjin > Reporter type name**. + +Select the generated file, Reporter-specific settings are displayed in the inspector and can be customized. +You can prepare multiple Reporters with different settings for the same Reporter type. + ## Run autopilot @@ -214,8 +224,6 @@ For details on each argument, see the entry of the same name in the "Generate an
RANDOM_SEED
Specifies when you want to fix the seed given to the pseudo-random number generator
TIME_SCALE
Specifies the Time.timeScale. Default is 1.0
JUNIT_REPORT_PATH
Specifies the JUnit-style report file output path
-
SLACK_TOKEN
Web API token used for Slack notifications
-
SLACK_CHANNELS
Channels to send Slack notifications
In both cases, the key should be prefixed with `-` and specified as `-LIFESPAN_SEC 60`. @@ -224,7 +232,7 @@ In both cases, the key should be prefixed with `-` and specified as `-LIFESPAN_S ## Built-in Agents -The following Agents are provided. These can be used as they are, or project-specific Agents can be implemented and used. +The following Agent types are provided. These can be used as they are, or project-specific Agents can be implemented and used. ### UGUIMonkeyAgent @@ -370,6 +378,78 @@ This can be accomplished with `ParallelCompositeAgent`, but it is easier to set +## Built-in Logger + +The following Logger types are provided. These can be used as they are, or project-specific Loggers can be implemented and used. + + +### Composite Logger + +A Logger that delegates to multiple loggers. + +The instance of this Logger (.asset file) can have the following settings. + +
+
Loggers
A list of Logger to delegates
+
+ + +### Console Logger + +A Logger that outputs to a console. + +The instance of this Logger (.asset file) can have the following settings. + +
+
Filter LogType
To selective enable debug log message
+
+ + +### File Logger + +A Logger that outputs to a specified file. + +The instance of this Logger (.asset file) can have the following settings. + +
+
Output File Path
Log output file path. Specify relative path from project root or absolute path. When run on player, it will be the Application.persistentDataPath.
+
Filter LogType
To selective enable debug log message
+
Timestamp
Output timestamp to log entities
+
+ + + +## Built-in Reporter + +The following Reporter types are provided. These can be used as they are, or project-specific Reporters can be implemented and used. + + +### Composite Reporter + +A Reporter that delegates to multiple Reporters. + +The instance of this Reporter (.asset file) can have the following settings. + +
+
Reporters
A list of Reporter to delegates
+
+ + +### Slack Reporter + +A Reporter that post report to Slack. + +The instance of this Reporter (.asset file) can have the following settings. + +
+
Slack Token
Web API token used for Slack notifications (if omitted, no notifications will be sent)
+
Slack Channels
Channels to send Slack notifications (not notified if omitted. Multiple channels can be specified by separating them with commas)
+
Mention Sub Team IDs
Comma Separated Team IDs to Mention in Slack Notification Message
+
Add Here In Slack Message
Add @here to Slack notification message. Default is off
+
+ + + ## Implementation of game title-specific code Game title specific Agents and initialization code must be avoided in the release build. diff --git a/README_ja.md b/README_ja.md index f8af08d..bb38a33 100644 --- a/README_ja.md +++ b/README_ja.md @@ -118,17 +118,8 @@ v1.0.0時点では `EmergencyExitAgent` の使用を想定しています。
Random Seed
疑似乱数発生器に与えるシードを固定したいときに指定します(省略可)。なお、これはオートパイロットの使用する疑似乱数発生器に関する設定であり、ゲーム本体の疑似乱数発生器シードを固定するにはタイトル側での実装が必要です。
Time Scale
Time.timeScaleを指定します。デフォルトは1.0
JUnit Report Path
JUnit形式のレポートファイル出力パスを指定します(省略可)。オートパイロット実行の成否は、Unityエディターの終了コードでなくこのファイルを見て判断するのが確実です。errors, failuresともに0件であれば正常終了と判断できます。
-
Slack Token
Slack通知に使用するWeb APIトークン(省略時は通知されない)
-
Slack Channels
Slack通知を送るチャンネル(省略時は通知されない。カンマ区切りで複数指定対応)
- - -#### Slackメンション設定 - -Slack通知に付与するメンションを設定します。 - -
-
Mention Sub Team IDs
Slack通知メッセージでメンションするチームのIDをカンマ区切りで指定します
-
Add Here In Slack Message
Slack通知メッセージに@hereを付けます。デフォルトはoff
+
Logger
オートパイロットが使用するロガー指定します。省略時は Debug.unityLogger がデフォルトとして使用されます
+
Reporter
対象のアプリケーションで発生したエラーを通知するレポータを指定します
#### エラーハンドリング設定 @@ -156,6 +147,26 @@ Slack通知に付与するメンションを設定します。 同じAgentでも設定の違うものを複数用意して、Sceneによって使い分けることができます。 +### ロガー設定ファイル(.asset)の生成 + +ロガーインスタンスは、UnityエディタのProjectウィンドウで右クリックしてコンテキストメニューを開き、 +**Create > Anjin > Logger名** +を選択すると生成できます。ファイル名は任意です。 + +生成したファイルを選択すると、インスペクタにロガー固有の設定項目が表示され、カスタマイズが可能です。 +同じロガーでも設定の違うものを複数用意して使い分けることができます。 + + +### レポータ設定ファイル(.asset)の生成 + +レポータインスタンスは、UnityエディタのProjectウィンドウで右クリックしてコンテキストメニューを開き、 +**Create > Anjin > Reporter名** +を選択すると生成できます。ファイル名は任意です。 + +生成したファイルを選択すると、インスペクタにレポータ固有の設定項目が表示され、カスタマイズが可能です。 +同じレポータでも設定の違うものを複数用意して使い分けることができます。 + + ## 実行方法 @@ -215,8 +226,6 @@ $(UNITY) \
RANDOM_SEED
疑似乱数発生器に与えるシードを固定したいときに指定します
TIME_SCALE
Time.timeScaleを指定します。デフォルトは1.0
JUNIT_REPORT_PATH
JUnit形式のレポートファイル出力パスを指定します
-
SLACK_TOKEN
Slack通知に使用するWeb APIトークン
-
SLACK_CHANNELS
Slack通知を送るチャンネル
いずれも、キーの先頭に`-`を付けて`-LIFESPAN_SEC 60`のように指定してください。 @@ -373,6 +382,78 @@ SerialCompositeAgentと組み合わせることで、シナリオを何周もし +## ビルトイン ロガー + +以下のロガータイプが用意されています。これらをそのまま使用することも、プロジェクト独自のロガーを実装して使用することも可能です。 + + +### Composite Logger + +複数のロガーを登録し、そのすべてにログ出力を委譲するロガーです。 + +このロガーのインスタンス(.assetファイル)には以下を設定できます。 + +
+
Loggers
ログ出力を委譲するLoggerのリスト
+
+ + +### Console Logger + +ログをコンソールに出力するロガーです。 + +このロガーのインスタンス(.assetファイル)には以下を設定できます。 + +
+
フィルタリングLogType
選択したLogType以上のログ出力のみを有効にします
+
+ + +### File Logger + +ログを指定ファイルに出力するロガーです。 + +このロガーのインスタンス(.assetファイル)には以下を設定できます。 + +
+
出力ファイルパス
ログ出力ファイルのパス。プロジェクトルートからの相対パスまたは絶対パスを指定します。プレイヤー実行では相対パスの起点は Application.persistentDataPath になります。
+
フィルタリングLogType
選択したLogType以上のログ出力のみを有効にします
+
タイムスタンプを出力
ログエンティティにタイムスタンプを出力します
+
+ + + +## ビルトイン レポータ + +以下のレポータタイプが用意されています。これらをそのまま使用することも、プロジェクト独自のレポータを実装して使用することも可能です。 + + +### Composite Reporter + +複数のレポータを登録し、そのすべてにレポート送信を委譲するレポータです。 + +このレポータのインスタンス(.assetファイル)には以下を設定できます。 + +
+
Reporters
レポート送信を委譲するReporterのリスト
+
+ + +### Slack Reporter + +Slackにレポート送信するレポータです。 + +このレポータのインスタンス(.assetファイル)には以下を設定できます。 + +
+
Slack Token
Slack通知に使用するWeb APIトークン(省略時は通知されない)
+
Slack Channels
Slack通知を送るチャンネル(省略時は通知されない。カンマ区切りで複数指定対応)
+
Mention Sub Team IDs
Slack通知メッセージでメンションするチームのIDをカンマ区切りで指定します
+
Add Here In Slack Message
Slack通知メッセージに@hereを付けます。デフォルトはoff
+
+ + + ## ゲームタイトル独自処理の実装 ゲームタイトル固有のAgent等を実装する場合、リリースビルドへの混入を避けるため、専用のアセンブリに分けることをおすすめします。 diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLogger.cs index 6d30d0f..abf7232 100644 --- a/Runtime/Loggers/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLogger.cs @@ -6,6 +6,7 @@ namespace DeNA.Anjin.Loggers { /// + /// A Logger that outputs to a console. /// Logger using Debug.unityLogger /// [CreateAssetMenu(fileName = "New ConsoleLogger", menuName = "Anjin/Console Logger", order = 71)] diff --git a/Runtime/Loggers/FileLogger.cs b/Runtime/Loggers/FileLogger.cs index 2d095fc..77db78b 100644 --- a/Runtime/Loggers/FileLogger.cs +++ b/Runtime/Loggers/FileLogger.cs @@ -9,7 +9,7 @@ namespace DeNA.Anjin.Loggers { /// - /// Logger that output to a file. + /// A Logger that outputs to a specified file. /// /// /// If you want more functionality in the future, consider using the Unity Logging package (com.unity.logging) or ZLogger. From 6220ae829ad2ac8164bc045306f10d0550f0113b Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 21:36:34 +0900 Subject: [PATCH 09/14] Refactor loggers --- Runtime/Loggers/CompositeLogger.cs | 23 +++++++++++++++++++++-- Runtime/Loggers/ConsoleLogger.cs | 17 +++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLogger.cs index e271546..5fc7122 100644 --- a/Runtime/Loggers/CompositeLogger.cs +++ b/Runtime/Loggers/CompositeLogger.cs @@ -19,13 +19,32 @@ public class CompositeLogger : AbstractLogger ///
public List loggers = new List(); + private ILogHandler _handler; + private ILogger _logger; + /// - public override ILogger LoggerImpl => new Logger(new CompositeLogHandler(loggers)); + public override ILogger LoggerImpl + { + get + { + if (_logger != null) + { + return _logger; + } + + _handler = new CompositeLogHandler(loggers); + _logger = new Logger(_handler); + return _logger; + } + } /// public override void Dispose() { - // Nothing to dispose. + foreach (var logger in loggers) + { + logger.Dispose(); + } } private class CompositeLogHandler : ILogHandler diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLogger.cs index abf7232..ea18d8c 100644 --- a/Runtime/Loggers/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLogger.cs @@ -17,9 +17,22 @@ public class ConsoleLogger : AbstractLogger /// public LogType filterLogType = LogType.Log; + private ILogger _logger; + /// - public override ILogger LoggerImpl => - new Logger(Debug.unityLogger.logHandler) { filterLogType = filterLogType }; + public override ILogger LoggerImpl + { + get + { + if (_logger != null) + { + return _logger; + } + + _logger = new Logger(Debug.unityLogger.logHandler) { filterLogType = filterLogType }; + return _logger; + } + } /// public override void Dispose() From 32f260ec02f0cce06a2fff1334b523d969581151 Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sun, 5 May 2024 21:56:02 +0900 Subject: [PATCH 10/14] Fix tests --- Tests/Runtime/Loggers/FileLoggerTest.cs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs b/Tests/Runtime/Loggers/FileLoggerTest.cs index 68965d1..52f7e3e 100644 --- a/Tests/Runtime/Loggers/FileLoggerTest.cs +++ b/Tests/Runtime/Loggers/FileLoggerTest.cs @@ -8,6 +8,8 @@ using NUnit.Framework; using UnityEngine; +// ReSharper disable MethodHasAsyncOverload + namespace DeNA.Anjin.Loggers { [TestFixture] @@ -23,7 +25,10 @@ private static string GetOutputPath() [Test, Order(0)] public async Task GetLoggerImpl_DirectoryDoesNotExist_CreateDirectoryAndWriteToFile() { - Directory.Delete(LogsDirectoryPath, true); + if (Directory.Exists(LogsDirectoryPath)) + { + Directory.Delete(LogsDirectoryPath, true); + } var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); @@ -35,7 +40,7 @@ public async Task GetLoggerImpl_DirectoryDoesNotExist_CreateDirectoryAndWriteToF sut.Dispose(); await Task.Yield(); - var actual = await File.ReadAllTextAsync(path); + var actual = File.ReadAllText(path); Assert.That(actual, Is.EqualTo(message + Environment.NewLine)); } @@ -44,7 +49,7 @@ public async Task GetLoggerImpl_FileExists_OverwrittenToFile() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - await File.WriteAllTextAsync(path, "Existing content"); + File.WriteAllText(path, "Existing content"); var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; @@ -54,7 +59,7 @@ public async Task GetLoggerImpl_FileExists_OverwrittenToFile() sut.Dispose(); await Task.Yield(); - var actual = await File.ReadAllTextAsync(path); + var actual = File.ReadAllText(path); Assert.That(actual, Is.EqualTo(message + Environment.NewLine)); } @@ -72,7 +77,7 @@ public async Task LogFormat_WriteToFile() sut.Dispose(); await Task.Yield(); - var actual = await File.ReadAllTextAsync(path); + var actual = File.ReadAllText(path); Assert.That(actual, Is.EqualTo(message + Environment.NewLine + message + Environment.NewLine)); } @@ -99,10 +104,10 @@ public async Task LogException_WriteToFile() sut.Dispose(); await Task.Yield(); - var actual = await File.ReadAllTextAsync(path); + var actual = File.ReadAllText(path); Assert.That(actual, Does.StartWith( "System.Exception: " + message + Environment.NewLine + - " at DeNA.Anjin.Loggers.FileLoggerTest.LogException_WriteToFile")); + " at DeNA.Anjin.Loggers.FileLoggerTest")); } [Test] @@ -121,7 +126,7 @@ public async Task LogFormat_WithTimestamp_WriteTimestamp() sut.Dispose(); await Task.Yield(); - var actual = await File.ReadAllTextAsync(path); + var actual = File.ReadAllText(path); var timestampFormat = @"\[\d{2}:\d{2}:\d{2}\.\d{3}\] "; var expected = timestampFormat + message + Environment.NewLine + timestampFormat + message + Environment.NewLine + From ff5be6ba5df15b153344ef0b661ed353e56dac35 Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Mon, 6 May 2024 12:15:31 +0900 Subject: [PATCH 11/14] Fix bugs --- Runtime/Loggers/CompositeLogger.cs | 29 ++-- Runtime/Loggers/FileLogger.cs | 21 ++- Tests/Runtime/Loggers/CompositeLoggerTest.cs | 142 ++++++++++++++++++- Tests/Runtime/Loggers/FileLoggerTest.cs | 103 +++++++++++--- Tests/Runtime/TestDoubles/SpyLogger.cs | 4 +- 5 files changed, 255 insertions(+), 44 deletions(-) diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLogger.cs index 5fc7122..857abfa 100644 --- a/Runtime/Loggers/CompositeLogger.cs +++ b/Runtime/Loggers/CompositeLogger.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using Object = UnityEngine.Object; @@ -32,7 +33,7 @@ public override ILogger LoggerImpl return _logger; } - _handler = new CompositeLogHandler(loggers); + _handler = new CompositeLogHandler(loggers, this); _logger = new Logger(_handler); return _logger; } @@ -41,36 +42,46 @@ public override ILogger LoggerImpl /// public override void Dispose() { - foreach (var logger in loggers) - { - logger.Dispose(); - } + ((CompositeLogHandler)LoggerImpl.logHandler).Dispose(); } - private class CompositeLogHandler : ILogHandler + private class CompositeLogHandler : ILogHandler, IDisposable { private readonly List _loggers; + private readonly AbstractLogger _owner; - public CompositeLogHandler(List loggers) + public CompositeLogHandler(List loggers, AbstractLogger owner) { _loggers = loggers; + _owner = owner; } + /// public void LogFormat(LogType logType, Object context, string format, params object[] args) { - foreach (var logger in _loggers) + foreach (var logger in _loggers.Where(logger => logger != null && logger != _owner)) { logger.LoggerImpl.LogFormat(logType, context, format, args); } } + /// public void LogException(Exception exception, Object context) { - foreach (var logger in _loggers) + foreach (var logger in _loggers.Where(logger => logger != null && logger != _owner)) { logger.LoggerImpl.LogException(exception, context); } } + + /// + public void Dispose() + { + foreach (var logger in _loggers.Where(logger => logger != null && logger != _owner)) + { + logger.Dispose(); + } + } } } } diff --git a/Runtime/Loggers/FileLogger.cs b/Runtime/Loggers/FileLogger.cs index 77db78b..be6d8b4 100644 --- a/Runtime/Loggers/FileLogger.cs +++ b/Runtime/Loggers/FileLogger.cs @@ -66,14 +66,14 @@ public override void Dispose() _handler?.Dispose(); } - internal class TimestampCache + private class TimestampCache { private string _timestampCache; private int _timestampCacheFrame; public string GetTimestamp() { - if (Time.frameCount != _timestampCacheFrame) + if (_timestampCacheFrame != Time.frameCount) { _timestampCache = DateTime.Now.ToString("[HH:mm:ss.fff] "); _timestampCacheFrame = Time.frameCount; @@ -88,6 +88,7 @@ private class FileLogHandler : ILogHandler, IDisposable private readonly StreamWriter _writer; private readonly bool _timestamp; private readonly TimestampCache _timestampCache; + private bool _disposed; public FileLogHandler(string outputPath, bool timestamp) { @@ -102,6 +103,11 @@ public FileLogHandler(string outputPath, bool timestamp) public void LogFormat(LogType logType, Object context, string format, params object[] args) { + if (_disposed) + { + return; + } + if (_timestamp) { _writer.Write(_timestampCache.GetTimestamp()); @@ -112,22 +118,23 @@ public void LogFormat(LogType logType, Object context, string format, params obj public void LogException(Exception exception, Object context) { + if (_disposed) + { + return; + } + if (_timestamp) { _writer.Write(_timestampCache.GetTimestamp()); } _writer.WriteLine("{0}", new object[] { exception.ToString() }); - - if (exception.StackTrace != null) - { - _writer.WriteLine("{0}", new object[] { exception.StackTrace }); - } } public void Dispose() { _writer?.Dispose(); + _disposed = true; } } } diff --git a/Tests/Runtime/Loggers/CompositeLoggerTest.cs b/Tests/Runtime/Loggers/CompositeLoggerTest.cs index c1a42c5..4c0dc23 100644 --- a/Tests/Runtime/Loggers/CompositeLoggerTest.cs +++ b/Tests/Runtime/Loggers/CompositeLoggerTest.cs @@ -1,30 +1,158 @@ // Copyright (c) 2023-2024 DeNA Co., Ltd. // This software is released under the MIT License. +using System; +using DeNA.Anjin.TestDoubles; using NUnit.Framework; using UnityEngine; -using UnityEngine.TestTools; namespace DeNA.Anjin.Loggers { [TestFixture] public class CompositeLoggerTest { + private static Exception CreateExceptionWithStacktrace(string message) + { + try + { + throw new ApplicationException(message); + } + catch (Exception e) + { + return e; + } + } + [Test] - public void CompositeTwoLoggers_OutputBothLoggers() + public void LogFormat_CompositeMultipleLoggers_OutputBothLoggers() { var message = TestContext.CurrentContext.Test.Name; - var logger1 = ScriptableObject.CreateInstance(); - var logger2 = ScriptableObject.CreateInstance(); + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(logger1); sut.loggers.Add(logger2); sut.LoggerImpl.Log(message); - LogAssert.Expect(LogType.Log, message); - LogAssert.Expect(LogType.Log, message); // log output twice - LogAssert.NoUnexpectedReceived(); + Assert.That(logger1.Logs, Does.Contain(message)); + Assert.That(logger2.Logs, Does.Contain(message)); + } + + [Test] + public void LogFormat_LoggersIncludesNull_IgnoreNull() + { + var message = TestContext.CurrentContext.Test.Name; + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(null); + sut.loggers.Add(logger2); + + sut.LoggerImpl.Log(message); + + Assert.That(logger2.Logs, Does.Contain(message)); + } + + [Test] + public void LogFormat_NestingLogger_IgnoreNested() + { + var message = TestContext.CurrentContext.Test.Name; + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(sut); // nesting + sut.loggers.Add(logger2); + + sut.LoggerImpl.Log(message); + + Assert.That(logger2.Logs, Does.Contain(message)); + } + + [Test] + public void LogException_CompositeMultipleLoggers_OutputBothLoggers() + { + var message = TestContext.CurrentContext.Test.Name; + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(logger1); + sut.loggers.Add(logger2); + + var exception = CreateExceptionWithStacktrace(message); + sut.LoggerImpl.LogException(exception); + + Assert.That(logger1.Logs, Does.Contain(exception.ToString())); + Assert.That(logger2.Logs, Does.Contain(exception.ToString())); + } + + [Test] + public void LogException_LoggersIncludesNull_IgnoreNull() + { + var message = TestContext.CurrentContext.Test.Name; + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(null); + sut.loggers.Add(logger2); + + var exception = CreateExceptionWithStacktrace(message); + sut.LoggerImpl.LogException(exception); + + Assert.That(logger2.Logs, Does.Contain(exception.ToString())); + } + + [Test] + public void LogException_NestingLogger_IgnoreNested() + { + var message = TestContext.CurrentContext.Test.Name; + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(sut); // nesting + sut.loggers.Add(logger2); + + var exception = CreateExceptionWithStacktrace(message); + sut.LoggerImpl.LogException(exception); + + Assert.That(logger2.Logs, Does.Contain(exception.ToString())); + } + + [Test] + public void Dispose_CompositeMultipleLoggers_DisposeAllLoggers() + { + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(logger1); + sut.loggers.Add(logger2); + + sut.Dispose(); + + Assert.That(logger1.Disposed, Is.True); + Assert.That(logger2.Disposed, Is.True); + } + + [Test] + public void Dispose_LoggersIncludesNull_IgnoreNull() + { + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(null); + sut.loggers.Add(logger2); + + sut.Dispose(); + + Assert.That(logger2.Disposed, Is.True); + } + + [Test] + public void Dispose_NestingLogger_IgnoreNested() + { + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggers.Add(sut); // nesting + sut.loggers.Add(logger2); + + sut.Dispose(); + + Assert.That(logger2.Disposed, Is.True); } } } diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs b/Tests/Runtime/Loggers/FileLoggerTest.cs index 52f7e3e..be6cccb 100644 --- a/Tests/Runtime/Loggers/FileLoggerTest.cs +++ b/Tests/Runtime/Loggers/FileLoggerTest.cs @@ -16,12 +16,25 @@ namespace DeNA.Anjin.Loggers public class FileLoggerTest { private const string LogsDirectoryPath = "Logs/FileLoggerTest"; + private const string TimestampRegex = @"\[\d{2}:\d{2}:\d{2}\.\d{3}\] "; private static string GetOutputPath() { return Path.Combine(LogsDirectoryPath, $"{TestContext.CurrentContext.Test.Name}.log"); } + private static Exception CreateExceptionWithStacktrace(string message) + { + try + { + throw new ApplicationException(message); + } + catch (Exception e) + { + return e; + } + } + [Test, Order(0)] public async Task GetLoggerImpl_DirectoryDoesNotExist_CreateDirectoryAndWriteToFile() { @@ -82,7 +95,7 @@ public async Task LogFormat_WriteToFile() } [Test] - public async Task LogException_WriteToFile() + public async Task LogFormat_Disposed_NotWriteToFile() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); @@ -90,24 +103,16 @@ public async Task LogException_WriteToFile() sut.outputPath = path; sut.timestamp = false; - Exception exception; - try - { - throw new Exception(message); - } - catch (Exception e) - { - exception = e; - } - - sut.LoggerImpl.LogException(exception); + sut.LoggerImpl.Log(message); + sut.LoggerImpl.Log(message); sut.Dispose(); await Task.Yield(); + sut.LoggerImpl.Log(message); // write after disposed + await Task.Yield(); + var actual = File.ReadAllText(path); - Assert.That(actual, Does.StartWith( - "System.Exception: " + message + Environment.NewLine + - " at DeNA.Anjin.Loggers.FileLoggerTest")); + Assert.That(actual, Is.EqualTo(message + Environment.NewLine + message + Environment.NewLine)); } [Test] @@ -127,11 +132,69 @@ public async Task LogFormat_WithTimestamp_WriteTimestamp() await Task.Yield(); var actual = File.ReadAllText(path); - var timestampFormat = @"\[\d{2}:\d{2}:\d{2}\.\d{3}\] "; - var expected = timestampFormat + message + Environment.NewLine + - timestampFormat + message + Environment.NewLine + - timestampFormat + message + Environment.NewLine; - Assert.That(actual, Does.Match(expected)); + Assert.That(actual, Does.Match( + "^" + + TimestampRegex + message + Environment.NewLine + + TimestampRegex + message + Environment.NewLine + + TimestampRegex + message + Environment.NewLine + + "$")); + } + + [Test] + public async Task LogException_WriteToFile() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + sut.timestamp = false; + + var exception = CreateExceptionWithStacktrace(message); + sut.LoggerImpl.LogException(exception); + sut.Dispose(); + await Task.Yield(); + + var actual = File.ReadAllText(path); + Assert.That(actual, Is.EqualTo(exception + Environment.NewLine)); + } + + [Test] + public async Task LogException_Disposed_NotWriteToFile() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + sut.timestamp = false; + + var exception = CreateExceptionWithStacktrace(message); + sut.LoggerImpl.LogException(exception); + sut.Dispose(); + await Task.Yield(); + + sut.LoggerImpl.LogException(exception); // write after disposed + await Task.Yield(); + + var actual = File.ReadAllText(path); + Assert.That(actual, Is.EqualTo(exception + Environment.NewLine)); + } + + [Test] + public async Task LogException_WithTimestamp_WriteTimestamp() + { + var message = TestContext.CurrentContext.Test.Name; + var path = GetOutputPath(); + var sut = ScriptableObject.CreateInstance(); + sut.outputPath = path; + sut.timestamp = true; + + var exception = CreateExceptionWithStacktrace(message); + sut.LoggerImpl.LogException(exception); + sut.Dispose(); + await Task.Yield(); + + var actual = File.ReadAllText(path); + Assert.That(actual, Does.Match("^" + TimestampRegex + ".*")); } } } diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs b/Tests/Runtime/TestDoubles/SpyLogger.cs index 5ca9c16..c541c29 100644 --- a/Tests/Runtime/TestDoubles/SpyLogger.cs +++ b/Tests/Runtime/TestDoubles/SpyLogger.cs @@ -11,6 +11,8 @@ namespace DeNA.Anjin.TestDoubles { public class SpyLogger : AbstractLogger { + public bool Disposed { get; private set; } + private SpyLogHandler _handler; private ILogger _logger; @@ -33,7 +35,7 @@ public override ILogger LoggerImpl public override void Dispose() { - // Nothing to dispose. + Disposed = true; } private class SpyLogHandler : ILogHandler From 7f3213e78789e214afa32ff4516512548a2ef787 Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Fri, 10 May 2024 06:12:44 +0900 Subject: [PATCH 12/14] Update Runtime/Loggers/CompositeLogger.cs Co-authored-by: Yuki Kokubun --- Runtime/Loggers/CompositeLogger.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLogger.cs index 857abfa..96cd269 100644 --- a/Runtime/Loggers/CompositeLogger.cs +++ b/Runtime/Loggers/CompositeLogger.cs @@ -20,8 +20,8 @@ public class CompositeLogger : AbstractLogger /// public List loggers = new List(); - private ILogHandler _handler; - private ILogger _logger; + private CompositeLogHandler _handler; + private Logger _logger; /// public override ILogger LoggerImpl From fb85140c17cd7c47843a8875a719b563e17d965e Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sat, 11 May 2024 12:15:39 +0900 Subject: [PATCH 13/14] Fix tests --- Runtime/Loggers/CompositeLogger.cs | 2 +- Tests/Runtime/Loggers/CompositeLoggerTest.cs | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLogger.cs index 96cd269..db7983b 100644 --- a/Runtime/Loggers/CompositeLogger.cs +++ b/Runtime/Loggers/CompositeLogger.cs @@ -42,7 +42,7 @@ public override ILogger LoggerImpl /// public override void Dispose() { - ((CompositeLogHandler)LoggerImpl.logHandler).Dispose(); + _handler?.Dispose(); } private class CompositeLogHandler : ILogHandler, IDisposable diff --git a/Tests/Runtime/Loggers/CompositeLoggerTest.cs b/Tests/Runtime/Loggers/CompositeLoggerTest.cs index 4c0dc23..7f2dbe9 100644 --- a/Tests/Runtime/Loggers/CompositeLoggerTest.cs +++ b/Tests/Runtime/Loggers/CompositeLoggerTest.cs @@ -26,13 +26,13 @@ private static Exception CreateExceptionWithStacktrace(string message) [Test] public void LogFormat_CompositeMultipleLoggers_OutputBothLoggers() { - var message = TestContext.CurrentContext.Test.Name; var logger1 = ScriptableObject.CreateInstance(); var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(logger1); sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; sut.LoggerImpl.Log(message); Assert.That(logger1.Logs, Does.Contain(message)); @@ -42,12 +42,12 @@ public void LogFormat_CompositeMultipleLoggers_OutputBothLoggers() [Test] public void LogFormat_LoggersIncludesNull_IgnoreNull() { - var message = TestContext.CurrentContext.Test.Name; var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(null); sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; sut.LoggerImpl.Log(message); Assert.That(logger2.Logs, Does.Contain(message)); @@ -56,12 +56,12 @@ public void LogFormat_LoggersIncludesNull_IgnoreNull() [Test] public void LogFormat_NestingLogger_IgnoreNested() { - var message = TestContext.CurrentContext.Test.Name; var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(sut); // nesting sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; sut.LoggerImpl.Log(message); Assert.That(logger2.Logs, Does.Contain(message)); @@ -70,13 +70,13 @@ public void LogFormat_NestingLogger_IgnoreNested() [Test] public void LogException_CompositeMultipleLoggers_OutputBothLoggers() { - var message = TestContext.CurrentContext.Test.Name; var logger1 = ScriptableObject.CreateInstance(); var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(logger1); sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; var exception = CreateExceptionWithStacktrace(message); sut.LoggerImpl.LogException(exception); @@ -87,12 +87,12 @@ public void LogException_CompositeMultipleLoggers_OutputBothLoggers() [Test] public void LogException_LoggersIncludesNull_IgnoreNull() { - var message = TestContext.CurrentContext.Test.Name; var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(null); sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; var exception = CreateExceptionWithStacktrace(message); sut.LoggerImpl.LogException(exception); @@ -102,12 +102,12 @@ public void LogException_LoggersIncludesNull_IgnoreNull() [Test] public void LogException_NestingLogger_IgnoreNested() { - var message = TestContext.CurrentContext.Test.Name; var logger2 = ScriptableObject.CreateInstance(); var sut = ScriptableObject.CreateInstance(); sut.loggers.Add(sut); // nesting sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; var exception = CreateExceptionWithStacktrace(message); sut.LoggerImpl.LogException(exception); @@ -123,6 +123,8 @@ public void Dispose_CompositeMultipleLoggers_DisposeAllLoggers() sut.loggers.Add(logger1); sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; + sut.LoggerImpl.Log(message); sut.Dispose(); Assert.That(logger1.Disposed, Is.True); @@ -137,6 +139,8 @@ public void Dispose_LoggersIncludesNull_IgnoreNull() sut.loggers.Add(null); sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; + sut.LoggerImpl.Log(message); sut.Dispose(); Assert.That(logger2.Disposed, Is.True); @@ -150,6 +154,8 @@ public void Dispose_NestingLogger_IgnoreNested() sut.loggers.Add(sut); // nesting sut.loggers.Add(logger2); + var message = TestContext.CurrentContext.Test.Name; + sut.LoggerImpl.Log(message); sut.Dispose(); Assert.That(logger2.Disposed, Is.True); From b08ff4c0615c839250babfc942a9ef791ca975cc Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Sat, 11 May 2024 12:20:08 +0900 Subject: [PATCH 14/14] Rename Logger to LoggerAsset, LoggerImpl to Logger --- Editor/UI/Loggers/CompositeLoggerEditor.cs | 6 +- Editor/UI/Loggers/ConsoleLoggerEditor.cs | 6 +- Editor/UI/Loggers/FileLoggerEditor.cs | 10 +- Editor/UI/Settings/AutopilotSettingsEditor.cs | 2 +- Runtime/Autopilot.cs | 14 +-- ...stractLogger.cs => AbstractLoggerAsset.cs} | 4 +- ...er.cs.meta => AbstractLoggerAsset.cs.meta} | 0 ...ositeLogger.cs => CompositeLoggerAsset.cs} | 28 +++--- ...r.cs.meta => CompositeLoggerAsset.cs.meta} | 0 ...ConsoleLogger.cs => ConsoleLoggerAsset.cs} | 4 +- ...ger.cs.meta => ConsoleLoggerAsset.cs.meta} | 0 .../{FileLogger.cs => FileLoggerAsset.cs} | 4 +- ...Logger.cs.meta => FileLoggerAsset.cs.meta} | 0 Runtime/Settings/AutopilotSettings.cs | 2 +- Tests/Runtime/AutopilotTest.cs | 4 +- ...gerTest.cs => CompositeLoggerAssetTest.cs} | 98 +++++++++---------- ....meta => CompositeLoggerAssetTest.cs.meta} | 0 ...oggerTest.cs => ConsoleLoggerAssetTest.cs} | 12 +-- ...cs.meta => ConsoleLoggerAssetTest.cs.meta} | 0 ...leLoggerTest.cs => FileLoggerAssetTest.cs} | 46 ++++----- ...st.cs.meta => FileLoggerAssetTest.cs.meta} | 0 .../{SpyLogger.cs => SpyLoggerAsset.cs} | 4 +- ...yLogger.cs.meta => SpyLoggerAsset.cs.meta} | 0 23 files changed, 120 insertions(+), 124 deletions(-) rename Runtime/Loggers/{AbstractLogger.cs => AbstractLoggerAsset.cs} (82%) rename Runtime/Loggers/{AbstractLogger.cs.meta => AbstractLoggerAsset.cs.meta} (100%) rename Runtime/Loggers/{CompositeLogger.cs => CompositeLoggerAsset.cs} (62%) rename Runtime/Loggers/{CompositeLogger.cs.meta => CompositeLoggerAsset.cs.meta} (100%) rename Runtime/Loggers/{ConsoleLogger.cs => ConsoleLoggerAsset.cs} (91%) rename Runtime/Loggers/{ConsoleLogger.cs.meta => ConsoleLoggerAsset.cs.meta} (100%) rename Runtime/Loggers/{FileLogger.cs => FileLoggerAsset.cs} (97%) rename Runtime/Loggers/{FileLogger.cs.meta => FileLoggerAsset.cs.meta} (100%) rename Tests/Runtime/Loggers/{CompositeLoggerTest.cs => CompositeLoggerAssetTest.cs} (74%) rename Tests/Runtime/Loggers/{CompositeLoggerTest.cs.meta => CompositeLoggerAssetTest.cs.meta} (100%) rename Tests/Runtime/Loggers/{ConsoleLoggerTest.cs => ConsoleLoggerAssetTest.cs} (82%) rename Tests/Runtime/Loggers/{ConsoleLoggerTest.cs.meta => ConsoleLoggerAssetTest.cs.meta} (100%) rename Tests/Runtime/Loggers/{FileLoggerTest.cs => FileLoggerAssetTest.cs} (88%) rename Tests/Runtime/Loggers/{FileLoggerTest.cs.meta => FileLoggerAssetTest.cs.meta} (100%) rename Tests/Runtime/TestDoubles/{SpyLogger.cs => SpyLoggerAsset.cs} (93%) rename Tests/Runtime/TestDoubles/{SpyLogger.cs.meta => SpyLoggerAsset.cs.meta} (100%) diff --git a/Editor/UI/Loggers/CompositeLoggerEditor.cs b/Editor/UI/Loggers/CompositeLoggerEditor.cs index 0b39e4a..3550ec9 100644 --- a/Editor/UI/Loggers/CompositeLoggerEditor.cs +++ b/Editor/UI/Loggers/CompositeLoggerEditor.cs @@ -10,7 +10,7 @@ namespace DeNA.Anjin.Editor.UI.Loggers /// /// Editor GUI for CompositeLogger. /// - [CustomEditor(typeof(CompositeLogger))] + [CustomEditor(typeof(CompositeLoggerAsset))] public class CompositeLoggerEditor : UnityEditor.Editor { private static readonly string s_description = L10n.Tr("Description"); @@ -24,9 +24,9 @@ public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(CompositeLogger.description)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(CompositeLoggerAsset.description)), new GUIContent(s_description, s_descriptionTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(CompositeLogger.loggers)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(CompositeLoggerAsset.loggerAssets)), new GUIContent(s_loggers, s_loggersTooltip)); serializedObject.ApplyModifiedProperties(); diff --git a/Editor/UI/Loggers/ConsoleLoggerEditor.cs b/Editor/UI/Loggers/ConsoleLoggerEditor.cs index 640b2e8..64a63bf 100644 --- a/Editor/UI/Loggers/ConsoleLoggerEditor.cs +++ b/Editor/UI/Loggers/ConsoleLoggerEditor.cs @@ -10,7 +10,7 @@ namespace DeNA.Anjin.Editor.UI.Loggers /// /// Editor GUI for ConsoleLogger. /// - [CustomEditor(typeof(ConsoleLogger))] + [CustomEditor(typeof(ConsoleLoggerAsset))] public class ConsoleLoggerEditor : UnityEditor.Editor { private static readonly string s_description = L10n.Tr("Description"); @@ -24,9 +24,9 @@ public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLogger.description)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLoggerAsset.description)), new GUIContent(s_description, s_descriptionTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLogger.filterLogType)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(ConsoleLoggerAsset.filterLogType)), new GUIContent(s_filterLogType, s_filterLogTypeTooltip)); serializedObject.ApplyModifiedProperties(); diff --git a/Editor/UI/Loggers/FileLoggerEditor.cs b/Editor/UI/Loggers/FileLoggerEditor.cs index 1ddb792..53ff52c 100644 --- a/Editor/UI/Loggers/FileLoggerEditor.cs +++ b/Editor/UI/Loggers/FileLoggerEditor.cs @@ -10,7 +10,7 @@ namespace DeNA.Anjin.Editor.UI.Loggers /// /// Editor GUI for FileLogger. /// - [CustomEditor(typeof(FileLogger))] + [CustomEditor(typeof(FileLoggerAsset))] public class FileLoggerEditor : UnityEditor.Editor { private static readonly string s_description = L10n.Tr("Description"); @@ -30,13 +30,13 @@ public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.description)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLoggerAsset.description)), new GUIContent(s_description, s_descriptionTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.outputPath)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLoggerAsset.outputPath)), new GUIContent(s_outputPath, s_outputPathTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.filterLogType)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLoggerAsset.filterLogType)), new GUIContent(s_filterLogType, s_filterLogTypeTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLogger.timestamp)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(FileLoggerAsset.timestamp)), new GUIContent(s_timestamp, s_timestampTooltip)); serializedObject.ApplyModifiedProperties(); diff --git a/Editor/UI/Settings/AutopilotSettingsEditor.cs b/Editor/UI/Settings/AutopilotSettingsEditor.cs index fab612d..2596290 100644 --- a/Editor/UI/Settings/AutopilotSettingsEditor.cs +++ b/Editor/UI/Settings/AutopilotSettingsEditor.cs @@ -115,7 +115,7 @@ public override void OnInspectorGUI() new GUIContent(s_timeScale, s_timeScaleTooltip)); EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.junitReportPath)), new GUIContent(s_junitReportPath, s_junitReportPathTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.logger)), + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.loggerAsset)), new GUIContent(s_logger, s_loggerTooltip)); EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(AutopilotSettings.reporter)), new GUIContent(s_reporter, s_reporterTooltip)); diff --git a/Runtime/Autopilot.cs b/Runtime/Autopilot.cs index 6a656c7..8251569 100644 --- a/Runtime/Autopilot.cs +++ b/Runtime/Autopilot.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Threading; using Cysharp.Threading.Tasks; +using DeNA.Anjin.Loggers; using DeNA.Anjin.Settings; using DeNA.Anjin.Utilities; using UnityEngine; @@ -18,6 +19,7 @@ namespace DeNA.Anjin /// public class Autopilot : MonoBehaviour { + private AbstractLoggerAsset _loggerAsset; private ILogger _logger; private RandomFactory _randomFactory; private IAgentDispatcher _dispatcher; @@ -32,14 +34,8 @@ private void Start() _settings = _state.settings; Assert.IsNotNull(_settings); - if (_settings.logger != null) - { - _logger = _settings.logger.LoggerImpl; - } - else - { - _logger = CreateDefaultLogger(); - } + _loggerAsset = _settings.loggerAsset; + _logger = _loggerAsset != null ? _loggerAsset.Logger : CreateDefaultLogger(); if (!int.TryParse(_settings.randomSeed, out var seed)) { @@ -99,7 +95,7 @@ private void OnDestroy() _dispatcher?.Dispose(); _logMessageHandler?.Dispose(); - _settings.logger?.Dispose(); + _settings.loggerAsset?.Dispose(); } /// diff --git a/Runtime/Loggers/AbstractLogger.cs b/Runtime/Loggers/AbstractLoggerAsset.cs similarity index 82% rename from Runtime/Loggers/AbstractLogger.cs rename to Runtime/Loggers/AbstractLoggerAsset.cs index 11bbc81..820c7e3 100644 --- a/Runtime/Loggers/AbstractLogger.cs +++ b/Runtime/Loggers/AbstractLoggerAsset.cs @@ -9,7 +9,7 @@ namespace DeNA.Anjin.Loggers /// /// Abstract logger settings used for autopilot. /// - public abstract class AbstractLogger : ScriptableObject, IDisposable + public abstract class AbstractLoggerAsset : ScriptableObject, IDisposable { #if UNITY_EDITOR /// @@ -21,7 +21,7 @@ public abstract class AbstractLogger : ScriptableObject, IDisposable /// /// Logger implementation used for autopilot. /// - public abstract ILogger LoggerImpl { get; } + public abstract ILogger Logger { get; } /// public abstract void Dispose(); diff --git a/Runtime/Loggers/AbstractLogger.cs.meta b/Runtime/Loggers/AbstractLoggerAsset.cs.meta similarity index 100% rename from Runtime/Loggers/AbstractLogger.cs.meta rename to Runtime/Loggers/AbstractLoggerAsset.cs.meta diff --git a/Runtime/Loggers/CompositeLogger.cs b/Runtime/Loggers/CompositeLoggerAsset.cs similarity index 62% rename from Runtime/Loggers/CompositeLogger.cs rename to Runtime/Loggers/CompositeLoggerAsset.cs index db7983b..21bffdb 100644 --- a/Runtime/Loggers/CompositeLogger.cs +++ b/Runtime/Loggers/CompositeLoggerAsset.cs @@ -13,18 +13,18 @@ namespace DeNA.Anjin.Loggers /// A class for a logger that delegates to multiple loggers /// [CreateAssetMenu(fileName = "New CompositeLogger", menuName = "Anjin/Composite Logger", order = 70)] - public class CompositeLogger : AbstractLogger + public class CompositeLoggerAsset : AbstractLoggerAsset { /// /// Loggers to delegates /// - public List loggers = new List(); + public List loggerAssets = new List(); private CompositeLogHandler _handler; private Logger _logger; /// - public override ILogger LoggerImpl + public override ILogger Logger { get { @@ -33,7 +33,7 @@ public override ILogger LoggerImpl return _logger; } - _handler = new CompositeLogHandler(loggers, this); + _handler = new CompositeLogHandler(loggerAssets, this); _logger = new Logger(_handler); return _logger; } @@ -47,39 +47,39 @@ public override void Dispose() private class CompositeLogHandler : ILogHandler, IDisposable { - private readonly List _loggers; - private readonly AbstractLogger _owner; + private readonly List _loggerAssets; + private readonly AbstractLoggerAsset _owner; - public CompositeLogHandler(List loggers, AbstractLogger owner) + public CompositeLogHandler(List loggerAssets, AbstractLoggerAsset owner) { - _loggers = loggers; + _loggerAssets = loggerAssets; _owner = owner; } /// public void LogFormat(LogType logType, Object context, string format, params object[] args) { - foreach (var logger in _loggers.Where(logger => logger != null && logger != _owner)) + foreach (var loggerAsset in _loggerAssets.Where(x => x != null && x != _owner)) { - logger.LoggerImpl.LogFormat(logType, context, format, args); + loggerAsset.Logger.LogFormat(logType, context, format, args); } } /// public void LogException(Exception exception, Object context) { - foreach (var logger in _loggers.Where(logger => logger != null && logger != _owner)) + foreach (var loggerAsset in _loggerAssets.Where(x => x != null && x != _owner)) { - logger.LoggerImpl.LogException(exception, context); + loggerAsset.Logger.LogException(exception, context); } } /// public void Dispose() { - foreach (var logger in _loggers.Where(logger => logger != null && logger != _owner)) + foreach (var loggerAsset in _loggerAssets.Where(x => x != null && x != _owner)) { - logger.Dispose(); + loggerAsset.Dispose(); } } } diff --git a/Runtime/Loggers/CompositeLogger.cs.meta b/Runtime/Loggers/CompositeLoggerAsset.cs.meta similarity index 100% rename from Runtime/Loggers/CompositeLogger.cs.meta rename to Runtime/Loggers/CompositeLoggerAsset.cs.meta diff --git a/Runtime/Loggers/ConsoleLogger.cs b/Runtime/Loggers/ConsoleLoggerAsset.cs similarity index 91% rename from Runtime/Loggers/ConsoleLogger.cs rename to Runtime/Loggers/ConsoleLoggerAsset.cs index ea18d8c..4d61dfc 100644 --- a/Runtime/Loggers/ConsoleLogger.cs +++ b/Runtime/Loggers/ConsoleLoggerAsset.cs @@ -10,7 +10,7 @@ namespace DeNA.Anjin.Loggers /// Logger using Debug.unityLogger /// [CreateAssetMenu(fileName = "New ConsoleLogger", menuName = "Anjin/Console Logger", order = 71)] - public class ConsoleLogger : AbstractLogger + public class ConsoleLoggerAsset : AbstractLoggerAsset { /// /// To selective enable debug log message. @@ -20,7 +20,7 @@ public class ConsoleLogger : AbstractLogger private ILogger _logger; /// - public override ILogger LoggerImpl + public override ILogger Logger { get { diff --git a/Runtime/Loggers/ConsoleLogger.cs.meta b/Runtime/Loggers/ConsoleLoggerAsset.cs.meta similarity index 100% rename from Runtime/Loggers/ConsoleLogger.cs.meta rename to Runtime/Loggers/ConsoleLoggerAsset.cs.meta diff --git a/Runtime/Loggers/FileLogger.cs b/Runtime/Loggers/FileLoggerAsset.cs similarity index 97% rename from Runtime/Loggers/FileLogger.cs rename to Runtime/Loggers/FileLoggerAsset.cs index be6d8b4..9cbc3a8 100644 --- a/Runtime/Loggers/FileLogger.cs +++ b/Runtime/Loggers/FileLoggerAsset.cs @@ -17,7 +17,7 @@ namespace DeNA.Anjin.Loggers /// /// [CreateAssetMenu(fileName = "New FileLogger", menuName = "Anjin/File Logger", order = 72)] - public class FileLogger : AbstractLogger + public class FileLoggerAsset : AbstractLoggerAsset { /// /// Log output file path. @@ -39,7 +39,7 @@ public class FileLogger : AbstractLogger private ILogger _logger; /// - public override ILogger LoggerImpl + public override ILogger Logger { get { diff --git a/Runtime/Loggers/FileLogger.cs.meta b/Runtime/Loggers/FileLoggerAsset.cs.meta similarity index 100% rename from Runtime/Loggers/FileLogger.cs.meta rename to Runtime/Loggers/FileLoggerAsset.cs.meta diff --git a/Runtime/Settings/AutopilotSettings.cs b/Runtime/Settings/AutopilotSettings.cs index df6a754..9d58170 100644 --- a/Runtime/Settings/AutopilotSettings.cs +++ b/Runtime/Settings/AutopilotSettings.cs @@ -129,7 +129,7 @@ public class AutopilotSettings : ScriptableObject /// /// Logger used for this autopilot settings. /// - public AbstractLogger logger; + public AbstractLoggerAsset loggerAsset; /// /// Reporter that called when some errors occurred diff --git a/Tests/Runtime/AutopilotTest.cs b/Tests/Runtime/AutopilotTest.cs index f13684f..cd87fa0 100644 --- a/Tests/Runtime/AutopilotTest.cs +++ b/Tests/Runtime/AutopilotTest.cs @@ -32,8 +32,8 @@ public async Task Start_LoggerSpecified_UsingSpecifiedLogger() var autopilotSettings = ScriptableObject.CreateInstance(); autopilotSettings.sceneAgentMaps = new List(); autopilotSettings.lifespanSec = 1; - var spyLogger = ScriptableObject.CreateInstance(); - autopilotSettings.logger = spyLogger; + var spyLogger = ScriptableObject.CreateInstance(); + autopilotSettings.loggerAsset = spyLogger; await LauncherFromTest.AutopilotAsync(autopilotSettings); diff --git a/Tests/Runtime/Loggers/CompositeLoggerTest.cs b/Tests/Runtime/Loggers/CompositeLoggerAssetTest.cs similarity index 74% rename from Tests/Runtime/Loggers/CompositeLoggerTest.cs rename to Tests/Runtime/Loggers/CompositeLoggerAssetTest.cs index 7f2dbe9..72d217e 100644 --- a/Tests/Runtime/Loggers/CompositeLoggerTest.cs +++ b/Tests/Runtime/Loggers/CompositeLoggerAssetTest.cs @@ -9,7 +9,7 @@ namespace DeNA.Anjin.Loggers { [TestFixture] - public class CompositeLoggerTest + public class CompositeLoggerAssetTest { private static Exception CreateExceptionWithStacktrace(string message) { @@ -26,14 +26,14 @@ private static Exception CreateExceptionWithStacktrace(string message) [Test] public void LogFormat_CompositeMultipleLoggers_OutputBothLoggers() { - var logger1 = ScriptableObject.CreateInstance(); - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(logger1); - sut.loggers.Add(logger2); + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(logger1); + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); Assert.That(logger1.Logs, Does.Contain(message)); Assert.That(logger2.Logs, Does.Contain(message)); @@ -42,13 +42,13 @@ public void LogFormat_CompositeMultipleLoggers_OutputBothLoggers() [Test] public void LogFormat_LoggersIncludesNull_IgnoreNull() { - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(null); - sut.loggers.Add(logger2); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(null); + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); Assert.That(logger2.Logs, Does.Contain(message)); } @@ -56,13 +56,13 @@ public void LogFormat_LoggersIncludesNull_IgnoreNull() [Test] public void LogFormat_NestingLogger_IgnoreNested() { - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(sut); // nesting - sut.loggers.Add(logger2); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(sut); // nesting + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); Assert.That(logger2.Logs, Does.Contain(message)); } @@ -70,15 +70,15 @@ public void LogFormat_NestingLogger_IgnoreNested() [Test] public void LogException_CompositeMultipleLoggers_OutputBothLoggers() { - var logger1 = ScriptableObject.CreateInstance(); - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(logger1); - sut.loggers.Add(logger2); + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(logger1); + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; var exception = CreateExceptionWithStacktrace(message); - sut.LoggerImpl.LogException(exception); + sut.Logger.LogException(exception); Assert.That(logger1.Logs, Does.Contain(exception.ToString())); Assert.That(logger2.Logs, Does.Contain(exception.ToString())); @@ -87,14 +87,14 @@ public void LogException_CompositeMultipleLoggers_OutputBothLoggers() [Test] public void LogException_LoggersIncludesNull_IgnoreNull() { - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(null); - sut.loggers.Add(logger2); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(null); + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; var exception = CreateExceptionWithStacktrace(message); - sut.LoggerImpl.LogException(exception); + sut.Logger.LogException(exception); Assert.That(logger2.Logs, Does.Contain(exception.ToString())); } @@ -102,14 +102,14 @@ public void LogException_LoggersIncludesNull_IgnoreNull() [Test] public void LogException_NestingLogger_IgnoreNested() { - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(sut); // nesting - sut.loggers.Add(logger2); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(sut); // nesting + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; var exception = CreateExceptionWithStacktrace(message); - sut.LoggerImpl.LogException(exception); + sut.Logger.LogException(exception); Assert.That(logger2.Logs, Does.Contain(exception.ToString())); } @@ -117,14 +117,14 @@ public void LogException_NestingLogger_IgnoreNested() [Test] public void Dispose_CompositeMultipleLoggers_DisposeAllLoggers() { - var logger1 = ScriptableObject.CreateInstance(); - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(logger1); - sut.loggers.Add(logger2); + var logger1 = ScriptableObject.CreateInstance(); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(logger1); + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); sut.Dispose(); Assert.That(logger1.Disposed, Is.True); @@ -134,13 +134,13 @@ public void Dispose_CompositeMultipleLoggers_DisposeAllLoggers() [Test] public void Dispose_LoggersIncludesNull_IgnoreNull() { - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(null); - sut.loggers.Add(logger2); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(null); + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); sut.Dispose(); Assert.That(logger2.Disposed, Is.True); @@ -149,13 +149,13 @@ public void Dispose_LoggersIncludesNull_IgnoreNull() [Test] public void Dispose_NestingLogger_IgnoreNested() { - var logger2 = ScriptableObject.CreateInstance(); - var sut = ScriptableObject.CreateInstance(); - sut.loggers.Add(sut); // nesting - sut.loggers.Add(logger2); + var logger2 = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); + sut.loggerAssets.Add(sut); // nesting + sut.loggerAssets.Add(logger2); var message = TestContext.CurrentContext.Test.Name; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); sut.Dispose(); Assert.That(logger2.Disposed, Is.True); diff --git a/Tests/Runtime/Loggers/CompositeLoggerTest.cs.meta b/Tests/Runtime/Loggers/CompositeLoggerAssetTest.cs.meta similarity index 100% rename from Tests/Runtime/Loggers/CompositeLoggerTest.cs.meta rename to Tests/Runtime/Loggers/CompositeLoggerAssetTest.cs.meta diff --git a/Tests/Runtime/Loggers/ConsoleLoggerTest.cs b/Tests/Runtime/Loggers/ConsoleLoggerAssetTest.cs similarity index 82% rename from Tests/Runtime/Loggers/ConsoleLoggerTest.cs rename to Tests/Runtime/Loggers/ConsoleLoggerAssetTest.cs index b448425..f29687b 100644 --- a/Tests/Runtime/Loggers/ConsoleLoggerTest.cs +++ b/Tests/Runtime/Loggers/ConsoleLoggerAssetTest.cs @@ -8,15 +8,15 @@ namespace DeNA.Anjin.Loggers { [TestFixture] - public class ConsoleLoggerTest + public class ConsoleLoggerAssetTest { [Test] public void FilterLogTypeIsNotSet_LogAsDefault() { var message = TestContext.CurrentContext.Test.Name; - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); LogAssert.Expect(LogType.Log, message); LogAssert.NoUnexpectedReceived(); @@ -28,11 +28,11 @@ public void FilterLogTypeSpecified( LogType logType) { var message = TestContext.CurrentContext.Test.Name; - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.filterLogType = logType; - sut.LoggerImpl.Log(logType, message); - sut.LoggerImpl.Log("Not output message because LogType.Log"); + sut.Logger.Log(logType, message); + sut.Logger.Log("Not output message because LogType.Log"); LogAssert.Expect(logType, message); LogAssert.NoUnexpectedReceived(); diff --git a/Tests/Runtime/Loggers/ConsoleLoggerTest.cs.meta b/Tests/Runtime/Loggers/ConsoleLoggerAssetTest.cs.meta similarity index 100% rename from Tests/Runtime/Loggers/ConsoleLoggerTest.cs.meta rename to Tests/Runtime/Loggers/ConsoleLoggerAssetTest.cs.meta diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs b/Tests/Runtime/Loggers/FileLoggerAssetTest.cs similarity index 88% rename from Tests/Runtime/Loggers/FileLoggerTest.cs rename to Tests/Runtime/Loggers/FileLoggerAssetTest.cs index be6cccb..9f44b0e 100644 --- a/Tests/Runtime/Loggers/FileLoggerTest.cs +++ b/Tests/Runtime/Loggers/FileLoggerAssetTest.cs @@ -13,7 +13,7 @@ namespace DeNA.Anjin.Loggers { [TestFixture] - public class FileLoggerTest + public class FileLoggerAssetTest { private const string LogsDirectoryPath = "Logs/FileLoggerTest"; private const string TimestampRegex = @"\[\d{2}:\d{2}:\d{2}\.\d{3}\] "; @@ -45,11 +45,11 @@ public async Task GetLoggerImpl_DirectoryDoesNotExist_CreateDirectoryAndWriteToF var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = false; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); sut.Dispose(); await Task.Yield(); @@ -64,11 +64,11 @@ public async Task GetLoggerImpl_FileExists_OverwrittenToFile() var path = GetOutputPath(); File.WriteAllText(path, "Existing content"); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = false; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); sut.Dispose(); await Task.Yield(); @@ -81,12 +81,12 @@ public async Task LogFormat_WriteToFile() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = false; - sut.LoggerImpl.Log(message); - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); + sut.Logger.Log(message); sut.Dispose(); await Task.Yield(); @@ -99,16 +99,16 @@ public async Task LogFormat_Disposed_NotWriteToFile() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = false; - sut.LoggerImpl.Log(message); - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); + sut.Logger.Log(message); sut.Dispose(); await Task.Yield(); - sut.LoggerImpl.Log(message); // write after disposed + sut.Logger.Log(message); // write after disposed await Task.Yield(); var actual = File.ReadAllText(path); @@ -120,14 +120,14 @@ public async Task LogFormat_WithTimestamp_WriteTimestamp() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = true; - sut.LoggerImpl.Log(message); + sut.Logger.Log(message); await UniTask.NextFrame(); - sut.LoggerImpl.Log(message); - sut.LoggerImpl.Log(message); // using cache + sut.Logger.Log(message); + sut.Logger.Log(message); // using cache sut.Dispose(); await Task.Yield(); @@ -145,12 +145,12 @@ public async Task LogException_WriteToFile() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = false; var exception = CreateExceptionWithStacktrace(message); - sut.LoggerImpl.LogException(exception); + sut.Logger.LogException(exception); sut.Dispose(); await Task.Yield(); @@ -163,16 +163,16 @@ public async Task LogException_Disposed_NotWriteToFile() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = false; var exception = CreateExceptionWithStacktrace(message); - sut.LoggerImpl.LogException(exception); + sut.Logger.LogException(exception); sut.Dispose(); await Task.Yield(); - sut.LoggerImpl.LogException(exception); // write after disposed + sut.Logger.LogException(exception); // write after disposed await Task.Yield(); var actual = File.ReadAllText(path); @@ -184,12 +184,12 @@ public async Task LogException_WithTimestamp_WriteTimestamp() { var message = TestContext.CurrentContext.Test.Name; var path = GetOutputPath(); - var sut = ScriptableObject.CreateInstance(); + var sut = ScriptableObject.CreateInstance(); sut.outputPath = path; sut.timestamp = true; var exception = CreateExceptionWithStacktrace(message); - sut.LoggerImpl.LogException(exception); + sut.Logger.LogException(exception); sut.Dispose(); await Task.Yield(); diff --git a/Tests/Runtime/Loggers/FileLoggerTest.cs.meta b/Tests/Runtime/Loggers/FileLoggerAssetTest.cs.meta similarity index 100% rename from Tests/Runtime/Loggers/FileLoggerTest.cs.meta rename to Tests/Runtime/Loggers/FileLoggerAssetTest.cs.meta diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs b/Tests/Runtime/TestDoubles/SpyLoggerAsset.cs similarity index 93% rename from Tests/Runtime/TestDoubles/SpyLogger.cs rename to Tests/Runtime/TestDoubles/SpyLoggerAsset.cs index c541c29..6689345 100644 --- a/Tests/Runtime/TestDoubles/SpyLogger.cs +++ b/Tests/Runtime/TestDoubles/SpyLoggerAsset.cs @@ -9,14 +9,14 @@ namespace DeNA.Anjin.TestDoubles { - public class SpyLogger : AbstractLogger + public class SpyLoggerAsset : AbstractLoggerAsset { public bool Disposed { get; private set; } private SpyLogHandler _handler; private ILogger _logger; - public override ILogger LoggerImpl + public override ILogger Logger { get { diff --git a/Tests/Runtime/TestDoubles/SpyLogger.cs.meta b/Tests/Runtime/TestDoubles/SpyLoggerAsset.cs.meta similarity index 100% rename from Tests/Runtime/TestDoubles/SpyLogger.cs.meta rename to Tests/Runtime/TestDoubles/SpyLoggerAsset.cs.meta