5

我正在使用 ruby​​ 标准记录器,我想要每天轮换一次,所以在我的代码中我有:

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

它运行良好,但它创建了两个文件errors.log.20130217errors.log.20130217.1.

我怎样才能强制它每天只创建一个文件?

4

1 回答 1

11

您的代码对于长时间运行的应用程序是正确的。

发生的事情是您在某一天不止一次运行代码。

第一次运行它时,Ruby 会创建一个日志文件“errors.log”。

当日期改变时,Ruby 将文件重命名为“errors.log.20130217”。

但不知何故,您再次运行代码,也许您正在运行两个使用相似代码的应用程序(或进程、或工作程序或线程),并且您的记录器看到文件名“errors.log.20130217”已经存在。

您的记录器不想破坏该文件,但仍需要将“errors.log”重命名为日期,因此记录器创建了一个不同的文件名“errors.log.20130217.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

没有解决方案 (AFAIK) 使用 Ruby 记录器及其内置的旋转器来同时管理由多个应用程序(又名工作人员、进程、线程)写入的日志。这是因为每个应用程序都有自己的日志文件句柄。

或者,使用任何好的日志旋转器工具,例如 Tin Man 用户在问题评论中建议的 logrotate:http: //linuxcommand.org/man_pages/logrotate8.html

一般来说,logrotate 将是您最好的选择恕我直言。

于 2013-02-18T08:58:52.053 回答