2011-05-24 54 views
21

Có công cụ nào có thể trích xuất danh sách các dấu vết ngăn xếp xuất hiện trong tệp nhật ký và có thể đếm số duy nhất không?Công cụ để trích xuất dấu vết ngăn xếp java từ các tệp nhật ký

EDIT: Tôi sẽ preffer cái gì đó không phải là dựa trên GUI và được chạy trên nền và cung cấp cho một số loại báo cáo lại. Tôi có khá nhiều nhật ký được thu thập từ nhiều môi trường và chỉ muốn có cái nhìn tổng quan nhanh chóng.

+0

Tại sao bạn có quá nhiều dấu vết ngăn xếp trong nhật ký của mình? Bạn có đăng nhập ngoại lệ trái và phải không? Bạn có chắc chắn đó là một ý tưởng hay không? – sleske

+0

Đó là nhật ký từ kiểm tra hiệu suất và một số phần nhất định của hệ thống không bị áp lực. Điều tôi muốn đạt được là một báo cáo bằng simpe về vị trí và ngoại lệ nào xảy ra trong quá trình chạy. –

+0

Có thể một ngoại lệ đã xảy ra trong 1 ngày hoặc có thể là 1000 ngoại lệ đã xảy ra trong một phút. Số lượng ngoại lệ không được xác định bởi số lượng nhật ký. –

Trả lời

2

Tôi đã đưa ra kịch bản Groovy sau. Đó là, tất nhiên, rất nhiều điều chỉnh theo nhu cầu của tôi, nhưng tôi hy vọng nó sẽ giúp một ai đó.

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

Tôi sử dụng Baretail.

+2

Tôi biết công cụ đó và thực sự tôi cũng sử dụng nó :). Nhưng tôi sẽ preffer cái gì đó không phải là dựa trên GUI. Chúng tôi có khá nhiều nhật ký và mở mỗi một trong số chúng trong GUI, thật không may, không phải là một tùy chọn. –

13

Bạn có thể tự viết bài này khá dễ dàng. Dưới đây là các mô hình:

  1. mở tập tin
  2. Tìm kiếm chuỗi "\n\tat " (đó là mới dòng, tab, at, trống) Đây là một chuỗi khá phổ biến bên ngoài của chồng dấu vết.

Bây giờ tất cả những gì bạn cần làm là tìm dòng đầu tiên không bắt đầu bằng \t để tìm kết thúc theo dõi ngăn xếp. Bạn có thể muốn bỏ qua 1-3 dòng sau đó để bắt các trường hợp ngoại lệ bị xích.

Thêm một vài dòng (nói 10 hoặc 50) trước dòng đầu tiên của dấu vết ngăn xếp để nhận một số ngữ cảnh.

+0

Cảm ơn, Aaron. Tôi đã có cùng một ý tưởng và đó là những gì tôi sẽ làm cuối cùng nếu tôi không tìm thấy bất cứ điều gì đã có :). Tôi khá chắc chắn tính năng này có mặt trong một số phân tích nhật ký comercial, nhưng tôi hy vọng một cái gì đó như thế tồn tại cũng như một công cụ miễn phí hoặc kịch bản ví dụ. –

14

Đây là một biểu hiện grep nhanh chóng-và-bẩn ... nếu bạn đang sử dụng một logger như log4j so với dòng đầu tiên của ngoại lệ thường sẽ chứa WARN hoặc ERROR, dòng tiếp theo sẽ chứa các ngoại lệ tên, và tùy chọn một tin nhắn, và sau đó là stack trace tiếp theo sẽ bắt đầu với một trong các cách sau:

  1. "\tat" (tab + ở)
  2. "Caused by: "
  3. "\t... <some number> more" (đây là những dòng mà chỉ ra số lượng khung hình trong ngăn xếp không được hiển thị trong một "gây ra bởi" ngoại lệ)
  4. Một tên ngoại lệ (và có lẽ tin nhắn) trước khi chồng

Chúng tôi muốn có được tất cả của các dòng trên, vì vậy biểu thức grep là:

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

Nó giả định một lớp ngoại lệ luôn chứa từ Exception mà có thể hoặc không có thể đúng, nhưng điều này là nhanh chóng-và-bẩn sau khi tất cả.

Điều chỉnh khi cần thiết cho trường hợp cụ thể của bạn.

9

Tôi đã viết một công cụ bằng Python. Nó quản lý để chia hai dấu vết ngăn xếp ngay cả khi họ đến ngay sau mỗi khác trong nhật ký.

#!/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

Kịch bản của bạn đang hoạt động tuyệt vời. Tuy nhiên nó sẽ đẹp hơn để thêm ngày của ngoại lệ. – Mitchapp

+0

@Mitchapp bạn có tệp nhật ký mẫu có ngày không? –

Các vấn đề liên quan