Project

General

Profile

Actions

Feature #11955

open

Expose Object that Receives logs in Logger

Added by schneems (Richard Schneeman) almost 9 years ago. Updated about 2 years ago.

Status:
Assigned
Target version:
-
[ruby-core:72725]

Description

I need to be able to perform logic based on the destination of a current logger, this is currently not possible without instance_variable_get. Why would you need to see what destination a logger is going to? There is a common pattern in long lived programs like webservers. You want logs on disk for later reference, but you also want them in STDOUT to make development and debugging easier. Rails does this in development mode. Since there is no way to see if a logger is already going to STDOUT, it gets extended to log to STDOUT so logs show up twice.

While that example was complicated the logic I want is very simple: if you have a logger that is logging to STDOUT, do nothing, otherwise log to STDOUT and current logger. You cannot do this today without exposing the destination of the logger. This patch exposes the logger destination and allows us to write code like this:

def make_sure_logging_to_stdout(logger)
  unless logger.destination == STDOUT   # <==== Cannot do this today
    stdout_logger = ::Logger.new(STDOUT)
    logger.extend(Module do
      def add((*args, &block)
        stdout_logger.add(*args, &block)
        super(*args, &block)
      end
    end)
  end
end

logger = Logger.new(STDOUT)
make_sure_logging_to_stdout(logger)

logger.fatal("An error has occured")

We should be able to inspect the destination of a logger, this patch enables this functionality.


Files

ruby-changes.patch (1.04 KB) ruby-changes.patch schneems (Richard Schneeman), 01/05/2016 09:58 PM
ruby-changes.patch (2.17 KB) ruby-changes.patch schneems (Richard Schneeman), 01/19/2016 08:02 PM

Updated by schneems (Richard Schneeman) almost 9 years ago

Here is a patch to Rails that could benefit from standardizing access to the logger destination object: https://github.com/rails/rails/pull/22933

Updated by nobu (Nobuyoshi Nakada) almost 9 years ago

  • Description updated (diff)

Your example doesn't seem to able to get rid of adding stdout_logger twice or more, even with logger.destination.

Maybe won't it be better to do in LogDevice layer?

Updated by schneems (Richard Schneeman) almost 9 years ago

Your example doesn't seem to able to get rid of adding stdout_logger twice or more, even with logger.destination.

It took a long time to write that example to be short, maybe I missed some details. A real world example is in that linked pull request, you can see the comparison I implemented https://github.com/rails/rails/blob/76c385709c873a7105e3a267d84c4e70417a15e2/activesupport/lib/active_support/logger.rb#L8-L17 this is where I would like to use a public interface instead of instance_variable_get.

LogDevice already exposes the destination, but Logger does not expose the LogDevice object. I did not know if there was a reason people did not what to provide access to LogDevice. Would you prefer that I submitted a patch to expose the LogDevice instead?

Updated by schneems (Richard Schneeman) almost 9 years ago

Nobu, I've added a new patch that would expose the LogDevice object in a Logger instance. This would be acceptable for my needs.

Updated by hsbt (Hiroshi SHIBATA) almost 9 years ago

  • Status changed from Open to Assigned
  • Assignee set to sonots (Naotoshi Seo)

Updated by schneems (Richard Schneeman) over 8 years ago

Anything else that needs to be done for this patch?

Updated by sonots (Naotoshi Seo) over 8 years ago

I am wondering of the interface yet.

Users pass an io object to Logger constructor as logdev like Logger.new(logdev), so getting the io object from Logger#logdev seems natural. However,

attr_reader :logdev

returns a LogDevice instance rather than io object, which seems natural from the view of source codes.

Updated by schneems (Richard Schneeman) over 8 years ago

Sorry for the delay, bugs.ruby-lang.org does not send me emails for some reason.

The first patch I attached returned @logdev.dev which is the IO object. It was discussed that to do this Logger must know too much about the logdev interface and it would be simpler to expose the logdev instead.

Either approach will work for my use cases. Now that 2.4.0 preview is out is there a feature freeze? Is there any chance this will come out in time for christmas?

Updated by tensho (Andrew Babichev) about 7 years ago

So will #logdev will be exposed in Logger or Logger::LogDevice?

Updated by ioquatix (Samuel Williams) about 2 years ago

I'm against this proposal because I think it's solving the wrong problem.

I don't think you should assume the Logger interface has the implementation provided by the logger gem, i.e. Logger::LogDevice is an implementation detail.

It should be very reasonable (as Rails appears to do) replace the logger with any compatible interface, which might not have the same underlying interface. By compatible interface, any object that responds to info, warn, error, etc.

I would say that trying to answer the question "Does calling info on this object emit data to STDOUT?" is fundamentally not part of the logger interface and therefore isn't a question you should be asking.

If your goal is to (1) when run interactively, log to STDOUT (or better, STDERR), and in addition, a file, and (2) when run non-interactively, only output to a file, I would suggest you model this in the configuration, e.g.

if Rails.interactive?
  Rails.logger = TeeLogger.new(STDOUT, file)
else
  Rails.logger = Logger.new(file)
end

This seems far more intuitive to me.

Is that possible?

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0