По теме логов есть довольно много информации, которую можно найти в статьях, базе знаний и справке Directum. Я же постараюсь не повторяться и поделюсь своим небольшим опытом работы с этими файлами. Для матерых админов данный материал открытий не сделает, но начинающим может оказаться полезным и сэкономит пару нервных клеток.
Итак, что касается отлова ошибок на dev-стенде, часто удобно использовать DirectumLogViewer (можно найти в справке) или Grafana (пример по этой теме на club).
Но здесь я хочу рассмотреть случаи, когда нужно открыть файл лога в текстовом редакторе (например, если архив логов приехал с теста или продуктива). Посмотрим, что можно сделать с Notepad++.
Когда требуется осуществить поиск "заковыристо", можно эффективно использовать регулярные выражения:
Использование регулярных выражений - это тема для отдельной статьи, да и в сети информации полно, так что подробно синтаксис я тут рассматривать не буду, но приведу небольшой пример использования для наглядности.
Допустим, нам нужно найти в логе ошибку, зная примерное время события. В запросе:
13:[3-4][0-9].*Error
<13:[3-4][0-9]> - временной диапазон, можно еще зафиксировать дату (<2022-09-07 13:[3-4][0-9]>).
<.*> - любое количество любых символов до следующего выражения.
<Error> - дополнительный фильтр (Может быть что-то другое, например ид процесса <"pid":"1+51">, пользователь, название функции из стека вызовов или комбинация фильтров с разделителем <.*>).
В результате поиска по этому запросу будут найдены все строки, в которых есть запись времени в диапазоне с 13:30 до 13:49 и включающие после текст "Error":
Пример использования нескольких критериев поиска для сужения выборки:
13:[3-4][0-9].*Error.*RabbitMQ
При необходимости можно использовать более сложные выражения, добавляя логические операторы:
pid":"1\+694".*(Error|Debug)
Добавлю еще что для сужения выборки в контекстном меню по ПКМ есть пункт Find in these search results... (Поиск в найденном...).
Допустим, мы нашли интересующую нас строку. Далее возникает вопрос удобочитаемости.
Можно выбрать синтаксис: Language (Синтаксисы) -> J -> JSON. Это немного "скрасит" однообразие оригинального оформления:
Уже лучше, но все равно не очень удобно.
В Notepad++ есть плагин для парсинга JSON. Для его установки нужно выполнить Plugins -> Plugins Admin... / Плагины (P) -> Администрирование плагинов ..., найти JSON Viewer и установить.
Результат обработки плагином:
В целом полученный результат более читаемый, чем оригинал, однако меня не устроили некоторые нюансы:
Как альтернативный вариант - записать макрос, который будет делать примерно то же самое. Я такой макрос уже создал и могу поделиться его кодом. Макрос будет форматировать строку, на которой находится курсор, при нажатии сочетания клавиш Alt + Enter.
</Macro>
<Macro name="row format RX log" Ctrl="no" Alt="yes" Shift="no" Key="13">
<Action type="0" message="2453" wParam="0" lParam="0" sParam="" />
<Action type="0" message="2453" wParam="0" lParam="0" sParam="" />
<Action type="0" message="2452" wParam="0" lParam="0" sParam="" />
<Action type="0" message="2452" wParam="0" lParam="0" sParam="" />
<Action type="0" message="2307" wParam="0" lParam="0" sParam="" />
<Action type="0" message="2307" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam="\\n at " />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam="",\n\t"" />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam="--- End" />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam="",\n\t"--- End" />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam='","' />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam='",\n"' />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam='{"t"' />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam='\n{\n"t"' />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam="}\n" />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n}\n\n" />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam=""host"" />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n"host"" />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam="},"ex"" />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam="},\n"ex"" />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
<Action type="3" message="1601" wParam="0" lParam="0" sParam=""stack"" />
<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n"stack"" />
<Action type="3" message="1702" wParam="0" lParam="896" sParam="" />
<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
</Macro>
Результат работы макроса:
Работу макроса проверял на Notepad++ версий 8.3.3 и 8.4.5. Чтобы сохранить макрос к себе, необходимо найти файл shortcuts.xml. Данный файл обычно находится в корне папки с установленным Notepad++ и в каталоге C:\Users\[user]\AppData\Roaming\Notepad++\shortcuts.xml. Далее нужно вручную поместить туда фрагмент приведенного выше кода, либо заменить файл полностью.
Файл оставлю тут: shortcuts.xml
Код должен находится внутри блока <Macros></Macros>. По умолчанию там уже может быть макрос "Trim Trailing Space and Save", новый можно добавить сразу под ним.
Важно! Править файлы shortcuts.xml нужно любым текстовым редактором кроме самого Notepad++ (он должен быть закрыт, иначе будет перезаписывать XML при выходе).
При желании можно изменить горячие клавиши активации прямо в коде или через меню Notepad++:
Macro -> Modify Shortcut/Delete Macro... (Макросы -> Изменить соч. клавиш/Удалить макро...).
Помимо использования области с результатами поиска, можно оставлять закладки и пометки по файлу. Добавить закладки можно несколькими способами:
Переключаться между закладками можно клавишами F2 и Shift+F2.
Кроме закладок есть такой инструмент, как Пометки. В окне поиска им отведен блок с командами (Меню Search -> Style All Occurrences of Token / Поиск -> Пометить все совпадения и элементы ниже до закладок). Мне удобнее пользоваться контекстным меню в редакторе текста по клику ПКМ.
Можно отметить одним из 5 стилей выделенный текст (Style one token/Пометить только одно) либо все совпадения по нему (Style all occurrences of token/Пометить все совпадения).
Пометки, порой, удобнее создавать через вкладку Mark (Пометки) окна поиска (Ctrl+M). В этом же окне можно установить чек-бокс Bookmark line (Помечать Закладкой), тогда найденные строки будут дополнительно помечены как закладки.
Пометки подсвечиваются по тексту выбранным стилем и по ним можно перемещаться сочетанием клавиш Ctrl+{1-5} и Ctrl+Shift+{1-5} (В зависимости от номера выбранного стиля) или Ctrl+0 и Ctrl+Shift+0 - для пометок, созданных из окна поиска.
Внимание! Закладки и пометки не сохраняются вместе с файлом при его закрытии. Но если очень хочется, то есть способ восстановить закладки позже, предварительно сохранив сессию: File -> Save Session... (Файл -> Сохранить сессию...). Позже этот файл можно загрузить, закладки восстановятся.
Однажды один разработчик добавлял логирование в код. При тестировании возникла ошибка. После долгих поисков оказалось, что ее вызывает само логирование. Говорят, хорошо учится на чужих ошибках, так что передаю опыт в массы
Сигнатура функции логирования ошибок выглядит так:
public static void ErrorFormat(string format, Exception exception, params object[] args);
Тут нужно обратить внимание, что параметр exception передается вне массива параметров для сообщения, т.е.:
// Не корректно и вызовет ошибку
Logger.ErrorFormat("{0}. Exception for document (ID={1})", ex, document.Id);
// Корректно
Logger.ErrorFormat("Exception for document (ID={0})", ex, document.Id);
На этом у меня пока все, надеюсь кому-то данный материал будет полезным. Если кому-то известны более удобные инструменты для работы с логами или замечания к статье, прошу поделиться в комментариях.
Еще можно попробовать https://github.com/DirectumCompany/DirectumLogConverter
Спасибо за статью!
Расстановку основных меток по "тэгам" так же можно автоматизировать через макросы, ища в самом начале (или в конце) первые вхождения искомых слов и расставляя метки по стилям:
где для действия типа 2 wParam номер стиля вычисляется как 43022 + (n-1)*2 (43022, 43024, 43026, 43028, 43030)
Авторизуйтесь, чтобы написать комментарий