null

Apache NiFi: заметки по ведению логов потоков данных

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

В первую очередь, вспомним, какие вообще бывают логи. В целом их 4 типа, хотя почти всегда нужен только один (nifi-app.log)

  • nifi-app.log - сообщения от процессоров внутри потока, собственно главное средство для отладки потока и понимания того, что вообще происходит в потоке, что было передано, что получено, какие данные обработаны со стороны NiFi;
  • nifi-user.log - сообщения, связанные с событиями аутентификации и авторизации пользователей, аудит безопасности и проверка пользователей, открывающих веб-интерфейс NiFi;
  • nifi-bootstrap.log - сообщения о запуске и остановке JVM, диагностика проблем с запуском и самой работоспособностью NiFi;
  • nifi-request.log - фиксация всех HTTP-запросов к NiFi, аудит веб-трафика (начиная с версии 1.16);
  • nifi-deprecation.log - логирование сведений об использовании устаревших процессоров (начиная с версии 1.18), используется для информации о наличии компонентов (или их отсутствии), препятствующих обновлению NiFi до новой версии (скажем, 2.x)

Все эти логи хранятся вместе в одной директории (обычно в /opt/nifi/nifi-current/logs, если NiFi развернут в Docker-контейнере, но зависит от специфики установки). Выглядит все это множество файлов например так:

Непосредственно файлы nifi-app.log, nifi-user.log, nifi-bootstrap.log и nifi-request.log представляют собой самые актуальные логи. Файлы же со временной отметкой являются логами историческими и описывают, что происходило с системой ранее. При этом важно четко осознавать, в какой момент логи сохраняются в файле с временной отметкой (то есть переходят в разряд прошедших событий) и каким образом NiFi понимает, что пора писать новый nifi-app.log файл. Далее мы будем рассматривать логирование в контексте nifi-app логов, поскольку их содержимое самое иформативное и интересует нас больше всего. Способы настройки логирования, о которых мы будет говорить далее, абсолютно идентичны и для остальных типов логов.

Итак, настройка же параметров логирования осуществляется в файле /opt/nifi/nifi-current/conf/logback.xml. В данном файла нас наиболее интересует вот этот фрагмент:

<appender name="APP_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${org.apache.nifi.bootstrap.config.log.dir}/nifi-app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--
              For daily rollover, use 'app_%d.log'.
              For hourly rollover, use 'app_%d{yyyy-MM-dd_HH}.log'.
              To GZIP rolled files, replace '.log' with '.log.gz'.
              To ZIP rolled files, replace '.log' with '.log.zip'.
            -->
            <fileNamePattern>${org.apache.nifi.bootstrap.config.log.dir}/nifi-app_%d.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <!-- keep 20 log files worth of history -->
            <maxHistory>20</maxHistory>
        </rollingPolicy>
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
        </encoder>
    </appender>

Значения внутри тегов здесь указаны не такие, как по умолчанию, но это не так важно. Как можно увидеть, в атрибут name записано "APP_FILE", а значит мы имеем дело с nifi-app.log, но с остальными типами все то же самое, конфигураторы для них расположены ниже в том же файле. При изменении любых настроек в этом файле не забудьте перезапустить NiFi для их применения.

Как мы видим, в файле уже есть комментарии, кратко поясняющие суть настройки логирования. Если в fileNamePattern указать 'app_%d.log', то новый отдельный файл с логами будет появляться каждый день. Если укажем 'app_%d{yyyy-MM-dd_HH}.log', то каждый час. Также доступно архивирование в zip и gzip. Но кроме этого есть еще две важные характеристики -- это максимальный размер одного файла (maxFileSize) и максимальное число файлов для хранения (maxHistory). Подчеркнем, что в парадигме NiFi число хранимых файлов с логами определяется не конкретными временными рамками, а параметром, задающим максимальное количество файлов. То есть мы храним логи не за "последние n дней", а строго в пределах максимально допустимого maxHistory. Переход к записи логов в новый файл начнется либо когда наступит новый день/час в зависимости от настроек, либо когда размер одного файла превысит maxFileSize. Обращу внимание, что в представленном выше фрагменте XML мы указали паттерн 'nifi-app_%d.%i.log', %i в нем означает индекс файла с логами. Это значит, что если в течение одного дня наберется больше 100МВ логов, то NiFi начнет писать логи уже в новый файл (на скриншотах выше можно заметить, например, файлы nifi-app_2025-12-09.0.log, nifi-app_2025-12-09.1.log и так далее).

Таким образом, основный посыл этой заметки в том, что при менеджменте логов в NiFi-трансферах надо обращать внимание на размер одного файла, на максимальное их количество, на частоту добавления нового файла с логами. Все эти параметры сильно зависят от специфики проекта, ресурсов сервера, пожеланий заказчика. Важно понимать, что если, например, у вас maxHistory равен 10, размер файла выставлен 50MB, а в один день данных внезапно пришло на 500МВ, то все предыдущие логи будут стерты и окажутся недоступны, что может быть проблемой, если необходимо проверить, что приходило в день предыдущий.

Обратим внимание, что в файле logback.xml также расположены уровни логирования для классов и пакетов Apache NiFi, где по желанию можно менять стандартные настройки, изменить WARN на INFO или на ERROR. Например:

<logger name="org.apache.nifi" level="INFO"/>
    <logger name="org.apache.nifi.processors" level="WARN"/>
    <logger name="org.apache.nifi.processors.standard.LogAttribute" level="INFO"/>
    <logger name="org.apache.nifi.processors.standard.LogMessage" level="INFO"/>
    <logger name="org.apache.nifi.controller.repository.StandardProcessSession" level="WARN" />

Поднимаясь же на уровень выше и переходя непосредственно к потоку обработки данных, то есть в веб-интерфейс NiFi, то для логирования мы используем самый обычный процессор LogAttribute, который для этого и предназначен. Здесь можно разве что отдельно выделить параметр Log prefix, который мы всегда заполняем, чтобы обозначить, что вообще логируется в данный момент (факт, что NiFi получил запрос, что обработал данные, что успешно отправил что-либо куда нужно и т.п.). Log Payload указывает на то, логировать ли тело FlowFile'а, или же сохранять в логах только атрибуты. Для атрибутов также хорошей практикой будет выбирать не все значения, а задавать лишь самые важные в свойстве Attributes to Log. Так получится сэкономить место на диске и в целом сохранить больше логов.

В конечном итоге информацию о прошедшем событии можно будет посмотреть в файле nifi-app.log (или в более поздних app файлах). Пример выше довольно простой, в нем мы предполагаем, что у нас NiFi получает запрос одного вида с параметрами ИД и тип, которые мы и хотим залогировать. Добавив процессор выше, мы обнаружим в логах нечто вроде указанного ниже, где префикс будет разделять нужную информацию с остальными логами:

------------[RECORD REQUEST RECEIVED]-------------
FlowFile Properties
Key: 'entryDate'
	Value: 'Thu Dec 18 15:19:17 UTC 2025'
Key: 'lineageStartDate'
	Value: 'Thu Dec 18 15:19:17 UTC 2025'
Key: 'fileSize'
	Value: '0'
FlowFile Attribute Map Content
Key: 'http.query.param.id'
	Value: '12375823'
Key: 'http.query.param.type'
	Value: 'Type1'
------------[RECORD REQUEST RECEIVED]-------------

 

Next