CATEGORY

Logger (独自ログ出力)

[C#][.NET] Logger (独自ログ出力)

※ 当サイトは広告を含みます。

C#でログを出力する独自コードです。コピペできるように置いておきます。
ライブラリに依存したくないとか、そもそも簡易機能で十分って人はどうぞ。

ソースコード


using System;

namespace ConsoleApp
{
  public class Logger
  {
    public enum LogLevelEnumeration
    {
      All,
      Trace,
      Info,
      Warn,
      Error,
      Fatal,
    }

    public static Logger Instance { get; } = new();

    private readonly object lockObject = new();

    public string DirectoryPath
    {
      get
      {
        var current = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? string.Empty;

        var now = DateTime.Now;

        var path = System.IO.Path.Combine(
          current,
          "Logs",
          $"{now:yyyyMMdd}"
        );

        return path;
      }
    }

    private Logger()
    {
    }

    public void Write(LogLevelEnumeration level, string? type, string? message)
    {
      this.Write(level, type, message, null);
    }

    public void Write(LogLevelEnumeration level, string? type, string? message, string? split)
    {
      lock (this.lockObject)
      {
        var app = System.Reflection.Assembly.GetEntryAssembly()?.GetName()?.Name;
        var now = DateTime.Now;
        var output = $"[{now:yyyy/MM/dd HH:mm:ss.fff}][{level}][{type}] {message}";

        var logFilePath = System.IO.Path.Combine(
          this.DirectoryPath,
          string.IsNullOrEmpty(split) ? $"{app}.log" : $"{app}.{split}.log"
        );

        var directoryName = System.IO.Path.GetDirectoryName(logFilePath);
        if (directoryName is null)
          return;

        System.IO.Directory.CreateDirectory(directoryName);
        using (var stream = new System.IO.StreamWriter(logFilePath, true))
          stream.WriteLine(output);
      }
    }

    public void Write(LogLevelEnumeration level, string? type, Exception exception)
    {
      this.Write(level, type, exception, null);
    }

    public void Write(LogLevelEnumeration level, string? type, Exception exception, string? split)
    {
      #region LocalMethod
      static List<string> __ExceptionMessage(Exception e)
      {
        var list = new List<string>();

        if (e is null)
          return list;

        list.Add($" Type={e.GetType()}");
        list.Add($" Object={e.Source ?? "null"}");
        list.Add($" Method={e.TargetSite?.ToString() ?? "null"}");
        list.Add($" StackTrace={e.StackTrace ?? "null"}");
        list.Add($" HResult={e.HResult.ToString() ?? "null"}");
        list.Add($" Message={e.Message ?? "null"}");

        foreach (var key in e.Data.Keys)
          list.Add($" Data[{key}]={e.Data[key]?.ToString() ?? "null"}");

        list.Add($" HelpLink={e.HelpLink ?? "null"}");

        return list;
      }
      #endregion

      var messages = new List<string>();

      messages.Add("Exception");
      messages.AddRange(
        __ExceptionMessage(exception)
      );

      var innerException = exception.InnerException;
      while (innerException is not null)
      {
        messages.Add("InnerException");
        messages.AddRange(
          __ExceptionMessage(innerException)
        );

        innerException = innerException.InnerException;
      }

      this.Write(level, type, messages, split);
    }

    public void Write(LogLevelEnumeration level, string? type, List<string> messages)
    {
      this.Write(level, type, messages.ToArray(), null);
    }

    public void Write(LogLevelEnumeration level, string? type, List<string> messages, string? split)
    {
      this.Write(level, type, messages.ToArray(), split);
    }

    public void Write(LogLevelEnumeration level, string? type, string[] messages)
    {
      this.Write(level, type, messages, null);
    }

    public void Write(LogLevelEnumeration level, string? type, string[] messages, string? split)
    {
      lock (this.lockObject)
      {
        var app = System.Reflection.Assembly.GetEntryAssembly()?.GetName()?.Name;
        var now = DateTime.Now;

        var output = new System.Text.StringBuilder();
        output.AppendLine($"[{now:yyyy/MM/dd HH:mm:ss.fff}][{level}][{type}]");

        foreach (var message in messages)
          output.AppendLine(message);

        var logFilePath = System.IO.Path.Combine(
          this.DirectoryPath,
          string.IsNullOrEmpty(split) ? $"{app}.log" : $"{app}.{split}.log"
        );

        var directoryName = System.IO.Path.GetDirectoryName(logFilePath);
        if (directoryName is null)
          return;

        System.IO.Directory.CreateDirectory(directoryName);
        using (var stream = new System.IO.StreamWriter(logFilePath, true))
          stream.Write(output.ToString());
      }
    }
  }
}

使い方

この辺のメソッドが主機能。引数で文字列、文字列の配列、文字列のリスト、例外が指定できます。
splitはログを分割したい場合に使います。指定すると、その文字列を付加したファイルで出力されます。

後、シングルトン前提です。private解除すればインスタンス化できますが、出力パスが共通なので意味ないです。
ログは実行アプリと同階層に日付ディレクトリの単位で出力されます。変更したい場合はDirectoryPathの中身を修正すればOK。


Logger.Instance.Write(Logger.LogLevelEnumeration.Info, "ProcessLog", "Result");
Logger.Instance.Write(Logger.LogLevelEnumeration.Info, "ProcessLog", new string[] { "Result.A", "Result.B", "Result.C" });

try
{
  throw new Exception("crash!");
}
catch (Exception e)
{
  try
  {
    throw new Exception("_crash!", e);
  }
  catch (Exception ee)
  {
    Logger.Instance.Write(Logger.LogLevelEnumeration.Info, "ExceptionLog", ee);
  }
}

Logger.Instance.Write(Logger.LogLevelEnumeration.Info, "ProcessLog", "Result.Split", "Split");

GitHubhttps://github.com/Takemi392/Code.20250614.1420

あとがき

管理人
管理人

ログは大切。みんな自分用を持ってる説。

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。