Ruby-在模块/类之间共享记录器实例 [英] Ruby - share logger instance among module/classes

查看:64
本文介绍了Ruby-在模块/类之间共享记录器实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

研究一个小的Ruby脚本,该脚本可以在网上发布并抓取各种服务.我有一个内部有几个类的模块:

Working on a little Ruby script that goes out to the web and crawls various services. I've got a module with several classes inside:

module Crawler
  class Runner
  class Options
  class Engine
end

我想在所有这些类中共享一个记录器.通常,我只是将其放在模块中的常量中,然后像这样引用它:

I want to share one logger among all those of those classes. Normally I'd just put this in a constant in the module and reference it like so:

Crawler::LOGGER.info("Hello, world")

问题在于,直到我知道输出的去向,我才能创建记录器实例.您可以通过命令行启动搜寻器,然后可以告诉它要在开发中运行(日志输出进入STDOUT)还是在生产环境中运行(日志输出进入文件crawler.log):

The problem is that I can't create my logger instance until I know where the output is going. You start the crawler via command line and at that point you can tell it you want to run in development (log output goes to STDOUT) or production (log output goes to a file, crawler.log):

crawler --environment=production

我有一个类Options,该类分析通过命令行传递的选项.只有到那时,我才知道如何用正确的输出位置实例化记录器.

I have a class Options that parses the options passed in through the command line. Only at that point do I know how to instantiate the logger with the correct output location.

所以,我的问题是:如何/在何处放置记录器对象,以便我所有的类都可以访问它?

So, my question is: how/where to I put my logger object so that all my classes have access to it?

我可以将记录器实例传递给我创建的每个类实例的每个new()调用,但是我知道必须有一种更好的,Rubyish的方式来做到这一点.我正在想象与class << self共享的模块上一些奇怪的类变量或其他魔术. :)

I could pass my logger instance to each new() call for every class instance I create, but I know there has to be a better, Rubyish way to do it. I'm imagining some weird class variable on the module that shared with class << self or some other magic. :)

更多细节:Runner通过将命令行选项传递给Options类来启动所有操作,并返回带有几个实例变量的对象:

A little more detail: Runner starts everything by passing the command line options to the Options class and gets back an object with a couple of instance variables:

module Crawler
  class Runner
    def initialize(argv)
      @options = Options.new(argv)
      # feels like logger initialization should go here
      # @options.log_output => STDOUT or string (log file name)
      # @options.log_level => Logger::DEBUG or Logger::INFO
      @engine = Engine.new()
    end
    def run
      @engine.go
    end
  end
end

runner = Runner.new(ARGV)
runner.run

我需要Engine中的代码才能访问记录器对象(以及在Engine内部初始化的几个其他类).救命!

I need the code in Engine to be able to access the logger object (along with a couple more classes that are initialized inside Engine). Help!

如果您可以动态地更改已实例化的Logger的输出位置(类似于更改日志级别的方式),则可以避免所有这些情况.我将其实例化为STDOUT,然后如果正在生产中,则将其转换为文件.我确实在某个地方看到了有关更改Ruby的$ stdout全局变量的建议,该建议会将输出重定向到STDOUT以外的其他地方,但这似乎很hacky.

All of this could be avoided if you could just dynamically change the output location of an already-instantiated Logger (similar to how you change the log level). I'd instantiate it to STDOUT and then change over to a file if I'm in production. I did see a suggestion somewhere about changing Ruby's $stdout global variable, which would redirect output somewhere other than STDOUT, but this seems pretty hacky.

谢谢!

推荐答案

使用您已经设计好的设计,看来最简单的解决方案是为Crawler提供一个模块方法,该方法返回模块ivar.

With the design you've laid out, it looks like the easiest solution is to give Crawler a module method that returns a module ivar.

module Crawler
  def self.logger
    @logger
  end
  def self.logger=(logger)
    @logger = logger
  end
end

或者,如果您愿意,也可以使用"class <<self魔术":

Or you could use "class <<self magic" if you wanted:

module Crawler
  class <<self
    attr_accessor :logger
  end
end

它做的完全一样.

这篇关于Ruby-在模块/类之间共享记录器实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