15
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【C#】シンプルなロガークラスを自作してみた

Last updated at Posted at 2019-07-07

自己紹介

はじめまして!非実在系PG女子の水無月 美玖(みなつき みく)です!
都心近郊で暮らしながら、お仕事でプログラムを書いたりしてます。
巷で#バーチャル高専女子というものが流行っている?らしいので、私みたいなジャンルのヒトがいてもいいのかなーということでアカウントの開設を行いました。
QiitaではC#やJava、git等の記事をメインで書いていこうかなーと考えてますので、なにとぞよろしくおねがいしますね。
Twitter: @miku_minatsuki

Logger

さて、みなさんはアプリケーションの『ログ出力』ってどうしてますか?
Microsoft.Build.Framework.Loggerを使う方もいれば、NLoglog4netを使う方もいらっしゃると思います。
私もしっかりしたアプリケーションを開発したりするときはNLogやlog4netを使うのですが、
ちょっとしたAPIのテストだったり、小さなアプリケーションを作る際にそこまでしっかりした造りのロガーじゃなくてもいいなー…って思うことが多々あります。
わざわざ設定ファイル作ったりするほどじゃないけど、一応日時の出力やログレベルくらいは欲しい…。

実際、ロガーがやっているお仕事って、メソッドが呼ばれたときにファイルに文字列を書き込んでるだけなんですよね。
たったそれくらいであれば、機能を絞ってシンプルなのを自作してみてもいいんじゃないかな?って思いまして。
しばらく前に作ったのですが、この度公開してみようと思います。

コード

特に複雑なこともしていないので、ファイル1つで十分でした。

Logger.cs
using System;
using System.IO;
using System.Text;

public class Logger
{
    private static readonly string LOG_FORMAT = "{0} {1} {2}";
    private static readonly string DATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss.fff";
    private StreamWriter stream = null;
    private readonly bool consoleOut;

    private static Logger singletonInstance = null;
    public static Logger GetInstance(string logFilePath, bool consoleOut = false)
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Logger(logFilePath, consoleOut);
        }
        return singletonInstance;
    }

    public static void Init(string logFilePath, bool consoleOut = false)
    {
        singletonInstance = new Logger(logFilePath, consoleOut);
    }

    private Logger(string logFilePath, bool consoleOut)
    {
        if (string.IsNullOrWhiteSpace(logFilePath))
        {
            throw new Exception("logFilePath is empty.");
        }

        var logFile = new FileInfo(logFilePath);
        if (!Directory.Exists(logFile.DirectoryName))
        {
            Directory.CreateDirectory(logFile.DirectoryName);
        }

        stream = new StreamWriter(logFile.FullName, true, Encoding.Default);
        stream.AutoFlush = true;
        this.consoleOut = consoleOut;
    }

    private void write(Level level, string text)
    {
        string log = string.Format(LOG_FORMAT, DateTime.Now.ToString(DATETIME_FORMAT), level.ToString(), text);
        stream.WriteLine(log);
        if (consoleOut)
        {
            Console.WriteLine(log);
        }
    }

    public void Error(string text)
    {
        write(Level.ERROR, text);
    }

    public void Error(Exception ex)
    {
        write(Level.ERROR, ex.Message + Environment.NewLine + ex.StackTrace);
    }

    public void Error(string format, object arg)
    {
        Error(string.Format(format, arg));
    }

    public void Error(string format, params object[] args)
    {
        Error(string.Format(format, args));
    }

    public void Warn(string text)
    {
        write(Level.WARN, text);
    }

    public void Warn(string format, object arg)
    {
        Warn(string.Format(format, arg));
    }

    public void Warn(string format, params object[] args)
    {
        Warn(string.Format(format, args));
    }

    public void Info(string text)
    {
        write(Level.INFO, text);
    }

    public void Info(string format, object arg)
    {
        Info(string.Format(format, arg));
    }

    public void Info(string format, params object[] args)
    {
        Info(string.Format(format, args));
    }

    public void Debug(string text)
    {
        write(Level.DEBUG, text);
    }

    public void Debug(string format, object arg)
    {
        Debug(string.Format(format, arg));
    }

    public void Debug(string format, params object[] args)
    {
        Debug(string.Format(format, args));
    }

    public void Trace(string text)
    {
        write(Level.TRACE, text);
    }

    public void Trace(string format, object arg)
    {
        Trace(string.Format(format, arg));
    }

    public void Trace(string format, params object[] args)
    {
        Trace(string.Format(format, args));
    }

    private enum Level
    {
        ERROR,
        WARN,
        INFO,
        DEBUG,
        TRACE
    }
}

