Skip to content

Commit

Permalink
Merge pull request #93 from nowsprinting/feature/report_on_normally_t…
Browse files Browse the repository at this point in the history
…ermination

Post a report when normally termination
  • Loading branch information
asurato authored Nov 1, 2024
2 parents ccfdc03 + e13dc2e commit 02b7af5
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 228 deletions.
24 changes: 24 additions & 0 deletions Editor/Localization/ja.po
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,27 @@ msgstr "@hereをメッセージにつける"
# addHereInSlackMessage tooltip
msgid "Whether adding @here into Slack messages or not"
msgstr "Slack通知メッセージに@hereを付けます"

# withScreenshotOnError
msgid "Take screenshot"
msgstr "スクリーンショット"

# withScreenshotOnError tooltip
msgid "Take a screenshot when posting an error terminated report"
msgstr "エラー終了時にスクリーンショットを撮影します"

# postOnNormally
msgid "Normally terminated report"
msgstr "正常終了時にもレポート"

# postOnNormally tooltip
msgid "Post a report if normally terminates."
msgstr "正常終了時にもレポートをポストします"

# withScreenshotOnNormally (same as withScreenshotOnError)
msgid "Take screenshot"
msgstr "スクリーンショット"

# withScreenshotOnNormally tooltip
msgid "Take a screenshot when posting a normally terminated report"
msgstr "正常終了時にスクリーンショットを撮影します"
43 changes: 35 additions & 8 deletions Editor/UI/Reporters/SlackReporterEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ namespace DeNA.Anjin.Editor.UI.Reporters
public class SlackReporterEditor : UnityEditor.Editor
{
private const float SpacerPixels = 10f;
private const float SpacerPixelsUnderHeader = 4f;


private static readonly string s_description = L10n.Tr("Description");
private static readonly string s_descriptionTooltip = L10n.Tr("Description about this Reporter instance");
private SerializedProperty _descriptionProp;
Expand All @@ -31,8 +30,6 @@ public class SlackReporterEditor : UnityEditor.Editor
private SerializedProperty _slackChannelsProp;
private GUIContent _slackChannelsGUIContent;

private static readonly string s_slackMentionSettingsHeader = L10n.Tr("Slack Mention Settings");

private static readonly string s_mentionSubTeamIDs = L10n.Tr("Sub Team IDs to Mention");
private static readonly string s_mentionSubTeamIDsTooltip = L10n.Tr("Sub team IDs to mention (comma separates)");
private SerializedProperty _mentionSubTeamIDsProp;
Expand All @@ -43,6 +40,20 @@ public class SlackReporterEditor : UnityEditor.Editor
private SerializedProperty _addHereInSlackMessageProp;
private GUIContent _addHereInSlackMessageGUIContent;

private static readonly string s_withScreenshotOnError = L10n.Tr("Take screenshot");
private static readonly string s_withScreenshotOnErrorTooltip = L10n.Tr("Take a screenshot when posting an error terminated report");
private SerializedProperty _withScreenshotOnErrorProp;
private GUIContent _withScreenshotOnErrorGUIContent;

private static readonly string s_postOnNormally = L10n.Tr("Normally terminated report");
private static readonly string s_postOnNormallyTooltip = L10n.Tr("Post a report if normally terminates.");
private SerializedProperty _postOnNormallyProp;
private GUIContent _postOnNormallyGUIContent;

private static readonly string s_withScreenshotOnNormally = L10n.Tr("Take screenshot");
private static readonly string s_withScreenshotOnNormallyTooltip = L10n.Tr("Take a screenshot when posting a normally terminated report");
private SerializedProperty _withScreenshotOnNormallyProp;
private GUIContent _withScreenshotOnNormallyGUIContent;

private void OnEnable()
{
Expand All @@ -66,26 +77,42 @@ private void Initialize()

_addHereInSlackMessageProp = serializedObject.FindProperty(nameof(SlackReporter.addHereInSlackMessage));
_addHereInSlackMessageGUIContent = new GUIContent(s_addHereInSlackMessage, s_addHereInSlackMessageTooltip);

_withScreenshotOnErrorProp = serializedObject.FindProperty(nameof(SlackReporter.withScreenshotOnError));
_withScreenshotOnErrorGUIContent = new GUIContent(s_withScreenshotOnError, s_withScreenshotOnErrorTooltip);

_postOnNormallyProp = serializedObject.FindProperty(nameof(SlackReporter.postOnNormally));
_postOnNormallyGUIContent = new GUIContent(s_postOnNormally, s_postOnNormallyTooltip);

_withScreenshotOnNormallyProp = serializedObject.FindProperty(nameof(SlackReporter.withScreenshotOnNormally));
_withScreenshotOnNormallyGUIContent = new GUIContent(s_withScreenshotOnNormally, s_withScreenshotOnNormallyTooltip);
}


public override void OnInspectorGUI()
{
serializedObject.Update();

EditorGUILayout.PropertyField(_descriptionProp, _descriptionGUIContent);
GUILayout.Space(SpacerPixels);

EditorGUILayout.PropertyField(_slackTokenProp, _slackTokenGUIContent);
EditorGUILayout.PropertyField(_slackChannelsProp, _slackChannelsGUIContent);

GUILayout.Space(SpacerPixels);
GUILayout.Label(s_slackMentionSettingsHeader);
GUILayout.Space(SpacerPixelsUnderHeader);

EditorGUILayout.PropertyField(_mentionSubTeamIDsProp, _mentionSubTeamIDsGUIContent);
EditorGUILayout.PropertyField(_addHereInSlackMessageProp, _addHereInSlackMessageGUIContent);

GUILayout.Space(SpacerPixels);
EditorGUILayout.PropertyField(_withScreenshotOnErrorProp, _withScreenshotOnErrorGUIContent);

GUILayout.Space(SpacerPixels);
EditorGUILayout.PropertyField(_postOnNormallyProp, _postOnNormallyGUIContent);

EditorGUI.BeginDisabledGroup(!_postOnNormallyProp.boolValue);
EditorGUILayout.PropertyField(_withScreenshotOnNormallyProp, _withScreenshotOnNormallyGUIContent);
EditorGUI.EndDisabledGroup();

serializedObject.ApplyModifiedProperties();
}
}
Expand Down
2 changes: 1 addition & 1 deletion Editor/UI/Settings/AutopilotSettingsEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ internal void Stop()
var autopilot = FindObjectOfType<Autopilot>();
if (autopilot)
{
autopilot.TerminateAsync(ExitCode.Normally).Forget();
autopilot.TerminateAsync(ExitCode.Normally, reporting: false).Forget();
}
}

Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ This item can also be overridden from the commandline (see below).
<dt>Time Scale</dt><dd>Time.timeScale. Default is 1.0</dd>
<dt>JUnit Report Path</dt><dd>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. </dd>
<dt>Logger</dt><dd>Logger used for this autopilot settings. If omitted, <code>Debug.unityLogger</code> will be used as default.</dd>
<dt>Reporter</dt><dd>Reporter that called when some errors occurred in target application</dd>
<dt>Reporter</dt><dd>Reporter to be called on Autopilot terminate.</dd>
</dl>

