Мониторинг Apache Tomcat с помощью Proto Observability

Сбор метрик и логов Apache Tomcat: пулы потоков, коннекторы, сервлеты, JSP, кэши и JVM.

На этой странице:

Сбор метрик Tomcat

Интеграция tomcat собирает метрики Apache Tomcat через JMX. Проверка опрашивает MBean’ы в домене Catalina (или Tomcat — у некоторых сборок) и стандартные java.lang:* / java.nio:* beans JVM. Из коробки покрываются:

  • пулы потоков коннекторов (Catalina:type=ThreadPool);
  • глобальные счётчики запросов коннектора (Catalina:type=GlobalRequestProcessor);
  • сервлеты каждого веб-модуля (Catalina:j2eeType=Servlet);
  • JSP-мониторы веб-модулей (Catalina:type=JspMonitor);
  • строковый кэш (Catalina:type=StringCache) и кэш веб-ресурсов (Catalina:type=WebResourceRoot,name=Cache);
  • пул JDBC-соединений Tomcat, если он используется (Catalina:type=DataSource);
  • стандартные метрики JVM (heap/non-heap, GC, потоки, классы, буферы, дескрипторы).

Конфигурация Tomcat

JMX Remote должен быть включён и доступен с хоста, на котором работает агент. catalina.sh уважает переменные окружения CATALINA_OPTS и JAVA_OPTS, поэтому отдельный JmxRemoteLifecycleListener в server.xml не нужен — достаточно передать JVM-флаги.

Создайте (или дополните) файл <CATALINA_BASE>/bin/setenv.shcatalina.sh подхватывает его автоматически:

# <CATALINA_BASE>/bin/setenv.sh
export CATALINA_OPTS="$CATALINA_OPTS \
  -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9010 \
  -Dcom.sun.management.jmxremote.rmi.port=9010 \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Dcom.sun.management.jmxremote.local.only=false \
  -Djava.rmi.server.hostname=<имя_хоста_или_адрес_интерфейса>"

Закрепление jmxremote.rmi.port на том же значении, что и jmxremote.port, даёт один порт для RMI-реестра и для RMI-объектов — удобно для проброса через firewall / docker. На проде включите аутентификацию JMX (-Dcom.sun.management.jmxremote.authenticate=true + password/access файлы) и TLS вместо ssl=false.

После правок перезапустите Tomcat.

Те же флаги пробрасываются через environment: (значение CATALINA_OPTS автоматически попадает в JVM):

services:
  tomcat:
    image: tomcat:9.0-jdk17-temurin
    environment:
      CATALINA_OPTS: >-
        -Dcom.sun.management.jmxremote
        -Dcom.sun.management.jmxremote.port=9010
        -Dcom.sun.management.jmxremote.rmi.port=9010
        -Dcom.sun.management.jmxremote.authenticate=false
        -Dcom.sun.management.jmxremote.ssl=false
        -Dcom.sun.management.jmxremote.local.only=false
        -Djava.rmi.server.hostname=tomcat   # имя сервиса в docker network        
    ports:
      - "8080:8080"   # HTTP-коннектор
      - "9010:9010"   # JMX

Конфигурация ProtoOBP агента

Если агент запускается в виде службы на хосте

  1. Создайте файл /etc/protoobp-agent/conf.d/tomcat.d/conf.yaml:

    init_config:
      is_jmx: true
      collect_default_metrics: true
      # Современные имена GC-метрик: jvm_gc_minor_collection_count и т.п.
      # вместо jvm_gc_parnew_time / jvm_gc_cms_count.
      new_gc_metrics: true
    
    instances:
      - host: localhost
        port: 9010
        # user: monitorRole       # если на JMX включена аутентификация
        # password: <пароль>
        name: tomcat_instance
    
  2. Перезапустите агента: systemctl restart protoobp-agent.

Если агент запускается в виде Docker контейнера

Добавьте autodiscovery-лейблы к контейнеру Tomcat. В docker-compose.yaml:

