2009-08-18 6 views
17

Tengo un archivo de registro que está en constante crecimiento. ¿Cómo puedo ver y analizar a través de un script de Ruby?Mirar/leer un archivo de registro en crecimiento

el guión analizar cada nueva línea, ya que se escribe en el archivo y mostrar algo a la pantalla cuando la nueva línea contiene la cadena 'ERROR'

Respuesta

8

Puede utilizar Kernel#select de la siguiente manera:

def watch_for(file,pattern) 
    f = File.open(file,"r") 

    # Since this file exists and is growing, seek to the end of the most recent entry 
    f.seek(0,IO::SEEK_END) 

    while true 
     select([f]) 
     puts "Found it!" if f.gets =~ pattern 
    end 
end 

Entonces llamar así:

watch_for("some_file", /ERROR/) 

he elididas toda comprobación de errores y tal - que tendrá que tener eso y probablemente algunos mecha nismo para salir del círculo. Pero la idea básica está ahí.

4

Si estás en Linux ...

tail -f log/development.log | grep "ERROR" 

A menos que realmente quería que fuera un script de Ruby por alguna razón.

+0

envolver esta en un script le da la capacidad de reaccionar a un error de una manera más significativa que al notar que ocurrió. el grepping es bueno cuando desea postprocesar, pero tiene una capacidad limitada para invocar un comportamiento dinámico. – ezpz

+0

"... muestra algo en la pantalla cuando la nueva línea contiene la cadena 'ERROR'" no es un comportamiento dinámico :) – cakeforcerberus

+1

Esto funciona mejor para mí. La metaprogramación alrededor del registro de errores parece un esfuerzo mejor empleado en otro lugar. – MattC

17
def watch_for(file, pattern) 
    f = File.open(file,"r") 
    f.seek(0,IO::SEEK_END) 
    while true do 
    select([f]) 
    line = f.gets 
    puts "Found it! #{line}" if line=~pattern 
    end 
end 

watch_for("g.txt",/ERROR/) 

Gracias por la idea del EZPZ, utilizando el método de selección se obtiene consigue lo que quiere. El método de selección es escuchar el flujo de IO, leer los bytes lo que viene 'tarde'.

+2

Nota: 'select' siempre regresa inmediatamente cuando se utiliza en una secuencia de archivos: siempre puede leer EOF de esa secuencia de archivos, por lo que su proceso ruby ​​termina girando mientras espera que el archivo se actualice. Los diferentes sistemas operativos tienden a ofrecer diferentes herramientas para esperar en los archivos, Linux ha inotify y OS X tiene fsevents: hay gemas de rubí convenientes que los envuelven también. – antifuchs

+1

-1 Solución tonta que usa el 100% de la CPU. –

+0

Creo que la razón por la que usa el 100% de CPU es porque si quita la línea que dice 'if line = ~ pattern' simplemente sigue devolviendo líneas en blanco, incluso si no hay una nueva actualización. No estoy seguro de cómo arreglarlo yo mismo, ya que me topé con ese problema también. – Pred

3

del hombre pobre para la materia rápida:

  1. un script Ruby que hace

    ARGF.each do |line| 
        ... 
    
  2. pantalla Running with:

    tail -f file | ruby script 
    
5

Existen dos enfoque:

  • sondeo el archivo en un bucle infinito (como en la respuesta de Qianjigui, pero es bueno para poner un poco de sleep dentro del bucle infinito) subsistema de evento
  • uso OS: kqueue en BSD, inotify en Linux

Aquí hay un artículo que escribí al respecto: Ruby for Admins: Reading Growing Files. Para que el programa que combina tanto subsistema de evento y de votación es el siguiente:

def tail_dash_f(filename) 
    open(ARGV.first) do |file| 
    file.read   
    case RUBY_PLATFORM # string with OS name, like "amd64-freebsd8" 
    when /bsd/, /darwin/ 
     require 'rb-kqueue' 
     queue = KQueue::Queue.new  
     queue.watch_file(ARGV.first, :extend) do 
     yield file.read    
     end 
     queue.run      
    when /linux/ 
     require 'rb-inotify' 
     queue = INotify::Notifier.new 
     queue.watch(ARGV.first, :modify) do 
     yield file.read    
     end 
     queue.run      
    else 
     loop do   
     changes = file.read 
     unless changes.empty? 
      yield changes 
     end 
     sleep 1.0  
     end 
    end 
    end 
end 

tail_dash_f ARGV.first do |data| 
    print data 
    if data =~ /error/i 
    # do something else, for example send an email to administrator 
    end 
end 
1

Trabajando sobre la idea, pero no de @Qianjigui utilizando el 100% de la CPU:

def watch_for(file, pattern) 
    # Replace -n0 with -n+1 if you want to read from the beginning of file 
    f = IO.popen(%W[tail -f -n0 #{file}]) 
    loop do 
    select([f]) 
    while line = f.gets 
     puts "Found it! #{line}" if line =~ pattern 
    end 
    end 
end 

watch_for('g.txt', /ERROR/) 
Cuestiones relacionadas