Выборочный анализ файлов журналов с использованием Java - PullRequest
0 голосов
/ 10 января 2011

Мне нужно проанализировать большую кучу файлов журналов в следующем формате.

SOME SQL STATEMENT/QUERY

DB20000I  The SQL command completed successfully.

SOME OTHER SQL STATEMENT/QUERY

DB21034E  The command was processed as an SQL statement because it was not a 
valid Command Line Processor command.

РЕДАКТИРОВАТЬ 1: Первые 3 строки (включая пустую строку) указываютSQL-оператор выполнен успешно, в то время как следующие три показывают оператор и исключение, которое оно вызвало.Ответ darioo ниже, в котором предлагается использовать grep вместо Java, прекрасно работает для однострочного оператора SQL.

EDIT 2: Однако оператор / запрос SQL не обязательно должен быть одной строкой.Иногда это большой CREATE PROCEDURE...END PROCEDURE блок.Можно ли решить эту проблему, используя только команды Unix?

Теперь мне нужно проанализировать весь файл журнала, выбрать все вхождения пары (оператор SQL + ошибка) и записать их в отдельный файл.

Пожалуйста, покажи мне, как это сделать!

Ответы [ 5 ]

4 голосов
/ 10 января 2011

Мой ответ будет основан не на Java, поскольку это классический пример проблемы, которая может быть решена намного, намного проще.

Все, что вам нужно, это инструмент grep. Если вы работаете в Windows, вы можете найти его здесь .

Предполагая, что ваши журналы находятся в файле log.txt, решение вашей проблемы - один слой:

grep -hE --before-context 1 "^DB2[0-9]+E" log.txt > filtered.txt

Пояснение:

  • -h - не печатать имя файла
  • -E - поиск по регулярному выражению
  • --before-context 1 - это напечатает одну строку перед найденным сообщением об ошибке (это будет работать, если все ваши SQL-запросы находятся в одной строке)
  • ^DB2[0-9]+E - поиск строк, начинающихся с «DB2», имеющих некоторые цифры и заканчивающихся «E»

Выше выражение будет печатать каждую нужную строку в новом файле с именем filtered.txt.


Обновление : после некоторого возни, мне удалось получить то, что нужно, используя только стандартные * nix утилиты. Осторожно, это не красиво. Конечное выражение:

grep -nE "^DB2[0-9]+" log.txt | cut -f 1 -d " " | gawk "/E$/{y=$0;print x, y};{x=$0}" | sed -e "s/:DB2[[:digit:]]\+[IE]//g" | gawk "{print \"sed -n \\\"\" $1+1 \",\" $2 \"p\\\" log.txt \"}" | sed -e "s/$/ >> filtered.txt/g" > run.bat

Пояснение:

  • grep -nE "^DB2[0-9]+" log.txt - печатает строки, начинающиеся с DB2..., а их номер строки начинается. Пример: * * тысяча сорок-две
6:DB20000I  The SQL command completed successfully.
12:DB21034E  The command was processed as an SQL statement because it was not a valid Command Line Processor command.
19:DB21034E  The command was processed as an SQL statement because it was not a valid Command Line Processor command.
26:DB21034E  The command was processed as an SQL statement because it was not a valid Command Line Processor command.
34:DB20000I  The SQL command completed successfully.
41:DB20000I  The SQL command completed successfully.
47:DB21034E  The command was processed as an SQL statement because it was not a valid Command Line Processor command.
54:DB20000I  The SQL command completed successfully.
  • cut -f 1 -d " " - печатает только «первый столбец», то есть удаляет все после сообщения об ошибке. Пример: * * тысяча сорок восемь
6:DB20000I
12:DB21034E
19:DB21034E
26:DB21034E
34:DB20000I
41:DB20000I
47:DB21034E
54:DB20000I
  • gawk "/E$/{y=$0;print x, y};{x=$0}" - для каждой строки, заканчивающейся буквой «E» (строка ошибки), выведите строку перед ней, а затем строку ошибки. Пример: * * тысяча пятьдесят-четырь
6:DB20000I 12:DB21034E
12:DB21034E 19:DB21034E
19:DB21034E 26:DB21034E
41:DB20000I 47:DB21034E
  • sed -e "s/:DB2[[:digit:]]\+[IE]//g" - удаляет двоеточие и сообщение об ошибке, оставляя только номера строк. Пример:
6 12
12 19
19 26
41 47
  • gawk "{print \"sed -n \\\"\" $1+1 \",\" $2 \"p\\\" log.txt \"}" - форматирует вышеуказанные строки для обработки sed и увеличивает номер первой строки на единицу. Пример:
sed -n "7,12p" log.txt 
sed -n "13,19p" log.txt 
sed -n "20,26p" log.txt 
sed -n "42,47p" log.txt 
  • sed -e "s/$/ >> filtered.txt/g" - добавляет >> filtered.txt к строкам для добавления в конечный выходной файл. Пример: * * тысяча семьдесят три