services:
  tomcat:
    labels:
      com.protoobp.ad.check_names: '["tomcat"]'
      com.protoobp.ad.init_configs: '[{"is_jmx": true, "collect_default_metrics": true, "new_gc_metrics": true}]'
      com.protoobp.ad.instances: '[{"host": "%%host%%", "port": "9010", "name": "tomcat_instance"}]'

Проверка

Убедитесь, что проверка запустилась и собирает метрики:

docker exec protoobp-agent agent status | grep -A 8 "^    tomcat$"

Ожидаемый вывод — status : OK и metric_count > 0:

    tomcat
      instance_name : tomcat_instance
      message : <no value>
      metric_count : 157
      service_check_count : 0
      status : OK

Полный список найденных JMX-атрибутов (видны beans ThreadPool, GlobalRequestProcessor, Servlet, JspMonitor, WebResourceRoot, StringCache и стандартные java.lang:*):

docker exec protoobp-agent agent jmx list collected

Собираемые метрики

Все метрики собираются по JMX и имеют тип gauge — содержат мгновенное значение на момент сбора. Метрики, имена которых заканчиваются на _count (tomcat_request_count, tomcat_error_count, tomcat_bytes_sent, tomcat_bytes_rcvd, tomcat_processing_time, tomcat_servlet_*_count, tomcat_servlet_processing_time, tomcat_jsp_*, tomcat_string_cache_*_count, tomcat_web_cache_*_count), не являются кумулятивными счётчиками: в JMX они отдаются как монотонные счётчики, а интеграция конвертирует их в rate в секунду на стороне агента. (Метрики JDBC-пула — обычные gauge, без конверсии.)

Лейблы

Общие (на всех метриках)

Добавляются агентом и ProtoOBP backend’ом:

ЛейблЗначение
hostХост, на котором работает агент
instancename из instances: конфига проверки (tomcat_instance и т.п.)
jmx_domainДомен MBean’а — Catalina (или Tomcat) для метрик Tomcat; java.lang / java.nio для метрик JVM
serviceТег service (через com.protoobp.tags.service или POBP_TAGS)
envТег env
docker_imageПолный ref образа контейнера (например, tomcat:9.0-jdk17-temurin)
image_nameИмя образа без тега
image_tagТег образа
short_imageКороткое имя образа
Специфичные для конкретных beans

Извлекаются из имени MBean’а:

ЛейблНа каких метрикахПример
typeThreadPool, GlobalRequestProcessor, StringCache, WebResourceRoot, MemoryPool, BufferPool, …ThreadPool, GlobalRequestProcessor
nameпулы потоков и коннекторы — имя коннектора; WebResourceRootCache; MemoryPool/BufferPool — имя пула; сервлеты — имя сервлета"http-nio-8080", Cache, G1 Eden Space, default
j2ee_typebeans сервлетов (Catalina:j2eeType=Servlet)Servlet
webmodulebeans сервлетов и JspMonitor — путь развёрнутого веб-модуля//localhost/examples
host
(в имени bean’а WebResourceRoot)
tomcat_web_cache_* — виртуальный хост Tomcatlocalhost
contexttomcat_web_cache_* — контекст веб-приложения/, /docs

Имя коннектора Tomcat в JMX заключено в двойные кавычки (name="http-nio-8080") — в лейблах они сохраняются.

Метрики JVM

Стандартный набор JMXFetch (collect_default_metrics: true). Несут лейблы jmx_domain (java.lang / java.nio), type и name (для memory/buffer пулов).

