(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!


無効化した時に無駄な文字列を生成しないログクラス【Unity】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 2022.3.32f1

はじめに

ゲーム開発(というかプログラミング?)に欠かせないログの表示ですが、

処理負荷の軽減や情報漏洩防止のためにリリース時には表示しないようにする事がほとんどです。



ただ、シンプルにログ表示メソッドだけを無効化すると以下のような

処理結果に応じて長めのログを作る時は無駄な文字列を生成してしまいます。

var log = "テストでログ追加";

/*なんか色々処理*/

log += "\n処理をもとに追加";

/*さらに色々処理*/

log += " + さらにログ追加";
    
//ログ表示
Debug.Log(log);//ここを無効化してもlogの文字列は生成してしまう


ということで今回は、

無効化した時に無駄な文字列を生成しないログクラスを作ったので、その紹介です!


無効化した時に無駄な文字列を生成しないログクラス

早速ですが、無効化した時に無駄な文字列を生成しないログクラスのコードは以下のとおりです。

なお、今回はUnityエディタ以外ではログを無効化するようにしていますが、

UNITY_EDITOR部分を変えれば任意のタイミングで無効化できます。

using System;
using System.Diagnostics;
using System.Text;
using UnityEngine;
using Debug = UnityEngine.Debug;

/// <summary>
/// エディタ用ログクラス
/// </summary>
public class EditorLogger {
  
  #if UNITY_EDITOR //一応、無駄に生成しないように
  private readonly StringBuilder _stringBuilder = new StringBuilder();
  #endif
  
  //=================================================================================
  //初期化
  //=================================================================================

  /// <summary>
  /// ログをリセット
  /// </summary>
  [Conditional("UNITY_EDITOR")]
  public void Clear() {
    #if UNITY_EDITOR
    _stringBuilder.Clear();
    #endif
  }

  //=================================================================================
  //追加
  //=================================================================================
  
  /// <summary>
  /// ログ追加
  /// </summary>
  [Conditional("UNITY_EDITOR")]
  public void Add(string message) {
  #if UNITY_EDITOR
    _stringBuilder.Append(message);
  #endif
  }

  //=================================================================================
  //表示
  //=================================================================================

  /// <summary>
  /// ログ表示
  /// </summary>
  [Conditional("UNITY_EDITOR")]
  public void Print(LogType logType = LogType.Log) {
  #if UNITY_EDITOR
    Print(_stringBuilder.ToString(), logType);
  #endif
  }

  /// <summary>
  /// ログ表示
  /// </summary>
  [Conditional("UNITY_EDITOR")]
  public static void Print(string message, LogType logType = LogType.Log) {
    switch (logType) {
      case LogType.Log:
        Debug.Log(message);
        break;
      case LogType.Warning:
        Debug.LogWarning(message);
        break;
      case LogType.Error:
        Debug.LogError(message);
        break;
      case LogType.Assert:
        Debug.LogAssertion(message);
        break;
      case LogType.Exception:
        Debug.LogException(new Exception(message));
        break;
      default:
        throw new ArgumentOutOfRangeException(nameof(logType), logType, null);
    }
  }

}


使い方はログクラスのインスタンスを作成した後、

表示したい文字列を追加していって、任意のタイミングで表示メソッドを実行するだけ。

//ログクラスのインスタンス作成
var logger = new EditorLogger();

//ログの文字列追加(この時点ではログ表示はされない)    
logger.Add($"テストでログ追加");
logger.Add($"\n改行してもっとログ追加");
logger.Add($" + さらにログ追加");

//追加された文字列を一気にログ表示
logger.Print();


なお、エラーなど表示やログの削除、インスタンス無しでのログ表示も可能です。

//ログをエラーで表示
logger.Print(LogType.Error);
//追加したログを消す
logger.Clear();
//インスタンス生成せず直接ログ表示
EditorLogger.Print($"テストログ");


一応仕組みについても説明しておくと、メソッドは全てConditionalがついてるので、

無効化されるタイミングでは呼び出し元は何もせずともメソッドは実行されず、ログは表示されません。

指定した条件付きコンパイル シンボルが定義されていない場合、メソッド呼び出しまたは属性を無視するようコンパイラに指示します。


しかもConditionalは引数の評価もされないので、Add内での文字列生成も無かった事になります。

(なのでAdd外で文字列作って、Addで渡すのはダメ)