вступление
Этот пост косвенно связан с моим мини-сериалом об анализе логов. Было бы здорово прочитать две основные части, чтобы лучше понять, о чем я говорю. Часть 1 , Часть 2 .
Этот пост описывает одну важную проблему, с которой я столкнулся при реализации подхода IDE.
Описание задания
Когда кто-то работает с журналами, обычно ему нужно исследовать только один интервал времени. Доступные журналы обычно охватывают дни, но интервал времени, который должен быть исследован, составляет 1-2 часа. Задача состоит в том, чтобы выбрать все записи журнала за этот интервал времени.
Основная запись журнала Regex
Чтобы выбрать запись журнала, нам нужно регулярное выражение, соответствующее любой записи журнала. Для простого формата log4j вроде
1
|
2018-08-10 11:00:56,234 DEBUG [Thread-1] package1.pkg2.Class1 Text Message |
Я нашел следующее регулярное выражение:
1
|
TIME_REGEX((?!(TIME_REGEX)).*\r?\n)* |
Это регулярное выражение соответствует как однострочным, так и многострочным записям журнала. Время может быть регулярным выражением
1
|
\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d,\d\d\d |
Поэтому, если кто-то хочет загрузить все журналы в текстовое окно, он может открыть файлы журнала один за другим и использовать Matcher.find () с этим регулярным выражением для получения всех записей журнала.
Это регулярное выражение основано на том факте, что шаблон регулярного выражения никогда не повторяется в теле сообщения журнала, что верно в 99% всех случаев.
Дата и время записи журнала
Для поиска определенного временного интервала и использования других функций имеет смысл извлечь информацию dtaetime из записи журнала. К счастью, эта задача была решена JDK с DateTimeFormatter. Достаточно указать формат для типа журнала и дату можно извлечь. Например, для записи журнала выше формат
1
|
yyyy-MM- dd HH:mm:ss,SSS |
Как только мы можем извлечь информацию о дате и времени, мы можем указать интервал как значения даты и времени, а не строки в каком-то определенном формате.
Время поиска
Теперь, когда мы нашли способ выбрать любую запись журнала и извлечь из нее информацию о дате, путь вперед кажется ясным:
- указать интервал,
- выберите записи по одной
- извлечь информацию о дате из записи журнала
- сравнить дату и время с интервалом
- если дата-время находится в пределах интервала, добавьте эту запись в список найденных записей.
- после поиска по всем файлам показать найденные записи
У этого подхода есть одна большая проблема:
время С 50 файлами журналов по 50 МБ каждый потребуется несколько часов, чтобы просканировать все их, чтобы найти 10 МБ записей в интервале.
Решение
Мы можем использовать один трюк, чтобы отфильтровать файлы, которые не содержат ни одной записи в интервале. Мы используем тот факт, что записи журнала в файлах журнала записываются одна за другой. Это означает, что время следующей записи равно или после времени этой записи. Например, возможны только 2 ситуации:
1
2
|
2018-08-10 11:00:56,234 DEBUG [Thread-1] package1.pkg2.Class1 Text Message 2018-08-10 11:00:56,234 DEBUG [Thread-1] package1.pkg2.Class1 Msg 2 |
Или же
1
2
|
2018-08-10 11:00:56,234 DEBUG [Thread-1] package1.pkg2.Class1 Text Message 2018-08-10 11:00:56,278 DEBUG [Thread-1] package1.pkg2.Class1 Msg 2 |
Я редко видел примеры, когда при высокой нагрузке записи журнала могут идти в обратном порядке, но разница в миллисекундах. Мы можем считать эту разницу незначительной для нашей цели.
Это означает, что если ни первая, ни последняя запись в файле не находятся в интервале, то все записи в файле не находятся в интервале, и этот файл можно отфильтровать. Регулярные выражения Java имеют специальные конструкции для поиска первой и последней записей.
Первая запись:
1
|
<b>\A< /b >TIME_REGEX((?!(TIME_REGEX)).*\r?\n)* |
Последняя запись:
1
|
TIME_REGEX((?!(TIME_REGEX)).*\r?\n)*<b>\Z< /b > |
\ A означает начало текста, \ Z означает конец текста. Вы можете найти более подробную информацию в javadocs для java.util.regex.Pattern.
Решение заключается в использовании специальной техники предварительного сканирования. Перед сканированием всего текста файла журнала найдите первую и последнюю записи и, если их нет в интервале, пропустите файл. Возможно, из 50 файлов 1-2 необходимо отсканировать.
Вывод
REAL использует эту технику для ускорения поиска для интервала даты и времени. Я обнаружил, что требуется приблизительно 5-10 секунд, чтобы решить, должен ли файл быть пропущен. Большую часть времени выполняет Matcher.find () для последней записи. Первая запись найдена намного быстрее. Я думаю, что можно ускорить его, выбрав последние 5 МБ из 50 МБ файла для поиска последней записи. Но даже в текущем состоянии это достаточно быстро.
Опубликовано на Java Code Geeks с разрешения Вадима Коркина, партнера нашей программы JCG . Смотреть оригинальную статью здесь: Поиск временного интервала в журналах
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |