Просмотр логов Directum RX в Notepad++

26 2

По теме логов есть довольно много информации, которую можно найти в статьях, базе знаний и справке Directum. Я же постараюсь не повторяться и поделюсь своим небольшим опытом работы с этими файлами. Для матерых админов данный материал открытий не сделает, но начинающим может оказаться полезным и сэкономит пару нервных клеток.

Программы

Итак, что касается отлова ошибок на dev-стенде, часто удобно использовать DirectumLogViewer (можно найти в справке) или Grafana (пример по этой теме на club).
Но здесь я хочу рассмотреть случаи, когда нужно открыть файл лога в текстовом редакторе (например, если архив логов приехал с теста или продуктива). Посмотрим, что можно сделать с Notepad++.

Как искать

Когда требуется осуществить поиск "заковыристо", можно эффективно использовать регулярные выражения:

  • Запускаем поиск (Ctrl + F)
  • Режим поиска переключаем на регулярные выражения. Для этого необходимо выделить нужный переключатель: Search Mode - Regular expression (Режим поиска – Регулярные выражения)
  • Вводим запрос "маску" для поиска.

Использование регулярных выражений - это тема для отдельной статьи, да и в сети информации полно, так что подробно синтаксис я тут рассматривать не буду, но приведу небольшой пример использования для наглядности.
Допустим, нам нужно найти в логе ошибку, зная примерное время события. В запросе:

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 и установить.

Результат обработки плагином:

В целом полученный результат более читаемый, чем оригинал, однако меня не устроили некоторые нюансы:

  • Чтобы плагин отработал корректно необходимо предварительно выделить подходящий фрагмент текста, иначе он выкинет ошибку
  • Значение записи stack остается вытянутым в одну строку, из-за чего приходится использовать горизонтальный скроллинг
  • Горячие клавиши есть, но не самый удобный вариант, а как поменять я не нашел (дело привычки, но все же...)

Как альтернативный вариант - записать макрос, который будет делать примерно то же самое. Я такой макрос уже создал и могу поделиться его кодом. Макрос будет форматировать строку, на которой находится курсор, при нажатии сочетания клавиш 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="&quot;,\n\t&quot;" />
		<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="&quot;,\n\t&quot;--- 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='&quot;,&quot;' />
		<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
		<Action type="3" message="1602" wParam="0" lParam="0" sParam='&quot;,\n&quot;' />
		<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='{&quot;t&quot;' />
		<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
		<Action type="3" message="1602" wParam="0" lParam="0" sParam='\n{\n&quot;t&quot;' />
		<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="&quot;host&quot;" />
		<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
		<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n&quot;host&quot;" />
		<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="},&quot;ex&quot;" />
		<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
		<Action type="3" message="1602" wParam="0" lParam="0" sParam="},\n&quot;ex&quot;" />
		<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="&quot;stack&quot;" />
		<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
		<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n&quot;stack&quot;" />
		<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... (Макросы -> Изменить соч. клавиш/Удалить макро...).

Закладки

Помимо использования области с результатами поиска, можно оставлять закладки и пометки по файлу. Добавить закладки можно несколькими способами:

  • Комбинацией клавиш Ctrl+F2
  • через меню Search -> Bookmark -> Toggle Bookmark / Поиск -> Закладки -> Закладка
  • В области между номером строки и редактором можно кликнуть ЛКМ

Переключаться между закладками можно клавишами 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);

На этом у меня пока все, надеюсь кому-то данный материал будет полезным. Если кому-то известны более удобные инструменты для работы с логами или замечания к статье, прошу поделиться в комментариях.

26
Авторизуйтесь, чтобы оценить материал.
4
Константин Мосолов

Еще можно попробовать https://github.com/DirectumCompany/DirectumLogConverter 

Konstantin Bastylev

Спасибо за статью!

Расстановку основных меток по "тэгам" так же можно автоматизировать через макросы, ища в самом начале (или в конце) первые вхождения искомых слов и расставляя метки по стилям:

<Macro name="SetErrorMarks" Ctrl="no" Alt="no" Shift="no" Key="0">
  <Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
  <Action type="3" message="1601" wParam="0" lParam="0" sParam="Error" />
  <Action type="3" message="1625" wParam="0" lParam="0" sParam="" />
  <Action type="3" message="1702" wParam="0" lParam="768" sParam="" />
  <Action type="3" message="1701" wParam="0" lParam="1" sParam="" />
  <Action type="2" message="0" wParam="43026" lParam="0" sParam="" />
</Macro>

где для действия типа 2 wParam номер стиля вычисляется как 43022 + (n-1)*2 (43022, 43024, 43026, 43028, 43030)

 

 

Авторизуйтесь, чтобы написать комментарий