2009-08-18 13 views
17

J'ai un fichier journal qui ne cesse de croître. Comment puis-je regarder et analyser cela via un script Ruby?Regarder/lire un fichier journal en croissance

Le script analysera chaque nouvelle ligne comme il est écrit dans le fichier et quelque chose de sortie à l'écran lorsque la nouvelle ligne contient la chaîne « erreur »

Répondre

8

Vous pouvez utiliser Kernel#select de la manière suivante:

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 

appeler Ensuite, comme:

watch_for("some_file", /ERROR/) 

J'ai élidé tous les contrôles d'erreur et comme - vous voulez avoir cela et probablement une mecha nisme pour sortir de la boucle. Mais l'idée de base est là.

4

Si vous êtes sous Linux ...

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

À moins que vous vouliez vraiment que ce soit un script Ruby pour une raison quelconque.

+0

Emballage dans un script vous donne la possibilité de réagir à une erreur d'une manière plus significative qu'en notant que cela s'est produit. Le grepping est bon quand vous voulez post-traiter, mais il est plutôt limité dans sa capacité à invoquer un comportement dynamique. – ezpz

+0

"... afficher quelque chose à l'écran lorsque la nouvelle ligne contient la chaîne 'ERROR'" n'est pas un comportement dynamique :) – cakeforcerberus

+1

Cela fonctionne mieux pour moi. La méta-programmation autour du journal des erreurs semble être un effort mieux dépensé ailleurs. – 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/) 

Merci pour l'idée de l'ezpz, en utilisant la méthode select vous obtenez ce que vous voulez. La méthode select écoute le flux des E/S, lisez les octets qui arrivent 'en retard'.

+2

Note: 'select' retourne toujours immédiatement lorsqu'il est utilisé sur un flux de fichier: Vous pouvez toujours lire EOF à partir de ce flux de fichiers, ainsi votre processus ruby ​​finit par tourner pendant qu'il attend la mise à jour du fichier. Différents systèmes d'exploitation ont tendance à offrir différents outils pour attendre sur les fichiers, Linux a inotify et OS X a des fsevents - il y a des rubis intéressants qui les enveloppent aussi. – antifuchs

+1

-1 Solution stupide qui utilise 100% du CPU. –

+0

Je pense que la raison pour laquelle il utilise 100% CPU est parce que si vous supprimez la ligne qui dit 'if line = ~ pattern' il continue de retourner des lignes vides même s'il n'y a pas de nouvelle mise à jour. Je ne suis pas sûr de savoir comment résoudre le problème moi-même, car j'ai aussi trébuché sur ce problème. – Pred

3

L'approche de l'homme pauvre pour des trucs rapides:

  1. un script Ruby qui ne

    ARGF.each do |line| 
        ... 
    
  2. écran Courir avec:

    tail -f file | ruby script 
    
5

Il y a deux approche:

  • sondage le fichier dans une boucle infinie (comme dans la réponse de Qianjigui, mais il est bon de mettre un peu sleep dans la boucle infinie)
  • utilisation sous-système d'événements OS: kqueue sur BSD, inotify sous Linux

Voici un article que j'ai écrit à ce sujet: Ruby for Admins: Reading Growing Files. Ainsi, le programme combinant à la fois sous-système d'événements et sondages ressemble à ceci:

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

travail sur idée de @Qianjigui mais pas en utilisant CPU 100%:

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/) 
Questions connexes