Имя метрикиЕдиницаОписание
jvm_heap_memorybyteИспользовано heap-памяти JVM
jvm_heap_memory_committedbyteHeap-память, зарезервированная под использование
jvm_heap_memory_initbyteНачально выделенная heap-память
jvm_heap_memory_maxbyteМаксимально доступная heap-память
jvm_non_heap_memorybyteИспользовано non-heap памяти (Metaspace, CompressedClassSpace, CodeCache)
jvm_non_heap_memory_committedbyteNon-heap память, зарезервированная под использование
jvm_non_heap_memory_initbyteНачально выделенная non-heap память
jvm_non_heap_memory_maxbyteМаксимально доступная non-heap память
jvm_gc_eden_sizebyteЗанято в Eden Space
jvm_gc_survivor_sizebyteЗанято в Survivor Space
jvm_gc_old_gen_sizebyteЗанято в Old Generation
jvm_gc_metaspace_sizebyteЗанято в Metaspace
jvm_gc_major_collection_countcollection/sЧастота major (full) GC (при new_gc_metrics: true)
jvm_gc_minor_collection_countcollection/sЧастота minor (young) GC (при new_gc_metrics: true)
jvm_gc_major_collection_timems/sВремя, проведённое в major GC (при new_gc_metrics: true)
jvm_gc_minor_collection_timems/sВремя, проведённое в minor GC (при new_gc_metrics: true)
jvm_thread_countthreadКоличество живых потоков JVM
jvm_loaded_classesclassКоличество загруженных классов
jvm_cpu_load_processpercentЗагрузка CPU процессом JVM
jvm_cpu_load_systempercentЗагрузка CPU всей системы
jvm_os_open_file_descriptorsdescriptorКоличество открытых файловых дескрипторов
jvm_buffer_pool_direct_usedbyteИспользуется в пуле direct-буферов NIO
jvm_buffer_pool_direct_countbufferКоличество direct-буферов NIO
jvm_buffer_pool_direct_capacitybyteЁмкость пула direct-буферов NIO
jvm_buffer_pool_mapped_usedbyteИспользуется в пуле mapped-буферов NIO
jvm_buffer_pool_mapped_countbufferКоличество mapped-буферов NIO
jvm_buffer_pool_mapped_capacitybyteЁмкость пула mapped-буферов NIO

Метрики коннекторов и пулов потоков

tomcat_threads_* — из bean’а ThreadPool (по одному на коннектор; лейбл name = имя коннектора, например "http-nio-8080"). tomcat_bytes_*, tomcat_*_count, tomcat_*_time — из bean’а GlobalRequestProcessor (агрегат по всем процессорам запросов коннектора).

Имя метрикиЕдиницаОписание
tomcat_threads_busythreadКоличество занятых рабочих потоков пула
tomcat_threads_countthreadТекущее количество потоков, которыми управляет пул
tomcat_threads_maxthreadМаксимально допустимое количество рабочих потоков
tomcat_threads_minthreadМинимальное количество резервных потоков (minSpareThreads)
tomcat_request_countrequest/secondСкорость обработки запросов всеми процессорами запросов коннектора
tomcat_error_counterror/secondСкорость ошибочных ответов на всех процессорах запросов
tomcat_bytes_sentbyte/secondСкорость отдачи данных всеми процессорами запросов
tomcat_bytes_rcvdbyte/secondСкорость приёма данных всеми процессорами запросов
tomcat_processing_timemillisecond/secondСуммарное время обработки запросов (в мс) в секунду — растёт быстрее при росте latency или RPS
tomcat_max_timemillisecondСамое долгое время обработки одного запроса
tomcat_min_timemillisecondСамое быстрое время обработки одного запроса

Метрики сервлетов