#### Error Handling Settings
Expand Down Expand Up @@ -461,12 +461,15 @@ The instance of this Reporter (.asset file) can have the following settings.
The bot must be invited to the channel.</dd>
<dt>Mention Sub Team IDs</dt><dd>Comma Separated Team IDs to mention in notification message</dd>
<dt>Add Here In Slack Message</dt><dd>Add @here to notification message. Default is off</dd>
<dt>Take screenshot</dt><dd>Take a screenshot when posting an error terminated report. Default is on</dd>
<dt>Normally terminated report</dt><dd>Post a report if normally terminates. Default is off</dd>
<dt>Take screenshot</dt><dd>Take a screenshot when posting a normally terminated report. Default is off</dd>
</dl>

You can create a bot on the following page:
You can create a Slack Bot on the following page:
[Slack API: Applications](https://api.slack.com/apps)

The bot needs the following permissions:
The Slack Bot needs the following permissions:

- chat:write
- files:write
Expand Down
11 changes: 7 additions & 4 deletions README_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ v1.0.0時点では `EmergencyExitAgent` の使用を想定しています。
<dt>Time Scale</dt><dd>Time.timeScaleを指定します。デフォルトは1.0</dd>
<dt>JUnit Report Path</dt><dd>JUnit形式のレポートファイル出力パスを指定します(省略可)。オートパイロット実行の成否は、Unityエディターの終了コードでなくこのファイルを見て判断するのが確実です。errors, failuresともに0件であれば正常終了と判断できます。</dd>
<dt>Logger</dt><dd>オートパイロットが使用するLogger指定します。省略時は <code>Debug.unityLogger</code> がデフォルトとして使用されます</dd>
<dt>Reporter</dt><dd>対象のアプリケーションで発生したエラーを通知するReporterを指定します</dd>
<dt>Reporter</dt><dd>オートパイロット終了時に通知を行なうReporterを指定します</dd>
</dl>

#### エラーハンドリング設定
Expand Down Expand Up @@ -464,13 +464,16 @@ Slackにレポート送信するReporterです。
コマンドライン引数 <code>-SLACK_CHANNELS</code> で上書きできます。
チャンネルにはBotを招待しておく必要があります。</dd>
<dt>Mention Sub Team IDs</dt><dd>通知メッセージでメンションするチームのIDをカンマ区切りで指定します</dd>
<dt>Add Here In Slack Message</dt><dd>通知メッセージに@hereを付けます。デフォルトはoff</dd>
<dt>Add Here In Slack Message</dt><dd>通知メッセージに@hereを付けます(デフォルト: off)</dd>
<dt>Take screenshot</dt><dd>エラー終了時にスクリーンショットを撮影します(デフォルト: on)</dd>
<dt>Normally terminated report</dt><dd>正常終了時にもレポートをポストします(デフォルト: off)</dd>
<dt>Take screenshot</dt><dd>正常終了時にスクリーンショットを撮影します(デフォルト: off)</dd>
</dl>

Botは次のページで作成できます。
Slack Botは次のページで作成できます。
[Slack API: Applications](https://api.slack.com/apps)

Botには次の権限が必要です。
Slack Botには次の権限が必要です。

- chat:write
- files:write
Expand Down
60 changes: 40 additions & 20 deletions Runtime/Autopilot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,28 @@

namespace DeNA.Anjin
{
/// <summary>
/// Can be terminated.
/// </summary>
public interface ITerminatable
{
/// <summary>
/// Terminate autopilot
/// </summary>
/// <param name="exitCode">Exit code for Unity Editor/ Player-build</param>
/// <param name="message">Log message string or terminate message</param>
/// <param name="stackTrace">Stack trace when terminate by the log message</param>
/// <param name="reporting">Call Reporter if true</param>
/// <param name="token">Cancellation token</param>
/// <returns>A task awaits termination get completed</returns>
UniTask TerminateAsync(ExitCode exitCode, string message = null, string stackTrace = null,
bool reporting = true, CancellationToken token = default);
}

/// <summary>
/// Autopilot main logic
/// </summary>
public class Autopilot : MonoBehaviour
public class Autopilot : MonoBehaviour, ITerminatable
{
private AbstractLoggerAsset _loggerAsset;
private ILogger _logger;
Expand All @@ -28,6 +46,7 @@ public class Autopilot : MonoBehaviour
private AutopilotState _state;
private AutopilotSettings _settings;
private float _startTime;
private bool _isTerminating;

private void Start()
{
Expand All @@ -51,7 +70,7 @@ private void Start()
// NOTE: Registering logMessageReceived must be placed before DispatchByScene.
// Because some agent can throw an error immediately, so reporter can miss the error if
// registering logMessageReceived is placed after DispatchByScene.
_logMessageHandler = new LogMessageHandler(_settings, _settings.reporter);
_logMessageHandler = new LogMessageHandler(_settings, this);

_dispatcher = new AgentDispatcher(_settings, _logger, _randomFactory);
var dispatched = _dispatcher.DispatchByScene(SceneManager.GetActiveScene(), false);
Expand Down Expand Up @@ -126,34 +145,41 @@ internal static void ConvertSlackReporterFromObsoleteSlackSettings(AutopilotSett
private IEnumerator Lifespan(int timeoutSec)
{
yield return new WaitForSecondsRealtime(timeoutSec);
yield return UniTask.ToCoroutine(() => TerminateAsync(ExitCode.Normally));
yield return UniTask.ToCoroutine(() =>
TerminateAsync(ExitCode.Normally, "Autopilot has reached the end of its lifespan."));
}

private void OnDestroy()
{
// Clear event listeners.
// When play mode is stopped by the user, onDestroy calls without TerminateAsync.

_logger?.Log("Destroy Autopilot object");
_dispatcher?.Dispose();
_logMessageHandler?.Dispose();
_settings.loggerAsset?.Dispose();
}

/// <summary>
/// Terminate autopilot
/// </summary>
/// <param name="exitCode">Exit code for Unity Editor</param>
/// <param name="logString">Log message string when terminate by the log message</param>
/// <param name="stackTrace">Stack trace when terminate by the log message</param>
/// <param name="token">Cancellation token</param>
/// <returns>A task awaits termination get completed</returns>
public async UniTask TerminateAsync(ExitCode exitCode, string logString = null, string stackTrace = null,
CancellationToken token = default)
/// <inheritdoc/>
public async UniTask TerminateAsync(ExitCode exitCode, string message = null, string stackTrace = null,
bool reporting = true, CancellationToken token = default)
{
if (_isTerminating)
{
return; // Prevent multiple termination.
}

_isTerminating = true;

if (reporting && _state.IsRunning && _settings.reporter != null)
{
await _settings.reporter.PostReportAsync(message, stackTrace, exitCode, token);
}

if (_state.settings != null && !string.IsNullOrEmpty(_state.settings.junitReportPath))
{
var time = Time.realtimeSinceStartup - _startTime;
JUnitReporter.Output(_state.settings.junitReportPath, (int)exitCode, logString, stackTrace, time);
JUnitReporter.Output(_state.settings.junitReportPath, (int)exitCode, message, stackTrace, time);
}

DestroyImmediate(this.gameObject);
Expand All @@ -162,12 +188,6 @@ public async UniTask TerminateAsync(ExitCode exitCode, string logString = null,
await Launcher.TeardownLaunchAutopilotAsync(_state, _logger, exitCode, "Autopilot", token);
}

/// <summary>
/// Terminate autopilot
/// </summary>
/// <param name="exitCode">Exit code for Unity Editor</param>
/// <param name="logString">Log message string when terminate by the log message</param>
/// <param name="stackTrace">Stack trace when terminate by the log message</param>
[Obsolete("Use " + nameof(TerminateAsync))]
public void Terminate(ExitCode exitCode, string logString = null, string stackTrace = null)
{
Expand Down
15 changes: 7 additions & 8 deletions Runtime/Reporters/AbstractReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
namespace DeNA.Anjin.Reporters
{
/// <summary>
/// Reporter base class
/// Reporter base class.
/// Reporter is called on Autopilot termination.
/// </summary>
public abstract class AbstractReporter : ScriptableObject
{
Expand All @@ -22,17 +23,15 @@ public abstract class AbstractReporter : ScriptableObject
/// <summary>
/// Post report log message, stacktrace and screenshot
/// </summary>
/// <param name="logString">Log message</param>
/// <param name="stackTrace">Stack trace</param>
/// <param name="type">Log message type</param>
/// <param name="withScreenshot">With screenshot</param>
/// <param name="message">Log message or terminate message</param>
/// <param name="stackTrace">Stack trace (can be null)</param>
/// <param name="exitCode">Exit code indicating the reason for termination</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns></returns>
public abstract UniTask PostReportAsync(
string logString,
string message,
string stackTrace,
LogType type,
bool withScreenshot,
ExitCode exitCode,
CancellationToken cancellationToken = default
);
}
Expand Down
7 changes: 3 additions & 4 deletions Runtime/Reporters/CompositeReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@ public class CompositeReporter : AbstractReporter

/// <inheritdoc />
public override async UniTask PostReportAsync(
string logString,
string message,
string stackTrace,
LogType type,
bool withScreenshot,
ExitCode exitCode,
CancellationToken cancellationToken = default
)
{
await UniTask.WhenAll(
reporters
.Where(r => r != this && r != null)
.Select(
r => r.PostReportAsync(logString, stackTrace, type, withScreenshot, cancellationToken)
r => r.PostReportAsync(message, stackTrace, exitCode, cancellationToken)
)
);
}
Expand Down
Loading

0 comments on commit 02b7af5

Please sign in to comment.