logger
Android loggerからインスパイアされた美しいログを出力する小さく使いやすく拡張可能なDart/Flutterロギングパッケージ。trace、debug、info、warning、error、fatalレベルをサポート。デバッグモードでは設定レベル以上のログを表示、リリースモードでは全ログを省略。
ライブラリ
Logger (Standard Library)
概要
Logger (Standard Library)は「Ruby標準ライブラリのロギング機能」として、外部依存関係なしで基本的なロギング機能を提供するシンプルで信頼性の高いログソリューションです。ログレベル制御、ファイルローテーション、カスタムフォーマッターをサポートし、小規模なRubyアプリケーションやスクリプトでの日常的なロギング要件に対応。5つのログレベル(DEBUG、INFO、WARN、ERROR、FATAL)による詳細な出力制御と、プログラム名指定による識別機能を提供します。
詳細
Ruby標準Loggerは2025年でも小規模プロジェクトや学習用途での継続的な価値を持つ実用的な選択肢です。外部gemへの依存なしに即座に利用可能で、サイズベースとタイムベースの両方のログローテーション機能を内蔵。カスタムフォーマッター定義により柔軟な出力形式カスタマイズが可能で、日時フォーマット指定、プログラム名設定、複数の出力先指定など基本的なログ管理機能を網羅しています。シンプルな要件に十分対応できるものの、本格的なWebアプリケーションやRailsプロジェクトではより高機能なライブラリへの移行が推奨される現状です。
主な特徴
- 標準ライブラリ: 外部依存なしで即座に利用可能
- 5つのログレベル: DEBUG、INFO、WARN、ERROR、FATALによる詳細制御
- ログローテーション: サイズベース・タイムベース両方をサポート
- カスタムフォーマッター: Procによる柔軟な出力形式カスタマイズ
- 複数出力先: ファイル、STDOUT、IOストリーム対応
- プログラム名設定: ログエントリの識別機能
メリット・デメリット
メリット
- 外部依存関係なしで即座に利用開始可能なゼロセットアップ環境
- Ruby標準ライブラリとしての長期サポートと安定性保証
- サイズベース・タイムベース両方のログローテーション機能内蔵
- Procベースのカスタムフォーマッターによる柔軟な出力制御
- 複数出力先(ファイル、STDOUT、ストリーム)への同時出力可能
- 学習コストが低く、Rubyの基本概念のみで理解可能
デメリット
- 構造化ログやJSON出力などのモダンなログ形式に対応不足
- 高性能要件やマルチプロセス環境での機能制約
- 本格的なWebアプリケーションでは機能不足
- ログレベル別の出力先分散や高度なフィルタリング機能の欠如
- サードパーティサービスとの統合機能なし
- エンタープライズレベルの監査・セキュリティ要件への対応不足
参考ページ
書き方の例
インストールとセットアップ
# Loggerは標準ライブラリのため、requireのみで利用可能
require 'logger'
# 基本的なロガー作成(STDOUT出力)
logger = Logger.new(STDOUT)
# ファイル出力用ロガー
logger = Logger.new('application.log')
# IOストリーム指定
logger = Logger.new($stdout)
# プログラム名付きロガー
logger = Logger.new(STDOUT, progname: 'MyApp')
# バージョン確認
puts "Ruby Version: #{RUBY_VERSION}"
puts "Logger available: #{defined?(Logger) ? 'Yes' : 'No'}"
基本的なロギング(レベル別メッセージ出力)
require 'logger'
# 基本ロガー設定
logger = Logger.new(STDOUT)
logger.level = Logger::DEBUG
# 5つのログレベルでのメッセージ出力
logger.debug("デバッグ情報:詳細な実行トレース")
logger.info("情報:アプリケーション開始")
logger.warn("警告:非推奨メソッドの使用")
logger.error("エラー:処理中に問題が発生")
logger.fatal("致命的:システム停止レベルの問題")
# ログレベル設定による出力制御
logger.level = Logger::WARN
logger.debug("このメッセージは出力されません")
logger.info("このメッセージも出力されません")
logger.warn("このメッセージは出力されます")
# プログラム名付きロギング
logger.progname = 'UserService'
logger.info("ユーザー認証処理開始")
# ブロック形式でのロギング(遅延評価)
logger.debug { "重い処理の結果: #{expensive_calculation}" }
# ログレベル確認
logger.debug? && logger.debug("デバッグレベルが有効です")
ログレベル制御とフィルタリング
require 'logger'
# 基本的なログレベル設定
logger = Logger.new('application.log')
# ログレベル設定の各種方法
logger.level = Logger::INFO
logger.level = Logger::DEBUG
logger.level = Logger::WARN
logger.level = Logger::ERROR
logger.level = Logger::FATAL
# 数値での設定も可能
logger.level = 2 # Logger::WARN相当
# 環境変数からのログレベル設定
log_level = ENV['RUBY_LOG_LEVEL'] || 'INFO'
logger.level = Logger.const_get(log_level)
# ログレベル判定メソッド
def log_with_level_check(logger)
logger.debug? && logger.debug("デバッグレベル有効")
logger.info? && logger.info("インフォレベル有効")
logger.warn? && logger.warn("警告レベル有効")
logger.error? && logger.error("エラーレベル有効")
logger.fatal? && logger.fatal("致命的レベル有効")
end
# 環境別ログレベル設定
case ENV['RAILS_ENV']
when 'development'
logger.level = Logger::DEBUG
when 'test'
logger.level = Logger::WARN
when 'production'
logger.level = Logger::ERROR
else
logger.level = Logger::INFO
end
# ログレベル表示
puts "現在のログレベル: #{logger.level}"
puts "ログレベル名: #{%w[DEBUG INFO WARN ERROR FATAL UNKNOWN][logger.level]}"
ログローテーションと出力先管理
require 'logger'
# サイズベースローテーション(3ファイル、10MB制限)
logger = Logger.new('application.log', 3, 10485760)
# タイムベースローテーション(日次ローテーション)
logger = Logger.new('daily.log', 'daily')
logger = Logger.new('weekly.log', 'weekly')
logger = Logger.new('monthly.log', 'monthly')
# 複数の出力先管理クラス
class MultiLogger
def initialize(*loggers)
@loggers = loggers
end
def info(message)
@loggers.each { |logger| logger.info(message) }
end
def error(message)
@loggers.each { |logger| logger.error(message) }
end
def warn(message)
@loggers.each { |logger| logger.warn(message) }
end
end
# 複数ロガーの使用例
file_logger = Logger.new('application.log')
console_logger = Logger.new(STDOUT)
error_logger = Logger.new('error.log')
multi_logger = MultiLogger.new(file_logger, console_logger)
multi_logger.info("全ロガーに出力されるメッセージ")
# 条件付きログローテーション
class ConditionalRotationLogger
def initialize(filename, max_size = 1048576) # 1MB
@filename = filename
@max_size = max_size
@logger = create_logger
end
def rotate_if_needed
if File.exist?(@filename) && File.size(@filename) > @max_size
backup_name = "#{@filename}.#{Time.now.strftime('%Y%m%d_%H%M%S')}"
File.rename(@filename, backup_name)
@logger = create_logger
end
end
def info(message)
rotate_if_needed
@logger.info(message)
end
private
def create_logger
Logger.new(@filename)
end
end
# 使用例
rotating_logger = ConditionalRotationLogger.new('app.log')
rotating_logger.info("ローテーション対応ログメッセージ")
カスタムフォーマッターとレイアウト設定
require 'logger'
# カスタムフォーマッター作成
logger = Logger.new(STDOUT)
# シンプルなカスタムフォーマッター
logger.formatter = proc do |severity, datetime, progname, msg|
"#{datetime}: #{severity} - #{msg}\n"
end
# 詳細なカスタムフォーマッター
logger.formatter = proc do |severity, datetime, progname, msg|
date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
"[#{date_format}] #{severity.ljust(5)} #{progname}: #{msg}\n"
end
# JSON風フォーマッター
logger.formatter = proc do |severity, datetime, progname, msg|
{
timestamp: datetime.iso8601,
level: severity,
program: progname,
message: msg
}.to_json + "\n"
end
# カラー付きフォーマッター(ターミナル用)
class ColorFormatter
COLORS = {
'DEBUG' => "\033[36m", # シアン
'INFO' => "\033[32m", # グリーン
'WARN' => "\033[33m", # イエロー
'ERROR' => "\033[31m", # レッド
'FATAL' => "\033[35m" # マゼンタ
}.freeze
RESET = "\033[0m".freeze
def call(severity, datetime, progname, msg)
color = COLORS[severity] || ''
"#{color}[#{datetime.strftime('%H:%M:%S')}] #{severity}: #{msg}#{RESET}\n"
end
end
logger.formatter = ColorFormatter.new
# 日時フォーマットカスタマイズ
logger.datetime_format = '%Y-%m-%d %H:%M:%S'
# プログラム名を含むフォーマッター
logger.progname = 'MyApp'
logger.formatter = proc do |severity, datetime, progname, msg|
"[#{progname}] #{datetime.strftime('%H:%M:%S')} #{severity}: #{msg}\n"
end
# ログテスト
logger.debug("デバッグメッセージ")
logger.info("情報メッセージ")
logger.warn("警告メッセージ")
logger.error("エラーメッセージ")
エラーハンドリングとログ管理
require 'logger'
# 安全なロガー作成関数
def create_safe_logger(filename, level = Logger::INFO)
begin
logger = Logger.new(filename)
logger.level = level
logger.info("ログファイル初期化完了: #{filename}")
logger
rescue StandardError => e
fallback_logger = Logger.new(STDERR)
fallback_logger.error("ログファイル作成失敗 (#{filename}): #{e.message}")
fallback_logger
end
end
# 例外ログ出力の標準パターン
def log_exception(logger, exception, context = '')
logger.error "#{context}例外が発生: #{exception.class}: #{exception.message}"
logger.error "バックトレース:"
exception.backtrace.each { |line| logger.error " #{line}" }
end
# ログレベル別の例外処理
class ApplicationLogger
def initialize(filename = 'application.log')
@logger = create_safe_logger(filename)
end
def log_with_exception_handling(level, message)
begin
@logger.send(level, message)
rescue StandardError => e
STDERR.puts "ログ出力エラー: #{e.message}"
end
end
def safe_info(message)
log_with_exception_handling(:info, message)
end
def safe_error(message)
log_with_exception_handling(:error, message)
end
def log_method_execution(method_name)
start_time = Time.now
@logger.debug("メソッド開始: #{method_name}")
begin
result = yield
duration = Time.now - start_time
@logger.info("メソッド完了: #{method_name} (#{duration.round(3)}秒)")
result
rescue StandardError => e
duration = Time.now - start_time
@logger.error("メソッド失敗: #{method_name} (#{duration.round(3)}秒)")
log_exception(@logger, e, "#{method_name}で")
raise
end
end
end
# 使用例
app_logger = ApplicationLogger.new
begin
app_logger.log_method_execution('data_processing') do
# 何らかの処理
raise "テスト例外" if rand(2) == 0
"処理完了"
end
rescue StandardError => e
app_logger.safe_error("アプリケーションレベルでの例外キャッチ: #{e.message}")
end
# ログファイルアクセス権限チェック
def check_log_permissions(filename)
logger = Logger.new(STDERR)
begin
test_logger = Logger.new(filename)
test_logger.info("権限テスト")
test_logger.close
logger.info("ログファイル権限OK: #{filename}")
true
rescue StandardError => e
logger.error("ログファイル権限エラー (#{filename}): #{e.message}")
false
end
end
# システム情報ログ
def log_system_info(logger)
logger.info("Ruby Version: #{RUBY_VERSION}")
logger.info("Platform: #{RUBY_PLATFORM}")
logger.info("Process ID: #{Process.pid}")
logger.info("Logger Level: #{logger.level}")
end
# 実行例
system_logger = create_safe_logger('system.log')
log_system_info(system_logger)
実用的なアプリケーション統合
require 'logger'
require 'fileutils'
# アプリケーション用ロガークラス
class ApplicationLogger
DEFAULT_LOG_DIR = 'log'.freeze
DEFAULT_LOG_LEVEL = Logger::INFO
def initialize(app_name, log_dir = DEFAULT_LOG_DIR)
@app_name = app_name
@log_dir = log_dir
ensure_log_directory
@logger = create_logger
setup_formatter
log_startup_info
end
def debug(message); @logger.debug(format_message(message)); end
def info(message); @logger.info(format_message(message)); end
def warn(message); @logger.warn(format_message(message)); end
def error(message); @logger.error(format_message(message)); end
def fatal(message); @logger.fatal(format_message(message)); end
def log_performance(operation_name)
start_time = Time.now
info("開始: #{operation_name}")
begin
result = yield
duration = Time.now - start_time
info("完了: #{operation_name} (#{duration.round(3)}秒)")
result
rescue StandardError => e
duration = Time.now - start_time
error("失敗: #{operation_name} (#{duration.round(3)}秒): #{e.message}")
raise
end
end
def close
info("ログシステム停止")
@logger.close if @logger.respond_to?(:close)
end
private
def ensure_log_directory
FileUtils.mkdir_p(@log_dir) unless Dir.exist?(@log_dir)
end
def create_logger
log_file = File.join(@log_dir, "#{@app_name}.log")
Logger.new(log_file, 'daily')
end
def setup_formatter
@logger.formatter = proc do |severity, datetime, progname, msg|
"[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{severity.ljust(5)} [#{@app_name}] #{msg}\n"
end
end
def format_message(message)
"[PID:#{Process.pid}] #{message}"
end
def log_startup_info
info("=== #{@app_name} 開始 ===")
info("Ruby Version: #{RUBY_VERSION}")
info("Log Level: #{@logger.level}")
info("Log File: #{@log_dir}/#{@app_name}.log")
end
end
# 設定管理クラス
class LogConfig
def self.setup_from_env
{
level: log_level_from_env,
app_name: ENV['APP_NAME'] || 'MyApp',
log_dir: ENV['LOG_DIR'] || 'log'
}
end
def self.log_level_from_env
level_name = ENV['LOG_LEVEL'] || 'INFO'
Logger.const_get(level_name.upcase)
rescue NameError
Logger::INFO
end
end
# 使用例
begin
config = LogConfig.setup_from_env
logger = ApplicationLogger.new(config[:app_name], config[:log_dir])
logger.info("設定読み込み完了")
# 実際のアプリケーション処理
logger.log_performance('データベース初期化') do
sleep(0.1) # 実際の初期化処理の代わり
"DB接続完了"
end
logger.log_performance('ユーザーデータ処理') do
# 何らかの処理
100.times do |i|
logger.debug("処理中: #{i+1}/100") if (i+1) % 10 == 0
end
"処理完了"
end
ensure
logger&.close
end
# シングルトンロガーパターン
class GlobalLogger
@@instance = nil
def self.instance
@@instance ||= ApplicationLogger.new('global')
end
def self.method_missing(method, *args)
instance.send(method, *args)
end
end
# グローバルロガーの使用
GlobalLogger.info("グローバルロガーメッセージ")
GlobalLogger.warn("グローバル警告")