0

我有一个可用的 Rails 3.2 应用程序(Windows Server 2008 R2 上的 Ruby 1.9.2p290),它对多个后台作业使用延迟作业。我最近用 log4r 替换了 Rails 默认日志记录,它在 Rails 应用程序中运行良好。但是,当我启动rake jobs:work任务时,我收到一个抱怨 nil 输出器的错误:

开始工作的工人
耙中止!
TypeError:预期的输出类型,得到 NilClass
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/log4r-1.1.10/lib/log4r/logger.rb:120:in `each'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/log4r-1.1.10/lib/log4r/logger.rb:120:in `add'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/delayed_job-4.0.0/lib/delayed/worker.rb:248:in `say'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/delayed_job-4.0.0/lib/delayed/worker.rb:147:in `start'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/delayed_job-4.0.0/lib/delayed/tasks.rb:9:in `block (2 levels) in '
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:240:in `call'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:240:in `block in execute'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:235:in `each'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:235:in `execute'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:179:in `block in invoke_with_call_chain'
F:/web-shared/Ruby192/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:172:in `invoke_with_call_chain'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:165:in `invoke'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:150:in `invoke_task'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:106:in `block (2 levels) in top_level
'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:106:in `each'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:106:in `block in top_level'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:115:in `run_with_threads'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:100:in `top_level'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:78:in `block in run'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:176:in `standard_exception_handling'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:75:in `run'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/bin/rake:33:in `'
F:/web-shared/Ruby192/bin/rake:19:in `load'
F:/web-shared/Ruby192/bin/rake:19:in `'
任务:TOP => 工作:工作

还有其他人成功使用 log4r 延迟工作吗?我可以使用一些指针;通过 Google 或 DuckDuckGo 搜索找不到任何内容。

这是config/application.rb片段:

require File.expand_path('../boot', __FILE__)

require 'erb'
require 'rails/all'

# log4r
require 'log4r'
require 'log4r/yamlconfigurator'
require 'log4r/outputter/datefileoutputter'
require 'log4r/outputter/consoleoutputters'
include Log4r

...

class Application < Rails::Application

...

  # assign log4r's logger as rails' logger.
  log4r_config = YAML.load(ERB.new(File.read(File.join(File.dirname(__FILE__), 'log4r.yml'))).result)
  log4r_config['ENV'] = Rails.env
  log4r_config['APPNAME'] = Rails.application.class.parent_name
  YamlConfigurator.decode_yaml(log4r_config['log4r_config'])
  config.logger = Log4r::Logger[Rails.env]
  ActiveRecord::Base.logger = Log4r::Logger[Rails.env]
end

这是config/log4r.yml文件:

log4r_config:
  # define all loggers ...
  loggers:
  - name: production
    level: WARN
    trace: 'false'
    outputters:
      - datefile_production
      - console_production
  - name: development
    level: DEBUG
    trace: 'true'
    outputters:
      - datefile_development
      - console_development
  - name: test
    level: DEBUG
    trace: 'true'
    outputters:
      - datefile_test
      - console_test

  # define all outputters (incl. formatters)
  outputters:
  - type: DateFileOutputter
    name: datefile_production
    dirname: "<%= File.join(Rails.root, 'log') %>"
    filename: "production.log"
    formatter:
      date_pattern: '%H:%M:%S.%L'
      pattern: '%p\t%d\t%X{:remote_ip}\t%X{:user}\t%X{:controller}\t%X{:action}\t%l\t%m'
      type: PatternFormatter
  - type: DateFileOutputter
    name: datefile_development
    dirname: "<%= File.join(Rails.root, 'log') %>"
    filename: "development.log"
    formatter:
      date_pattern: '%H:%M:%S.%L'
      pattern: '%p\t%d\t%X{:remote_ip}\t%X{:user}\t%X{:controller}\t%X{:action}\t%l\t%m'
      type: PatternFormatter
  - type: DateFileOutputter
    name: datefile_test
    dirname: "<%= File.join(Rails.root, 'log') %>"
    filename: "test.log"
    formatter:
      date_pattern: '%H:%M:%S.%L'
      pattern: '%p\t%d\t%X{:remote_ip}\t%X{:user}\t%X{:controller}\t%X{:action}\t%l\t%m'
      type: PatternFormatter
  - type: StdoutOutputter
    name: console_production
    formatter:
      date_pattern: '%H:%M:%S.%L'
      pattern: '%p\t%d\t%l\t%m'
      type: PatternFormatter
  - type: StdoutOutputter
    name: console_development
    formatter:
      date_pattern: '%H:%M:%S.%L'
      pattern: '%p\t%d\t%X{:remote_ip}\t%X{:user}\t%X{:controller}\t%X{:action}\t%l\t%m'
      type: PatternFormatter
  - type: StdoutOutputter
    name: console_test
    formatter:
      date_pattern: '%H:%M:%S.%L'
      pattern: '%p\t%d\t%X{:remote_ip}\t%X{:user}\t%X{:controller}\t%X{:action}\t%l\t%m'
      type: PatternFormatter

更新

好吧,在通过调试器运行 rake 任务之后,我弄清楚了发生了什么。

Delayed::Workerdelayed_job/lib/delayed/worker.rb 第 248 行)正在通过记录器的 add 方法记录一条消息,如下所示:

logger.add level, "#{Time.now.strftime('%FT%T%z')}: #{text}" if logger

这对于 Ruby 的Logger类是有效且正确的,请参阅Logger.html#method-i-add。但是,通过使用 log4r,它会解析为Log4r::Logger.addlog4r/lib/log4r/logger.rb 第 119 行),它会尝试添加一个输出器。

我不确定为什么会发生这种情况,或者解决方案是什么。

4

2 回答 2

1

您现在可以更新到delayed_jobs 4.0.1 gem,这将解决这个问题!

于 2014-04-29T17:33:34.280 回答
0

(有关此问题的原始评论,请参见blog.mmlac.com。)

问题是 DelayedJob 期望记录器是 Rails::Logger 并调用 log4r 不支持的记录器。

在本文中,logger 变量被覆盖以使用 Log4r::Logger,它不支持预期的 .add 调用。与 Java 不同,没有包来确定使用哪个记录器类或将不同记录器联合到标准接口的 slf4j。

这个问题没有简单的解决方案。一方面,您可以覆盖延迟作业的受影响部分。另一方面,当delayedJob 运行rails 时,您可以防止加载log4r,即使用自定义环境:

  • 发展
  • 生产
  • 延迟工作

这也不能保证在任何地方都有效(任何检查 rails env == “production” 的东西都会有问题)。

另一种方法是使用环境变量并检查 application.rb 中的环境变量:

if (ENV["log4rlogger"] == "true") config.logger = Log4r::Logger["rails"]
于 2014-03-31T20:30:29.307 回答