sed -n "7,12p" log.txt  >> filtered.txt
sed -n "13,19p" log.txt  >> filtered.txt
sed -n "20,26p" log.txt  >> filtered.txt
sed -n "42,47p" log.txt  >> filtered.txt
  • > run.bat - наконец, печатает последние строки в пакетный файл с именем run.bat

После того, как вы запустите этот файл, требуемый контент появится в filtered.txt.

Обновление 2 :

Вот еще одна версия, которая работает в Ubuntu (предыдущая версия была написана для Windows):

grep -nE "^DB2[0-9]+" log.txt | cut -f 1 -d " " | gawk '/E/{y=$0;print x, y};{x=$0}' | sed -e "s/:DB2[[:digit:]]\+[IE]//g" | gawk '{print "sed -n \""$1+1" ,"$2 "p\" log.txt" }' | sed -e "s/$/ >> filtered.txt/g" > run.sh

Две вещи не работали с предыдущей версией:

  1. по какой-то причине gawk '/E$/' не работал (он не распознал, что E находится в конце строки), поэтому я просто поставил /E/, поскольку E больше нигде не будет найдено.
  2. цитируя, " были преобразованы в ' для gawk, поскольку он не любит двойные кавычки; после этого, цитата внутри последнего выражения gawk была изменена
1 голос
/ 10 января 2011

Попробуйте:

#!/usr/bin/awk -f
$1 ~ /^DB.*I$/ {lines=""; nl=""; next} # discard successes
$1 ~ /^DB.*E$/ {print lines; print $0; print "-----"; lines=""; next} # print error blocks
$0 !~ /^$/ { lines = lines nl $0; nl="\n" } # accumulate lines in block

Если вы не хотите удалять пустые строки, удалите $0 !~ /^$/.

Запустите это так:

./script.awk inputfile
1 голос
/ 10 января 2011

Лично я бы пошел по-другому. Вместо того, чтобы найти все ошибки, я бы удалил все успехи.

Примерно так:

  • Чтение файла журнала (используйте метод чтения, а не readLine, так как последний будет сбрасывать символы новой строки) в строку
  • Используйте следующее регулярное выражение с replaceAll (regex, "") в строке для удаления всех успешных записей: (?:.+\r\n)+\r\n+DB2.+I(?:.+\r\n)+
  • Запишите полученную строку в новый файл.

И в коде (просто вызовите processLog с объектом File для журнала):

private void openAndProcessLog(){
    JFileChooser chooser = new JFileChooser();
    chooser.showOpenDialog(this);
    if (chooser.getSelectedFile() != null) {
        processLog(chooser.getSelectedFile());
    }
}

private void processLog(File logfile){
    String originalLog = readFile(logfile);
    String onlyFailures = removeAllSuccessFull(originalLog);
    System.out.println(onlyFailures);
}

private String readFile(File file) {
    String ret = "";
    try {
        BufferedReader in = new BufferedReader(
                new FileReader(file));
        StringWriter out = new StringWriter();
        char[] buf = new char[10000];
        int n;
        while( (n = in.read(buf)) >= 0 ) {
            out.write(buf, 0, n);
        }
        ret = out.toString();
    } catch (IOException e) {
    }
    return ret;
}

private String removeAllSuccessFull(String text) {
    String sep = System.getProperty("line.separator");
    Pattern regex = Pattern.compile(
            "(?:.+"+sep+")+"+sep+"+DB2.+I(?:.+"+sep+")+");
    return regex.matcher(text).replaceAll("");
}
1 голос
/ 10 января 2011

Предполагается, что вы ищете блок непустых строк, за которым следует пустая строка, затем блок непустых строк, первая из которых начинается с DB, затем попробуйте:

Pattern regex = Pattern.compile(
    "(?:.+\\n)+    # Match one or more non-blank lines\n" +
    "\\n           # Match one blank line\n" +
    "DB(?:.+\\n)+  # Match one or more non-blank lines, the first one starting with DB", 
    Pattern.COMMENTS);
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    // matched text: regexMatcher.group()
    // match start: regexMatcher.start()
    // match end: regexMatcher.end()
}

Это предполагает пустую строку между каждым совпадением и предполагает окончание строки Unix. Если это файл DOS / Windows, то замените \\n на \\r\\n.

0 голосов
/ 10 января 2011

Если вы используете оболочку linux или cygwin в Windows, я бы порекомендовал вам использовать grep с флагами -a (после) и -b (до):

grep -a 2 "The SQL command completed successfully" mylog.log

Напечатает 2 строки после строки, соответствующей заданному шаблону.

если вы хотите написать свой собственный, я бы порекомендовал вам сделать следующее:

Перебирайте строки, пока не встретите линию, соответствующую вашему шаблону. Затем продолжите чтение N строк (например, 2 строки) и напечатайте их где-нибудь. Тогда продолжайте читать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...