使い方

使い方は至ってシンプルですが、2通りの使い方があります。
どちらもシングルトンインスタンスを初期化し、それを取得してログ出力メソッドを呼び出すという点は変わりません。

Program.csでのみ使う場合

  1. Logger.csをプロジェクトに導入する
  2. Program.csでフィールドとしてprivate static Logger log = Logger.GetInstance(logFilePath, consoleOut);を宣言。
     logFilePathは絶対パスでも相対パスでもok。
     consoleOutは記述しなければfalseとなり、コンソールへの出力はされない。必要に応じてtrueを渡す。
  3. log.Error();なりlog.Info();なりご自由に

複数のクラスから呼び出す場合(普通のプロジェクトで使う場合)

  1. Logger.csをプロジェクトに導入する
  2. Mainメソッド内でLogger.init(logFilePath, consoleOut)を呼び出す。
     logFilePathは絶対パスでも相対パスでもok。
     consoleOutは記述しなければfalseとなり、コンソールへの出力はされない。必要に応じてtrueを渡す。
  3. 使いたいクラス内で、フィールドとしてprivate static Logger log = Logger.GetInstance();を宣言。
  4. log.Error();なりlog.Info();なりご自由に

使用例

たとえば、こんなProgram.csがあったとします。

Program.cs
using System;
using System.Diagnostics;
using System.Threading;

namespace Test
{
    public class Program
    {
        private static Logger log = Logger.GetInstance("calc.log", true);

        static void Main(string[] args)
        {
            var sw = new Stopwatch();
            log.Info("Start to calculation.");
            sw.Start();

            int result = 0;
            var rand = new Random();
            for (int i = 0; i < 10; i++)
            {
                int add = rand.Next(1, 1000000);
                result += add;
                log.Debug("add: {0}, result: {1}", add, result);
                Thread.Sleep(100);
            }

            sw.Stop();
            log.Info("Finished to process. result: {0}, time: {1}ms", result, sw.ElapsedMilliseconds);
        }
    }
}

このProgram.csを実行してできあがるのが、以下のcalc.logです。

calc.log
2019/07/07 23:25:44.942 INFO Start to calculation.
2019/07/07 23:25:44.945 DEBUG add: 849335, result: 849335
2019/07/07 23:25:45.046 DEBUG add: 817967, result: 1667302
2019/07/07 23:25:45.148 DEBUG add: 709783, result: 2377085
2019/07/07 23:25:45.249 DEBUG add: 945058, result: 3322143
2019/07/07 23:25:45.350 DEBUG add: 76153, result: 3398296
2019/07/07 23:25:45.451 DEBUG add: 519537, result: 3917833
2019/07/07 23:25:45.551 DEBUG add: 140003, result: 4057836
2019/07/07 23:25:45.652 DEBUG add: 555771, result: 4613607
2019/07/07 23:25:45.753 DEBUG add: 604428, result: 5218035
2019/07/07 23:25:45.853 DEBUG add: 687503, result: 5905538
2019/07/07 23:25:45.954 INFO Finished to process. result: 5905538, time: 1009ms

おわりに

ロガークラスの自作って、けっこういろんな方がされていると思います。
私の書き方が絶対ってことはないですし、もっと便利に作ってる方はたくさんいらっしゃるハズです。
今回は私自身の勉強も兼ねて自作してみましたが、広く公開するようなアプリケーションを作る場合はNLogやlog4netのように、設定ファイルによって様々な設定ができるロガーを使うほうが良いでしょう。
でも私みたいに(設定ファイル作るの面倒だなー…)って思っても許される程度の規模での開発なら、今回作ったLoggerクラスくらいのものでも十分に役割を果たせるのではないかと!

何かありましたら、お気軽にコメントしてくださいね。
Twitterでのフォロー等もお待ちしております|ω・)

15
24
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?