Se si sta creando il logger da soli, è possibile creare l'oggetto File
prima, quindi utilizzarlo per creare il data logger e assegnarlo a $stderr
:
log_file = File.new('foo.log', 'a')
logger = Logger.new(log_file, 'weekly')
$stderr = log_file #usually no need to use reopen
Si noti che questo si tradurrà in l'output del registro essere mescolato con l'output di $stderr
, che potrebbe causare problemi se si sta analizzando il file di registro in attesa che si trovi in un determinato formato (questo accadrà anche con la soluzione).
Se non si dispone del file sottostante ma si riceve lo logger
da qualche altra parte, è un po 'più complicato. Ciò che è necessario è un oggetto simile a IO
che può essere assegnato a $stderr
e passa qualsiasi cosa scritta al registratore. La classe IO
in Ruby è, purtroppo, abbastanza strettamente legata al sistema i/o sottostante (descrittori di file e simili), e non esiste un'interfaccia generale che possa essere utilizzata per creare flussi di input e output. (StringIO
è l'eccezione notevole).
Tuttavia la maggior parte, se non tutti, i metodi di uscita sul IO
infine passare attraverso #write
, quindi eseguendo l'override questo metodo è possibile avvicinarsi a quello che stai dopo:
class IOToLog < IO
def initialize(logger)
@logger = logger
end
def write(string)
#assume anything written to stderr is an error
@logger.error(message)
end
end
logger = get_logger_from_somewhere
$stderr = IOToLog.new(logger)
Ora qualsiasi cosa scritta $stderr
finirà per andare al file di registro. La formattazione tuttavia sarà un po 'strana. Ogni volta che uno qualsiasi dei metodi di scrittura chiama #write
, nel file di registro verrà creata una nuova voce. Ad esempio, #puts
chiamato con un array chiamerà #write
per ogni voce dell'array e nuovamente con un carattere di nuova riga tra ciascuna voce, risultando in 2n - 1 voci di registro, n - 1 di cui sarà vuoto.
È possibile rendere più complesso il metodo sostituito a #write
per gestire questo problema, magari utilizzando un buffer interno, e chiamare il registratore solo quando si ritiene di avere un messaggio completo. In alternativa, è possibile sovrascrivere i singoli metodi per scrivere nel registratore stesso. Se lo facevi, la classe IOToLog
non dovrebbe necessariamente ereditare da IO
.
La soluzione migliore dipenderà da come si desidera l'uscita standard error per apparire nel file di log, come il programma utilizza $stderr
, e come si vuole fare metodi di attuazione da IO
lavoro molto.
Ottima risposta, grazie! Nel mio caso sto creando il logger in modo che la tua prima soluzione sia pulita ed elegante. Mi piace particolarmente che tu abbia incluso la soluzione alternativa per l'altro caso. (Anche se in tal caso potrei sostenere il mio trucco di raggiungere e prendere direttamente il file.) – Phrogz
Il secondo metodo non funziona per me su jruby. Ottengo il seguente errore: (Errno :: EBADF) Descrittore di file errato –
Ci dovrebbe essere '@ logger.error (stringa)' Penso – lojza