Практика: Простое журналирование
Введение в журналирование: Зачем и что логировать?
> ℹ️ Информация: Правильно настроенное журналирование — это ваш «черный ящик», который поможет понять, что пошло не так в ваше отсутствие. Без логов вы будете пытаться диагностировать проблему "вслепую", полагаясь лишь на догадки.
Журналирование (или логирование) — это процесс систематической записи информации о событиях, происходящих в системе. Для инженера по автоматизации это один из важнейших инструментов, который служит трем ключевым целям.* Как часто открывается входная дверь в течение дня?
* Сколько часов в среднем работает система отопления в зимний период?
* Есть ли закономерности в ложных срабатываниях датчика протечки?
Анализ этих данных помогает оптимизировать сценарии, экономить ресурсы и повышать комфорт.
Чтобы логи были полезными и не превращались в информационный шум, необходимо придерживаться простого правила: логировать только значимые события.
📋 Ключевые понятия: Что следует и не следует логировать
| Критерий | Что следует логировать (Примеры) | Что НЕ следует логировать (Примеры) |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Изменения состояния | Включение/выключение света, открытие/закрытие двери (сработал геркон), изменение режима климат-контроля (с "Нагрев" на "Охлаждение"). | Постоянное значение температуры от датчика, если оно не меняется. |
| Команды | Команда от пользователя из мобильного приложения, нажатие настенного выключателя, команда от другого системного сценария. | Внутренние, служебные сообщения между узлами в Node-RED, которые служат лишь для передачи промежуточных данных. |
| Ошибки и исключения | Ошибка связи с Modbus-устройством, невалидные данные от датчика, сбой при отправке MQTT-сообщения, ошибка выполнения узла `function`. | Любые успешно выполненные, но рутинные операции. |
| Частота событий | Редкие, но важные события: срабатывание датчика протечки, датчика дыма, потеря связи с контроллером. | Высокочастотные данные: показания счетчика электроэнергии каждые 100 мс, сырые данные с акселерометра. Такие потоки данных могут быстро исчерпать место на диске. |
Важно также различать системные логи операционной системы контроллера (Debian) и прикладные логи, которые мы создаем целенаправленно для системы автоматизации.
- Системные логи (syslog, journald): Хранятся в `/var/log/syslog` или доступны через команду `journalctl`. Они содержат информацию о работе самой ОС, драйверов, сетевых подключений и сервисов, включая сам Node-RED. Сюда попадают ошибки запуска Node-RED, проблемы с USB-портами (например, RS-485 адаптером) и т.д.
- Прикладные логи автоматизации: Это файлы, которые мы создаем сами в Node-RED. Они содержат информацию в понятном нам формате о событиях в логике умного дома: "Датчик движения в коридоре сработал", "Свет в гостиной включен" и т.п. Именно созданию таких логов посвящен этот урок.
---
Инструменты для записи логов в Node-RED
Платформа Node-RED предоставляет несколько встроенных инструментов для журналирования, каждый из которых подходит для своей задачи.
Узел `debug`
Это основной инструмент для отладки в реальном времени. Он выводит полученное им сообщение `msg` на боковую панель редактора Node-RED.
- Режимы вывода:
* Системная консоль: Выводит лог в ту же консоль, где был запущен Node-RED. На контроллере HI это можно просмотреть командой `journalctl -f -u nodered`. Этот режим полезен для отслеживания событий без входа в редактор.
- Настройка вывода: В настройках узла можно выбрать, что именно выводить:
* Полный объект `msg`: Крайне полезно для отладки сложных потоков, так как позволяет увидеть все свойства сообщения (`topic`, `_msgid`, и любые другие, добавленные предыдущими узлами).
> 💡 Подсказка: Узлы `debug` можно временно отключать и включать кнопкой на самом узле прямо в редакторе, не останавливая поток. Это позволяет быстро фокусироваться на нужных участках логики.
Узел `file` для прямой записи в файл
Для постоянного журналирования, которое должно сохраняться между перезагрузками и анализироваться позже, используется узел `file`. Он записывает `msg.payload` в указанный файл.
- Filename (Имя файла): Здесь указывается полный путь к файлу на диске контроллера, например, `/var/log/home-automation/events.log`.
- Action (Действие):
* overwrite file (перезаписать файл): Полностью заменяет содержимое файла. Используется редко.
- Create directory if it doesn't exist? (Создать директорию?): Полезная опция, которая автоматически создаст папку (например, `home-automation`), если ее нет.
> ⚠️ Внимание: Для записи в системные папки (например, `/var/log`) у пользователя, от имени которого запущен Node-RED (обычно `nodered`), должны быть права на запись. Этот аспект мы разберем в практической части.
Формирование читаемой строки для лога
Просто записывать `msg.payload` (который часто является JSON-объектом или простым числом) в файл — не лучшая практика. Лог должен быть информативным. Каждая строка должна содержать как минимум временную метку и контекст события. Для этого перед узлом `file` ставят узел `function` или `template`.
Пример с использованием узла `function`:Предположим, на вход приходит сообщение от датчика. Мы хотим записать в лог время, топик и значение.
// Код для узла function
// 1. Получаем текущее время в стандартном формате ISO
const timestamp = new Date().toISOString();
// 2. Получаем топик, из которого пришло сообщение
const topic = msg.topic;
// 3. Получаем значение. Если это объект, преобразуем его в строку JSON.
let payload_str;
if (typeof msg.payload === 'object') {
payload_str = JSON.stringify(msg.payload);
} else {
payload_str = msg.payload;
}
// 4. Формируем единую строку для записи в лог-файл
// Формат: ВРЕМЯ | ТОПИК | ЗНАЧЕНИЕ
msg.payload = `${timestamp} | ${topic} | ${payload_str}\n`; // \n добавляет перенос строки
// 5. Передаем сообщение дальше на узел 'file'
return msg;
Кроме того, узел `file` позволяет динамически задавать имя файла через свойство `msg.filename`. Это открывает возможности для более сложной организации логов, например, записывать события от разных подсистем (освещение, безопасность, климат) в разные файлы.
---
Практика: Создание простого лог-файла для датчика двери
В этой практической части мы создадим поток, который будет записывать все события от датчика открытия/закрытия входной двери (геркона) в отдельный текстовый файл.
> 💡 Подсказка: Для удобного форматирования дат и времени в человекочитаемый вид (например, `27.10.2023 13:45:10`) можно использовать сторонний модуль `node-red-contrib-moment`. Он предоставляет готовый узел, который преобразует `timestamp` в любой заданный формат. Для простоты в этом уроке мы будем использовать стандартный формат ISO.
Пошаговое создание потока
Мы создадим цепочку из трех узлов: `mqtt in` -> `function` -> `file`.
Шаг 1: Подписка на событие от датчика
> 🔗 Связанный материал: Мы подробно анализировали структуру MQTT-топиков и контракты сообщений от оборудования в уроке `COURSE-01-M02-L06: Практика: Анализ контракта события`. Сообщение в этом топике будет содержать `1` (дверь закрыта/контакт замкнут) или `0` (дверь открыта/контакт разомкнут).
Шаг 2: Форматирование строки для лога
// Код для узла function "Format Door Log"
const timestamp = new Date().toISOString();
const topic = msg.topic;
const value = msg.payload;
let state_text;
if (value == '1') {
state_text = 'CLOSED';
} else if (value == '0') {
state_text = 'OPENED';
} else {
state_text = 'UNKNOWN_STATE';
}
// Формируем итоговую строку для лога.
// Пример: 2023-10-27T12:30:05.123Z | /devices/wb-gpio/controls/EXT1_IN | State: OPENED
msg.payload = `${timestamp} | ${topic} | State: ${state_text}\n`;
return msg;
Этот код не просто записывает `0` или `1`, а добавляет понятное текстовое описание `OPENED`/`CLOSED`, что делает лог значительно более читаемым для человека.
Шаг 3: Запись в файл и настройка прав доступа
* File path (Путь к файлу): `/var/log/home-automation/door_events.log`
* Action (Действие): `append to file` (добавлять в файл)
* Create directory...: Установите галочку.
После развертывания (Deploy) поток готов, но, скорее всего, он не сможет записать файл, так как у него нет прав. Узел `file` покажет красный индикатор ошибки.
Проверка и установка прав доступа в Linux
sudo mkdir -p /var/log/home-automation
sudo chown nodered:nodered /var/log/home-automation
cat /var/log/home-automation/door_events.log
Вы должны увидеть строки вида:
2023-10-27T12:30:05.123Z | /devices/wb-gpio/controls/EXT1_IN | State: OPENED
2023-10-27T12:30:08.456Z | /devices/wb-gpio/controls/EXT1_IN | State: CLOSED
Поздравляем! Вы создали свой первый автоматизированный журнал событий.
---
Управление лог-файлами: Ротация и очистка в Linux
Созданный нами лог-файл будет постоянно расти. На контроллере с ограниченным объемом памяти (например, eMMC на 8-16 ГБ или SD-карта) это неизбежно приведет к исчерпанию дискового пространства и отказу системы. Чтобы этого не произошло, используется механизм ротации логов.
> ⚠️ Внимание: Неправильная конфигурация `logrotate`, особенно в сочетании с неверными правами доступа, может привести к полной остановке записи логов. Перед применением на боевой системе всегда проверяйте конфигурацию командой `sudo logrotate --force --verbose /etc/logrotate.conf`.
Утилита `logrotate`
В Debian (и большинстве других дистрибутивов Linux) за ротацию логов отвечает стандартная утилита `logrotate`. Она запускается по расписанию (обычно раз в день) и обрабатывает файлы согласно правилам, описанным в конфигурационных файлах.
Основной принцип работы `logrotate`:
Создание конфигурации для нашего лога
Все пользовательские конфигурации для `logrotate` следует размещать в директории `/etc/logrotate.d/`.
sudo nano /etc/logrotate.d/home-automation
/var/log/home-automation/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 nodered nodered
size 10M
}
Разбор директив `logrotate`
Давайте разберем, что означает каждая строка в нашей конфигурации.
| Директива | Описание |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/var/log/home-automation/*.log` | Применить правила ко всем файлам, заканчивающимся на `.log` в указанной директории. |
| `daily` | Проверять файлы для ротации ежедневно. Альтернативы: `weekly`, `monthly`. |
| `rotate 7` | Хранить 7 старых копий лог-файлов. После создания 8-й копии, самая старая будет удалена. |
| `compress` | Сжимать старые лог-файлы с помощью `gzip` (они получат расширение `.gz`), чтобы экономить место. |
| `delaycompress` | Не сжимать самый последний (вчерашний) лог. Сжатие начнется со второго по старости файла. Это удобно, если нужно часто просматривать вчерашние события. |
| `missingok` | Не выдавать ошибку, если лог-файл не найден. |
| `notifempty` | Не проводить ротацию, если лог-файл пуст. |
| `create 0640 nodered nodered` | После ротации создать новый пустой файл с правами `0640` (чтение/запись для владельца, чтение для группы) и установить владельца и группу `nodered`. Это критически важная директива для Node-RED! |
| `size 10M` | Проводить ротацию, если размер файла превысит 10 мегабайт, даже если не прошел день (`daily`). Это защита от "всплеска" событий. |
После сохранения этого файла система `logrotate` автоматически подхватит его и начнет управлять вашими логами, предотвращая переполнение диска и обеспечивая надежное хранение истории событий за последнюю неделю.