5

私はルビー標準ロガーを使用しています。毎日ローテーションしたいので、私のコードでは次のようにしています:

Logger.new("#{$ROOT_PATH}/log/errors.log", 'daily')  

完全に機能していますが、2 つのファイルerrors.log.20130217errors.log.20130217.1.

1日に1つのファイルだけを強制的に作成するにはどうすればよいですか?

4

1 に答える 1

11

あなたのコードは、長時間実行されるアプリケーションに対して正しいです。

何が起こっているかというと、特定の日にコードを複数回実行しているということです。

初めて実行すると、Ruby はログ ファイル「errors.log」を作成します。

日が変わると、Ruby はファイルの名前を「errors.log.20130217」に変更します。

しかし、何らかの理由でコードを再度実行した場合、おそらく、同様のコードを使用する 2 つのアプリ (またはプロセス、ワーカー、またはスレッド) を実行しており、ロガーはファイル名 "errors.log.20130217" が既に存在することを確認しました。

ロガーはそのファイルを壊したくありませんでしたが、「errors.log」の名前を日付に変更する必要があったため、ロガーは代わりに別のファイル名「errors.log.20130217.1」を作成しました。

これを解決するには、コードを 1 回だけ実行します。

「foo」と「bar」という複数のアプリを実行している場合は、「foo-errors.log」や「bar-errors.log」などのログ ファイル名を使用します。または、複数のワーカーを使用している場合は、各ワーカーに独自のログ ファイル名を付けます (たとえば、ワーカーのプロセス ID またはワーカー プールの配列インデックスを使用するか、ワーカーを追跡します)。

本当に Ruby ロガーを使用してこれを解決したい場合は、ロガー #shift_log_period をオーバーライドして、".1" サフィックスを選択しないようにする必要があります。Logger をサブクラス化し、着用した #shift_log_period を記述して、その日付の既存のログ ファイルがあることを検出し、存在する場合は、ファイルの名前を変更する代わりにそれを使用できます。

これは、ロガーからそれを引き起こしているコードです:

def shift_log_period(period_end)
  postfix = period_end.strftime("%Y%m%d") # YYYYMMDD
  age_file = "#{@filename}.#{postfix}"
  if FileTest.exist?(age_file)
    # try to avoid filename crash caused by Timestamp change.
    idx = 0
    # .99 can be overridden; avoid too much file search with 'loop do'
    while idx < 100
      idx += 1
      age_file = "#{@filename}.#{postfix}.#{idx}"
      break unless FileTest.exist?(age_file)
    end
  end
  @dev.close rescue nil
  File.rename("#{@filename}", age_file)
  @dev = create_logfile(@filename)
  return true

複数のアプリ(別名ワーカー、プロセス、スレッド)によって同時に書き込まれたログを管理するために、ローテーターが組み込まれたRubyロガーを使用するソリューション(AFAIK)はありません。これは、各アプリが独自のログ ファイル ハンドルを取得するためです。

または、質問のコメントで Tin Man ユーザーが提案した logrotate などの優れたログ ローテーター ツールを使用します: http://linuxcommand.org/man_pages/logrotate8.html

一般に、logrotate が最善の策です。

于 2013-02-18T08:58:52.053 に答える