Из beans Catalina:j2eeType=Servlet. Несут лейблы j2ee_type=Servlet, webmodule (путь веб-модуля, например //localhost/examples) и name (имя сервлета).

Имя метрикиЕдиницаОписание
tomcat_servlet_request_countrequest/secondСкорость запросов к сервлету
tomcat_servlet_error_counterror/secondСкорость ошибочных запросов к сервлету
tomcat_servlet_processing_timemillisecond/secondСуммарное время обработки запросов сервлетом (в мс) в секунду
tomcat_servlet_max_timemillisecondМаксимальное время обработки одного запроса сервлетом
tomcat_servlet_min_timemillisecondМинимальное время обработки одного запроса сервлетом

Метрики JSP и кэшей

tomcat_jsp_* — из beans Catalina:type=JspMonitor (лейблы webmodule, name=jsp). tomcat_string_cache_* — из глобального Catalina:type=StringCache. tomcat_web_cache_* — из beans Catalina:type=WebResourceRoot,name=Cache (лейблы host = виртуальный хост Tomcat, context = контекст веб-приложения, name=Cache).

Имя метрикиЕдиницаОписание
tomcat_jsp_countpage/secondСкорость загрузки (компиляции) JSP в веб-модуле
tomcat_jsp_reload_countpage/secondСкорость перезагрузки JSP в веб-модуле
tomcat_string_cache_access_countget/secondСкорость обращений к строковому кэшу
tomcat_string_cache_hit_counthit/secondСкорость попаданий в строковый кэш
tomcat_string_cache_sizebyteТекущий размер строкового кэша
tomcat_string_cache_max_sizebyteМаксимальный размер строкового кэша
tomcat_web_cache_hit_counthit/secondСкорость попаданий в кэш веб-ресурсов контекста
tomcat_web_cache_lookup_countget/secondСкорость обращений к кэшу веб-ресурсов контекста

Метрики пула JDBC-соединений

Появляются только если приложение использует Catalina:type=DataSource (Tomcat JDBC Connection Pool). Обычные gauge.

Имя метрикиЕдиницаОписание
tomcat_jdbc_connection_pool_activeconnectionУстановленных соединений пула, занятых сейчас
tomcat_jdbc_connection_pool_idleconnectionУстановленных соединений пула в простое
tomcat_jdbc_connection_pool_sizeconnectionВсего установленных соединений пула (занятые + простаивающие)
tomcat_jdbc_connection_pool_max_activeconnectionМаксимальное число открытых соединений
tomcat_jdbc_connection_pool_max_idleconnectionМаксимальное число простаивающих соединений
tomcat_jdbc_connection_pool_min_idleconnectionМинимальное число простаивающих соединений

Метрик уровня HTTP-сессий (Catalina:type=Manager) в стандартном наборе интеграции нет — если они нужны, добавьте свой блок conf.yaml с JMX-bean’ом Catalina:type=Manager (атрибуты activeSessions, sessionCounter, expiredSessions, rejectedSessions, …).

Ключевые метрики для дашбордов и алертов

Доступность

  • Отсутствие свежих серий по instance — алерт: Tomcat недоступен или JMX отвалился (агент не получает метрики). Сервис-проверка tomcat_can_connect — индикатор того, что JMX-подключение установлено.

Насыщение пула потоков

  • tomcat_threads_busy / tomcat_threads_max per name (коннектор) — основной SLI. Приближение к 1 → пул исчерпан, новые запросы ждут в очереди acceptor’а. Алерт при > 0.85–0.9.
  • Рост tomcat_threads_count к tomcat_threads_max — пул расширяется под нагрузкой; если упёрся в max и busy тоже у потолка — пора увеличивать maxThreads или масштабировать.

Поток запросов

  • tomcat_request_count per name — RPS коннектора.
  • tomcat_bytes_rcvd / tomcat_bytes_sent — объём входящего/исходящего трафика; резкий рост bytes_sent без роста request_count = крупные ответы.
  • На уровне приложения — tomcat_servlet_request_count per webmodule / name.

Ошибки

  • tomcat_error_count per name — частота ошибочных ответов коннектора; алерт при ненулевом или превышении доли от request_count.
  • tomcat_servlet_error_count per webmodule / name — какой именно сервлет «фонит» ошибками.

Latency

  • tomcat_processing_time (rate, мс/с) растёт пропорционально RPS × среднему времени запроса — резкий рост при стабильном request_count = деградация.
  • tomcat_max_time — пиковая длительность запроса коннектора; на уровне сервлета — tomcat_servlet_max_time / tomcat_servlet_processing_time.

JVM

  • jvm_heap_memory / jvm_heap_memory_max близко к 1 — приближение к OOM; смотрите вместе с jvm_gc_major_collection_count / jvm_gc_major_collection_time (частые/долгие full GC = «GC trashing»).
  • jvm_thread_count неконтролируемо растёт — утечка потоков.
  • jvm_os_open_file_descriptors у потолка ulimit — утечка дескрипторов (незакрытые соединения/файлы).

Кэши

  • tomcat_web_cache_hit_count / tomcat_web_cache_lookup_count — hit-ratio кэша веб-ресурсов; низкий ratio при высоком lookup_count = кэш мал (cacheMaxSize) или приложение постоянно читает новые ресурсы.

Сбор логов Tomcat

Логи Tomcat собираются ProtoOBP агентом и отправляются в бэкенд ProtoOBP. Здесь — только специфичные для Tomcat настройки. Включение логов на стороне агента (logs_enabled, logs_pobp_url) описано в Получение данных логов.

Конфигурация ProtoOBP агента

Если агент запускается в виде службы на хосте

Дополните уже существующий /etc/protoobp-agent/conf.d/tomcat.d/conf.yaml (тот же файл, в котором лежит instances: для JMX) блоком logs::

logs:
  - type: file
    path: <CATALINA_BASE>/logs/catalina.out
    source: tomcat
    service: tomcat
    log_processing_rules:
      - type: multi_line
        name: log_start_with_date
        pattern: \d{2}-\w{3}-\d{4}
  # Если включён AccessLogValve (по умолчанию пишет в файл, не в stdout):
  - type: file
    path: <CATALINA_BASE>/logs/localhost_access_log.*.txt
    source: tomcat
    service: tomcat

<CATALINA_BASE> — каталог инстанса Tomcat (часто совпадает с CATALINA_HOME, например /opt/tomcat или /usr/local/tomcat). catalina.out — это перенаправленный stdout/stderr процесса Tomcat (то, куда ConsoleHandler JULI печатает строки лога); access-лог появляется, только если в server.xml сконфигурирован AccessLogValve.

Перезапустите агента: systemctl restart protoobp-agent.

Если агент запускается в виде Docker контейнера

Шаг 1 — включите сбор логов в самом агенте через переменные окружения и смонтируйте директорию JSON-логов docker-демона:

services:
  protoobp-agent:
    environment:
      POBP_LOGS_ENABLED: "true"
      POBP_LOGS_CONFIG_USE_HTTP: "true"
      POBP_LOGS_CONFIG_LOGS_POBP_URL: <protoobp-backend>:<port>
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      # Прямое чтение JSON-лог файлов docker-демона быстрее,
      # чем тянуть их через Docker socket API.
      - /var/lib/docker/containers:/var/lib/docker/containers:ro

Шаг 2 — добавьте лейбл com.protoobp.ad.logs к контейнеру Tomcat. Агент подхватит stdout/stderr контейнера (официальный образ tomcat пишет туда catalina.out) и пометит записи указанными source и service:

services:
  tomcat:
    labels:
      com.protoobp.ad.logs: '[{"source": "tomcat", "service": "tomcat", "log_processing_rules": [{"type": "multi_line", "name": "log_start_with_date", "pattern": "\\d{2}-\\w{3}-\\d{4}"}]}]'

Проверка

В выводе agent status должен быть раздел Logs Agent с источником tomcat и ненулевым BytesRead:

docker exec protoobp-agent agent status \
  | sed -n '/^==== Logs Agent ====/,/^====/p'
  docker
  ------
    - Type: file
      Path: /var/lib/docker/containers/<id>/<id>-json.log
      Service: tomcat
      Source: tomcat
      BytesRead: 13158

(Поле Status у источника типа «JSON-файл docker-контейнера» может отображаться как Pending даже при активном чтении — ориентируйтесь на ненулевой BytesRead и на рост LogsProcessed в шапке раздела Logs Agent.)