Получение ошибки при использовании log4r с отложенной работой

У меня есть рабочее приложение Rails 3.2 (Ruby 1.9.2p290 на Windows Server 2008 R2), которое использует отложенные задания для нескольких фоновых заданий. Я недавно заменил ведение журнала Rails по умолчанию на log4r, и он прекрасно работает для приложения Rails. Тем не менее, когда я запускаю rake jobs:work задача я получаю сообщение об ошибке с нулевым выходом:

Стартовая работа рабочих граблей отменена!
TypeError: Ожидаемый тип Outputter, полученный NilClass
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/log4r-1.1.10/lib/log4r/logger.rb:120: в `each'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/log4r-1.1.10/lib/log4r/logger.rb:120: в `add'
F:/web-shared/Ruby192/lib/ruby ​​/gems/1.9.1/gems/delayed_job-4.0.0/lib/delayed/worker.rb:248: в `скажем '
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: в блоке `(2 уровня) в '
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:240: в `call'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:240: в` блоке в "F" /web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:235: в "каждом" 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 / камни / рек-10.2.2 / Библиотека / рейка / та sk.rb:179: в `block in invoke_with_call_chain'
F:/web-shared/Ruby192/lib/ruby/1.9.1/monitor.rb:201: в`mon_synchronize'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/task.rb:172: в `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 `блок (2 уровня) на верхнем уровне '
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:106: в` каждом' F: /web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb: 106: в блоке на верхнем уровне F: / web-shared / Ruby192 / lib / ruby ​​/ gems / 1.9.1 / gems / rake-10.2.2 / lib / rake / application.rb: 115: в `run_with_threads 'F: /web-shared/Ruby192/lib/ruby/gems/1.9.1 / gems / rake-10.2.2 / lib / rake / application.rb: 100: в `top_level
'
F:/web-shared/Ruby192/lib/ruby ​​/gems/1.9.1/gems/rake-10.2.2/lib/rake/application.rb:78: в `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: в `run'
F:/web-shared/Ruby192/lib/ruby/gems/1.9.1/gems/rake-10.2.2/bin/rake:33: в`'
F:/web-shared/Ruby192/bin/rake:19: в `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

ОБНОВИТЬ

Что ж, после запуска граблей через отладчик я понял, что происходит.

Delayed::Worker ( delayed_job / lib / delayed / worker.rb строка 248) записывает сообщение с помощью метода add в логгере так:

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

Это верно и правильно для Ruby's Logger класс, см. Logger.html # method-i-add. Однако, используя log4r, он разрешает Log4r::Logger.add ( log4r / lib / log4r / logger.rb строка 119), которая пытается добавить выходной файл.

Я не уверен, почему это происходит, или какое решение будет.

2 ответа

Решение

(см. blog.mmlac.com для оригинального комментария к этой проблеме.)

Проблема заключается в том, что DelayedJob ожидает, что логгером будет Rails::Logger, и делает вызовы, которые log4r не поддерживает.

В этой статье переменная logger перезаписывается для использования Log4r::Logger, который не поддерживает вызов.add, как предполагалось. В отличие от Java, нет пакетов для определения, какой класс logger использовать, или slf4j, который объединяет различные регистраторы в стандартный интерфейс.

Простого решения этой проблемы не существует. С одной стороны, вы можете переписать затронутые части delayedJob. С другой стороны, вы можете предотвратить загрузку log4r, когда delayedJob запускает рельсы, т. Е. Используя пользовательскую среду:

  • развитие
  • производство
  • delayedJob

Это также не гарантируется для работы везде (все, что проверяет рельсы env == "production", будет иметь проблемы).

Другой способ - использовать переменные окружения и проверить их в application.rb:

if (ENV["log4rlogger"] == "true") config.logger = Log4r::Logger["rails"]

Теперь вы можете обновить до гема delayed_jobs 4.0.1, и это решит эту проблему!

Другие вопросы по тегам