98 votes

Comment puis-je avoir la sortie du journal de l'enregistreur ruby sur stdout ainsi que sur fichier?

Quelque chose comme une fonctionnalité de té dans l'enregistreur.

127voto

David Points 1450

Vous pouvez écrire un pseudo - IO classe qui va écrire à plusieurs IO objets. Quelque chose comme:

class MultiIO
  def initialize(*targets)
     @targets = targets
  end

  def write(*args)
    @targets.each {|t| t.write(*args)}
  end

  def close
    @targets.each(&:close)
  end
end

Puis le définir comme votre fichier de log:

log_file = File.open("log/debug.log", "a")
Logger.new MultiIO.new(STDOUT, log_file)

Chaque fois Logger des appels puts sur votre MultiIO objet, il conviendra d'écrire à la fois STDOUT et votre fichier de log.

Edit: je suis allé de l'avant et a trouvé le reste de l'interface. Un journal de l'appareil doit répondre aux write et close (pas puts). Tant que MultiIO répond aux besoins des personnes et des procurations à la vraie IO objets, cela devrait fonctionner.

48voto

jonas054 Points 571

@ La solution de David est très bonne. J'ai créé une classe de délégation générique pour plusieurs cibles en fonction de son code.

 require 'logger'

class MultiDelegator
  def initialize(*targets)
    @targets = targets
  end

  def self.delegate(*methods)
    methods.each do |m|
      define_method(m) do |*args|
        @targets.map { |t| t.send(m, *args) }
      end
    end
    self
  end

  class <<self
    alias to new
  end
end

log_file = File.open("debug.log", "a")
log = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)
 

13voto

Vous pouvez également ajouter plusieurs fonctionnalités de journalisation de périphérique directement dans le consignateur:

 require 'logger'

class Logger
  # Creates or opens a secondary log file.
  def attach(name)
    @logdev.attach(name)
  end

  # Closes a secondary log file.
  def detach(name)
    @logdev.detach(name)
  end

  class LogDevice # :nodoc:
    attr_reader :devs

    def attach(log)
      @devs ||= {}
      @devs[log] = open_logfile(log)
    end

    def detach(log)
      @devs ||= {}
      @devs[log].close
      @devs.delete(log)
    end

    alias_method :old_write, :write
    def write(message)
      old_write(message)

      @devs ||= {}
      @devs.each do |log, dev|
        dev.write(message)
      end
    end
  end
end
 

Par exemple:

 logger = Logger.new(STDOUT)
logger.warn('This message goes to stdout')

logger.attach('logfile.txt')
logger.warn('This message goes both to stdout and logfile.txt')

logger.detach('logfile.txt')
logger.warn('This message goes just to stdout')
 

13voto

dsz Points 506

Bien que j'aime bien les suggestions ci-dessus, j'ai constaté que j'avais le même problème, mais je voulais pouvoir utiliser différents niveaux de journalisation pour STDERR et le fichier (comme je le pouvais avec les plus grands cadres de journalisation comme NLog). Je me suis retrouvé avec une stratégie de routage qui multiplexe au niveau de l'enregistreur plutôt qu'au niveau des E / S, afin que chaque enregistreur puisse ensuite fonctionner à des niveaux de journalisation indépendants:

 class MultiLogger
    def initialize(*targets)
        @targets = targets
    end

    %w(log debug info warn error).each do |m|
        define_method(m) do |*args|
            @targets.map { |t| t.send(m, *args) }
        end
    end
end


$stderr_log = Logger.new(STDERR)
$file_log = Logger.new(File.open('logger.log','a'))

$stderr_log.level = Logger::INFO
$file_log.level = Logger::DEBUG

$log = MultiLogger.new( $stderr_log, $file_log )
 

9voto

Tyler Rick Points 3033

Voici une autre mise en œuvre, inspirée par @jonas054's réponse.

Il utilise un modèle similaire à Delegator. De cette façon, vous n'avez pas à énumérer toutes les méthodes que vous souhaitez déléguer, car il va déléguer toutes les méthodes qui sont définies dans l'une quelconque des objets cibles:

class Tee < DelegateToAllClass(IO)
end

$stdout = Tee.new(STDOUT, File.open("#{__FILE__}.log", "a"))

Vous devriez être capable de l'utiliser avec l'Enregistreur.

delegate_to_all.rb est disponible ici: https://gist.github.com/TylerRick/4990898

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X