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

查看:37
本文介绍了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 magic":

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

module Crawler
  class <<self
    attr_accessor :logger
  end
end

它做的完全一样.

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

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