[C#] log4netで呼び出し元のクラス・メソッド名をスタックトレースから取得するのはダメでCallerMemberName属性を使うべき

ILog取得する時にいちいちメソッド名とか指定するのがメンドイじゃん?

スタックトレースからメソッド名持ってこればいいよね? これって問題ある?Flyweightになっててメモリ食うか?

// この方法はダメダメです。CallerMemberName属性を使いましょう!
private static ILog GetLogger()
{
  MethodBase m = (new StackTrace(false)).GetFrame(2).GetMethod();
  return LogManager.GetLogger(m.DeclaringType.Name + '.' + m.Name);
}

public static void InfoFormat(string format, params object[] args)
{
  GetLogger().InfoFormat(format, args);
}

…で、その後、この方法はダメだったことが判明 ↓

StackFrameは使うな。CallerMemberName属性を使え。

上記のStackTraceを使う方法はいろいろとダメだった。 まずStackTraceではなくStackFrameを直接取得した方がいいという点。 場合によってはStackFrameが取得できないことがあるという点。

参考: C# メソッドの呼び出し元メソッド名を取得するおまじない - Qiita

なので、System.Runtime.CompilerServices.CallerMemberNameAttribute を使ってコンパイル時にメソッド名を埋め込んでもらうようにした方がいい。 これだと可変長引数が使えないけど…使えないからといってさほど不便ではないはず。

// CallerMemberName属性を付けると
// コンパイル時にメソッド名に置き換えてくれる
public void TraceDebug(string text, [CallerMemberName] string name = "")
{
  log4net.LogManager.GetLogger(name).Debug(text);
}

SkipFrameを使う場合は null チェックを入れておこう

var stackFrame = new StackFrame(skipFrames, false);
if (stackFrame != null)
{
  var m = stackFrame.GetMethod();
  return LogManager.GetLogger(m.DeclaringType.Name + '.' + m.Name);
}
else
{
  return LogManager.GetLogger("StackFrame取れない場合の代わりを入れて");
}
Share
関連記事