2011-05-24 10 views
21

Esiste uno strumento in grado di estrarre un elenco di tracce di stack che appaiono nel file di registro e probabilmente contare quelle univoche?Strumento per estrarre tracce di stack java dai file di registro

MODIFICA: Vorrei preffer qualcosa che non è basato su GUI e che viene eseguito in background e restituire una sorta di rapporto. Ho un sacco di registri raccolti da diversi ambienti e vorrei solo avere una rapida panoramica.

+0

Perché nel registro ci sono così tante tracce di stack? Stai registrando le eccezioni a destra e a sinistra? Sei sicuro che sia una buona idea? – sleske

+0

Questo è un registro da un test delle prestazioni e alcune parti del sistema non funzionano sotto pressione. La cosa che voglio raggiungere è una relazione simpe su dove e quali eccezioni si sono verificate durante la corsa. –

+0

Potrebbe essere un'eccezione avvenuta in 1 giorno o potrebbero essere 1000 eccezioni avvenute in un minuto. La quantità di eccezioni non è determinata dalla quantità di log. –

risposta

2

Ho creato il seguente script Groovy. È, naturalmente, molto adattato alle mie esigenze, ma spero che aiuti qualcuno.

def traceMap = [:] 

// Number of lines to keep in buffer 
def BUFFER_SIZE = 100 

// Pattern for stack trace line 
def TRACE_LINE_PATTERN = '^[\\s\\t]+at .*$' 

// Log line pattern between which we try to capture full trace 
def LOG_LINE_PATTERN = '^([<#][^/]|\\d\\d).*$' 

// List of patterns to replace in final captured stack trace line 
// (e.g. replace date and transaction information that may make similar traces to look as different) 
def REPLACE_PATTERNS = [ 
    '^\\d+-\\d+\\@.*?tksId: [^\\]]+\\]', 
    '^<\\w+ \\d+, \\d+ [^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <', 
    '^####<[^>]+?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <', 
    '<([\\w:]+)?TransaktionsID>[^<]+?</([\\w:]+)?TransaktionsID>', 
    '<([\\w:]+)?TransaktionsTid>[^<]+?</([\\w:]+)?TransaktionsTid>' 
] 

new File('.').eachFile { File file -> 
    if (file.name.contains('.log') || file.name.contains('.out')) { 
    def bufferLines = [] 
    file.withReader { Reader reader -> 
     while (reader.ready()) {  
     def String line = reader.readLine() 
     if (line.matches(TRACE_LINE_PATTERN)) { 
      def trace = [] 
      for(def i = bufferLines.size() - 1; i >= 0; i--) { 
      if (!bufferLines[i].matches(LOG_LINE_PATTERN)) { 
       trace.add(0, bufferLines[i]) 
      } else { 
       trace.add(0, bufferLines[i]) 
       break 
      } 
      } 
      trace.add(line) 
      if (reader.ready()) { 
      line = reader.readLine() 
      while (!line.matches(LOG_LINE_PATTERN)) { 
       trace.add(line) 
       if (reader.ready()) { 
       line = reader.readLine() 
       } else { 
       break; 
       } 
      } 
      } 
      def traceString = trace.join("\n") 
      REPLACE_PATTERNS.each { pattern -> 
      traceString = traceString.replaceAll(pattern, '') 
      } 
      if (traceMap.containsKey(traceString)) { 
      traceMap.put(traceString, traceMap.get(traceString) + 1) 
      } else { 
      traceMap.put(traceString, 1) 
      } 
     } 
     // Keep the buffer of last lines. 
     bufferLines.add(line) 
     if (bufferLines.size() > BUFFER_SIZE) { 
      bufferLines.remove(0) 
     } 
     } 
    } 
    } 
} 

traceMap = traceMap.sort { it.value } 

traceMap.reverseEach { trace, number -> 
    println "-- Occured $number times -----------------------------------------" 
    println trace 
} 
0

Io uso Baretail.

+2

