Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyのLoggerクラスでログを出力する方法!イベントとエラーメッセージの追跡ガイド

ロギング(ログ出力)とは、Rubyアプリケーションが現在何をしているのかという情報を記録・保存する仕組みのことです。

開発環境でも本番環境でも非常に役立つ機能で、ロギングの最大の目的は「何が起きたのか」「どこで問題が発生したのか」「何がうまくいったのか」という情報を収集することにあります。

ログに記録できる情報の例

  • 遅いSQLクエリ(ボトルネックを発見して修正するため)
  • エラーメッセージ
  • 詳細なリクエスト情報(URL、コントローラー、パラメータ、ビューなど)

こうした情報があれば、アプリケーションの問題を素早く診断し、原因を特定できるようになります。

Railsアプリの場合、ログは /log フォルダ配下に保存されます。開発モードでは development.log ファイルが使用され、rails server を実行しているターミナルにもリアルタイムでログが出力されます。

それでは、Ruby標準の Logger クラスを使ってロギングを行う方法を詳しく見ていきましょう。

Loggerクラスの基本

Rubyの Logger クラスを使えば、デフォルトの出力形式と複数の重要度レベルを持つログを簡単に生成できます。

ログファイルを作成する基本のコード

logger = Logger.new("my_log.txt")

このコードを実行すると、ログメッセージが my_log.txt に書き込まれます。

プログラムを実行しているターミナル上に直接メッセージを表示したい場合は、STDOUT を指定します。

logger = Logger.new(STDOUT)

ログレベルの種類と使い方

ログメッセージには、内容の重要度に応じて異なるレベルを設定できます。

用意されているレベルは以下の6つ

  • DEBUG — デバッグ用の詳細情報
  • INFO — 通常の動作情報
  • WARN — 警告
  • ERROR — エラー
  • FATAL — 致命的なエラー
  • UNKNOWN — 不明なメッセージ

各レベルには対応するインスタンスメソッドが用意されています。たとえば「info」レベルでログを記録したい場合は、次のように書きます。

logger.info("ロギングについてのガイドを読んでいます!")

実際に出力されるログエントリはこのようになります

# I, [2019-08-08T19:22:00.152079 #642]  INFO -- : ロギングについてのガイドを読んでいます!

ログレベルを適切に使い分けることで、ログファイルのフィルタリングが容易になり、目的の情報へすばやくアクセスできるようになります。また、時間の経過とともにどれだけのエラーや警告が発生しているかを把握するのにも役立ちます。

ログのフォーマットをカスタマイズする方法

Rubyのログはデフォルトの出力形式を使うのがおすすめです。多くの解析ツールがこの形式を前提として作られており、チームメンバーにとっても読みやすいためです。

もう一度ログ行を見てみましょう

# I, [2019-08-08T19:22:00.152079 #642]  INFO -- : test

この1行は以下の要素で構成されています

  • 先頭の「I」は重要度レベル(INFO)の頭文字
  • 角括弧内にはタイムスタンプと、このログを生成したプロセスID(PID)
  • 「INFO」は重要度レベルの正式名称
  • コロンの後には、実際に記録されたメッセージ本体

ただし、このフォーマットがすべてのケースに最適とは限りません。そんなときは、Rubyの機能を使って自由に変更できます。

formatterを設定するコード例

logger.formatter = proc { |severity, datetime, progname, msg| "#{severity}, #{datetime}, #{msg}\n" }

この設定での出力結果

DEBUG, 2019-08-08 19:39:01 +0200, testing

この仕組みを利用すれば、自分やチームにとって有用な追加情報(ユーザーIDやリクエストIDなど)をログに含めることも可能です。

ログファイルのサイズを制限する方法

ログは放置すると際限なく大きくなります。ログが原因でディスク容量を使い果たすと、システム全体で予期しない不具合が多発しかねません。

解決策はログのサイズ上限を設定することです。

MEGABYTE = 1024 ** 2
ONE_HUNDRED_MEGABYTES = MEGABYTE * 100

logger = Logger.new("my_log.txt", 1, ONE_HUNDRED_MEGABYTES)

各引数の意味

  • 第1引数:ログメッセージの保存先ファイル
  • 第2引数:保持するログファイルの世代数(ログローテーションの設定)
  • 第3引数:ログファイルの最大サイズ

この設定により、指定したサイズを超えると古いログが自動的にローテーションされ、ディスク容量を圧迫しなくなります。

ログの読み方とフィルタリング

ログが出力できたら、次は必要な情報を効率よく取り出す方法です。

ログはプレーンテキストファイルなので、任意のテキスト処理ツールを使って解析できます。

代表的なツールがgrepです。テキストファイルを条件で絞り込めるコマンドラインツールで、次のように使います。

grep INFO my_log.txt

このコマンドで、「INFO」レベルとして記録されたすべての行を抽出できます。「INFO」の部分を任意のキーワードに置き換えれば、ログ内の他のテキストも同様に検索可能です。

もうひとつ便利なUnixツールが less-R オプション付き)です。キーボード操作だけでログをスクロールして閲覧でき、検索機能も備えています。

さらに、ログ管理・検索に特化した専用ツールを使う選択肢もあります。たとえばDiscourseが公開している logster gemなどが有名です。

まとめ

この記事では、Rubyにおけるロギングの概要、Logger クラスの基本的な使い方、ログレベルの使い分け、フォーマットのカスタマイズ、ログローテーションによるサイズ制限、そしてgrepやlessを使ったログの検索方法までを解説しました。

ぜひ実際のプロジェクトで試してみてください。最後までお読みいただきありがとうございました!

  1. RubyのStructとOpenStructの使い方を徹底解説!値オブジェクトを簡単に作る方法

    Rubyには、関連する属性をまとめて保持する「値オブジェクト」を手軽に作れるStructという組み込みクラスが用意されています。本記事では、Structの基本的な使い方から注意点、そしてOpenStructとの違いまで詳しく解説します。 そもそもStructとは何か? StructはRubyに組み込まれたクラスで、新しいクラスを動的に生成し、値オブジェクト(Value Object)を作成するために使われます。値オブジェクトとは、関連性のある複数の属性をひとまとめにして扱うためのオブジェクトです。 具体例を挙げてみましょう。 2つの座標(xとy)を持つPointというデータを表したい場合、この

  2. Rubyプログラムのデバッグと修正方法を徹底解説|スタックトレースの読み方からPry・Byebugまで

    書いたプログラムが、初回実行で思い通りに動くことってどれくらいありますか? 多くの場合、プログラムは期待どおりには動いてくれないもの。そんなときに頼りになるのがRubyのデバッグという技術です。原因を突き止めるための頼れる相棒といえるでしょう。 次のようなエラーメッセージを見たことはありませんか? undefined method some_method for nil:NilClass これは、nil値がコードの中に紛れ込んでしまったことを意味します。 本記事で紹介するテクニックを身につければ、この問題や似たようなトラブルにも自信を持って対処できるようになりますよ! エラーとスタックトレース