アマゾンバナーリンク

ディスプレイ広告

スポンサーリンク

【Unity】エラーログをPlayFabに送る方法

こんにちは!ジェイです。オンラインゲーム制作で特に困るのがデバッグで、私は今までデバッグ配信をして、エラーログをDiscodeに張り付けてもらっていたのですが、送る方もにも手間がかかり大変な作業になります。

そこで今回は、エラーログをPlayFabのサーバーに送って、わざわざプレイヤーに報告してもらわなくてもよいように自動化する仕組みを作ります。

記事内広告

エラーを送信するクラス

まずは発生したエラーをフィルタリングや整形をし好みの形にします。以下のクラスは作成するだけでアタッチする必要はありません。

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Junya
{
	/// <summary>
	/// エラーを送信するインターフェイス
	/// </summary>
	public interface IErrorSenderHandle
	{
		/// <summary>
		/// エラーを送信する時に呼び出される関数
		/// </summary>
		void Send( string condition, string stack_trace, LogType type );
	}

	/// <summary>
	/// エラーを送信するクラス
	/// </summary>
	public sealed class CErrorSender
	{
		private readonly IErrorSenderHandle SenderHandle;
		/// <summary>
		/// 連続でエラーを送信する時の待機時間
		/// この待機時間の間に送信しようとしたエラーは無視します
		/// </summary>
		public float Interval { private get; set; }

		/// <summary>
		/// スタックトレースから除外したい文字列のリスト
		/// StartsWith で一致したスタックトレースの行は無視します
		/// </summary>
		public IReadOnlyList<string> IgnoreStackTraceList { private get; set; } = new string[0];

		/// <summary>
		/// 送信するスタックトレースの行数
		/// </summary>
		public int StackTraceLines { private get; set; } = 10;

		private string LastCondition;
		private string LastStackTrace;
		private float  LastTime;

		/// <summary>
		/// コンストラクタ
		/// </summary>
		public CErrorSender( IErrorSenderHandle handle )
		{
			SenderHandle = handle;
		}

		/// <summary>
		/// 最後に送信したエラーの情報を破棄します
		/// </summary>
		public void Clear()
		{
			LastCondition  = default;
			LastStackTrace = default;
			LastTime       = default;
		}

		/// <summary>
		/// エラーを送信します
		/// </summary>
		public void Send( string condition, string stack_trace, LogType type )
		{
			// Unityを再生していない時は送信しません
			if ( !Application.isPlaying ) return;
			
#if UNITY_EDITOR
			// コンパイル中は送信しません
			if ( UnityEditor.EditorApplication.isCompiling ) return;
#endif

			// 最後に送信したエラーと同じ場合は送信しません
			if ( LastCondition == condition && LastStackTrace == stack_trace) return;

			// 連続でエラーを送信しようとした場合は無視します
			var realtimeSinceStartup = Time.realtimeSinceStartup;
			if ( Mathf.Abs( realtimeSinceStartup - LastTime ) < Interval ) return;

			// 最後に送信したエラーの情報を記憶しておきます
			LastCondition  = condition;
			LastStackTrace = stack_trace;
			LastTime       = Time.realtimeSinceStartup;

			// スタックトレースから除外したい行を除外し、指定の行数に抑えます
			var stackTraceExcludingIgnores = stack_trace
					.Split('\n')
					.Where(x => IgnoreStackTraceList.All(y => !x.StartsWith(y)))
					.Take(StackTraceLines);

			stack_trace = string.Join( "\n", stackTraceExcludingIgnores ).TrimEnd();

			// 送信します
			SenderHandle.Send( condition, stack_trace, type );
		}
	}
}

PlayFabにエラーログを書き込む

実際にPlayFabにエラーログを書き込むプログラムです。まずは以下のスクリプトを適当なオブジェクトにアタッチしましょう。PlayFabにログインした後でなければ、エラーメッセージが送信できないので、注意してください。PlayFabのWritePlayerEventについてはこちら

using UnityEngine;
using PlayFab;
using PlayFab.ClientModels;
using System.Collections.Generic;
using Junya;

public class CSendErrorMessage : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Z))
        {
            int.Parse("a");
        }
    }

    private sealed class ErrorSenderHandle : IErrorSenderHandle
    {
        // PlayFabへエラーメッセージを送信する
        private void SendErrorMessageToPlayFab(string condition, string stack_trace, string log_type)
        {
            PlayFabClientAPI.WritePlayerEvent(new WriteClientPlayerEventRequest()
            {
                Body = new Dictionary<string, object>() 
                {
                    { "Condition", condition },
                    { "StackTrace", stack_trace },
                    { "LogType", log_type },
                },
                EventName = "ErrorLog"
            },
            result => Debug.Log("Success"),
            error => Debug.LogError(error.GenerateErrorReport()));
        }
        public void Send(string condition, string stack_trace, LogType type)
        {
            // ここにサーバにエラーログを送信する処理を記述
            SendErrorMessageToPlayFab(condition, stack_trace, type.ToString());
        }
    }

    // サーバにエラーを送信するためのインスタンス
    private readonly CErrorSender ErrorSender = new CErrorSender(new ErrorSenderHandle())
    {
        // 連続でエラーを送信する時の待機時間
        // この待機時間の間に発生したエラーは送信しない
        Interval = 0.5f,

        // スタックトレースから除外したい文字列のリスト
        // StartsWith で一致したスタックトレースの行は除外
        IgnoreStackTraceList = new string[0],

        // 送信するスタックトレースの行数
        StackTraceLines = 10,
    };

    private void Awake()
    {
        // ログ出力された時に呼び出されるイベントにコールバックを登録
        Application.logMessageReceivedThreaded += OnLogMessageReceivedThreaded;
    }

    private void OnLogMessageReceivedThreaded(string condition, string stacktrace, LogType type)
    {
        // エラーや例外ではない場合は無視
        if (type != LogType.Error && type != LogType.Assert && type != LogType.Exception) return;

        // エラーや例外はログの情報をサーバに送信
        ErrorSender.Send(condition, stacktrace, type);
    }
}

次にPlayFabにログインした後にタイトル概要のPlayStreamタブをクリックして、PlayStreamモニターを開きましょう。ちなみに色をつけた20行目から34行目と38行目を変更すれば、PlayFab以外の他のサーバーに送信するのも可能です。

その後にゲームを起動して、ログインを実行した後に、Zキーを押すとFomatExceptionのエラーがでます。

するとイベントからErrorMessageを選ぶと以下の様にエラーログが見れるようになります。

PlayStreamモニターを開いてない時にエラーを出しても、表示されないので注意が必要です。これでわざわざエラーログをDiscodeなどに張り付けてもらわなくても、サーバー側でエラーログを回収できるので、特にオンラインゲーム制作をする時には、かなり手間を減らすことができます。

アイコンは鬼塚@取締役【フリーアイコン職人】【アイコン企画】様からお借りしました。

+3