Conosco lo strumento e in realtà anch'io lo uso :). Ma preferirei qualcosa che non fosse basato sulla GUI. Abbiamo molti registri e l'apertura di ognuno di essi nella GUI non è, purtroppo, un'opzione. –

13

Puoi scrivere tu stesso abbastanza facilmente. Ecco lo schema:

  1. Aprire il file
  2. Cercare la stringa "\n\tat " (che è nuova linea, scheda, at, vuoto) Questa è una stringa abbastanza raro al di fuori di tracce dello stack.

Ora tutto quello che devi fare è trovare la prima riga che non inizia con \t per trovare la fine della traccia dello stack. Si consiglia di saltare 1-3 linee dopo di che per rilevare le eccezioni concatenate.

Inoltre, aggiungere un paio di righe (ad esempio 10 o 50) prima della prima riga della traccia dello stack per ottenere un contesto.

+0

Grazie, Aaron. Ho avuto la stessa idea ed è quello che farei alla fine se non trovassi nulla che sia già lì :). Sono abbastanza sicuro che questa funzionalità sia presente in alcuni analizzatori di log commerciali, ma speravo che qualcosa del genere esistesse anche come strumento gratuito o script di esempio. –

14

Ecco un'espressione rapido-and-dirty grep ... se si utilizza un registratore, come log4j rispetto alla prima linea di eccezione generalmente conterrà WARN o ERROR, la riga successiva conterrà l'eccezione nome, e, un messaggio, e quindi la successiva analisi dello stack inizierà con una delle seguenti:

  1. "\tat" (scheda + a)
  2. "Caused by: "
  3. "\t... <some number> more" (queste sono le linee che indicano il numero di fotogrammi nella pila non mostrato in un "causato da" eccezione)
  4. Un nome eccezione (e forse il messaggio) prima che la pila

Vogliamo ottenere tutto le righe precedenti, quindi l'espressione grep è:

grep -P "(WARN|ERROR|^\tat |Exception|^Caused by: |\t... \d+ more)"

assume una classe di eccezione contiene sempre la parola Exception che può o non può essere vero, ma questo è rapido e-sporco dopo tutto.

Regolare secondo necessità per il caso specifico.

9

Ho scritto uno strumento in Python. Riesce a dividere due tracce dello stack anche se si trovano una dopo l'altra nel registro.

#!/usr/bin/env python 
# 
# Extracts exceptions from log files. 
# 

import sys 
import re 
from collections import defaultdict 

REGEX = re.compile("(^\tat |^Caused by: |^\t... \\d+ more)") 
# Usually, all inner lines of a stack trace will be "at" or "Caused by" lines. 
# With one exception: the line following a "nested exception is" line does not 
# follow that convention. Due to that, this line is handled separately. 
CONT = re.compile("; nested exception is: *$") 

exceptions = defaultdict(int) 

def registerException(exc): 
    exceptions[exc] += 1 

def processFile(fileName): 
    with open(fileName, "r") as fh: 
    currentMatch = None 
    lastLine = None 
    addNextLine = False 
    for line in fh.readlines(): 
     if addNextLine and currentMatch != None: 
     addNextLine = False 
     currentMatch += line 
     continue 
     match = REGEX.search(line) != None 
     if match and currentMatch != None: 
     currentMatch += line 
     elif match: 
     currentMatch = lastLine + line 
     else: 
     if currentMatch != None: 
      registerException(currentMatch) 
     currentMatch = None 
     lastLine = line 
     addNextLine = CONT.search(line) != None 
    # If last line in file was a stack trace 
    if currentMatch != None: 
     registerException(currentMatch) 

for f in sys.argv[1:]: 
    processFile(f) 

for item in sorted(exceptions.items(), key=lambda e: e[1], reverse=True): 
    print item[1], ":", item[0] 
+0

Il tuo script sta funzionando alla grande. Tuttavia sarebbe più bello aggiungere la data dell'eccezione. – Mitchapp

+0

@Mitchapp hai un file di log di esempio con le date? –

Problemi correlati