Version: 1.4.9This documentation is for Spitfire 1.4.9.
Infrastructure — Kafka, RabbitMQ and ActiveMQ
Kafka, RabbitMQ and ActiveMQ metrics are collected through a Tower. The add steps are the same as for databases.
Kafka
Quick install
Run the command on a Kafka broker, answer the questions.
curl -fsSL "https://<spitfire>/api/v1/setup/ds/kafka.sh?t=<token>" -o /tmp/sf-kafka.sh && bash /tmp/sf-kafka.shWhen you see this line, you are done.
OK: Kafka added to Spitfire, first metrics within ~1 min
In the product (the Quick install tab) the command comes ready with your address and a fresh token; the token is valid for 1 hour and adds one monitored system. The script asks for the SASL mechanism; with SCRAM it creates spitfire_monitor, and with ACLs it grants Describe only. If you want, it installs the JMX exporter on the broker (Kafka restarts).
Manual install
With SCRAM, create the user.
/opt/kafka/bin/kafka-configs.sh --bootstrap-server localhost:9092 --alter --entity-type users --entity-name spitfire_monitor --add-config 'SCRAM-SHA-512=[iterations=8192,password=<password>]'With ACLs, grant Describe.
/opt/kafka/bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:spitfire_monitor --operation Describe --cluster /opt/kafka/bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:spitfire_monitor --operation Describe --topic '*' /opt/kafka/bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:spitfire_monitor --operation Describe --group '*'Check that the broker answers.
/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server <host>:9092 >/dev/null && echo 'OK: Kafka answered'Add it in Infrastructure sources → Kafka → Manual install.
Change /opt/kafka if Kafka is installed elsewhere. Enter the brokers comma separated (kafka1:9092,kafka2:9092). With a SASL mechanism other than none, a user and a password are needed.
Broker metrics (JMX exporter, optional)
Bytes and message rates, request p99, under-replicated and offline partitions, the controller, heap and GC come from the broker's JMX. Each broker runs the Prometheus JMX exporter as a javaagent. Do the steps on each broker:
Download the javaagent:
sudo mkdir -p /opt/jmx-exporter && sudo curl -fsSL -o /opt/jmx-exporter/jmx_prometheus_javaagent.jar https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/1.0.1/jmx_prometheus_javaagent-1.0.1.jarWrite the config file (also in the Broker metrics (JMX exporter) box on the page):
sudo tee /opt/jmx-exporter/kafka-jmx.yml >/dev/null <<'EOF' # Spitfire: Kafka broker metrics for the Prometheus JMX exporter javaagent. lowercaseOutputName: false includeObjectNames: - "kafka.server:type=BrokerTopicMetrics,*" - "kafka.server:type=ReplicaManager,*" - "kafka.controller:type=KafkaController,*" - "kafka.network:type=RequestMetrics,name=TotalTimeMs,*" - "java.lang:type=Memory" - "java.lang:type=GarbageCollector,*" rules: - pattern: 'kafka.server<type=BrokerTopicMetrics, name=BytesInPerSec><>Count' name: kafka_broker_bytes_in type: GAUGE - pattern: 'kafka.server<type=BrokerTopicMetrics, name=BytesOutPerSec><>Count' name: kafka_broker_bytes_out type: GAUGE - pattern: 'kafka.server<type=BrokerTopicMetrics, name=MessagesInPerSec><>Count' name: kafka_broker_messages_in type: GAUGE - pattern: 'kafka.server<type=BrokerTopicMetrics, name=TotalProduceRequestsPerSec><>Count' name: kafka_broker_produce_requests type: GAUGE - pattern: 'kafka.server<type=BrokerTopicMetrics, name=TotalFetchRequestsPerSec><>Count' name: kafka_broker_fetch_requests type: GAUGE - pattern: 'kafka.network<type=RequestMetrics, name=TotalTimeMs, request=(Produce|FetchConsumer|FetchFollower)><>99thPercentile' name: kafka_broker_request_p99_ms labels: request: "$1" type: GAUGE - pattern: 'kafka.server<type=ReplicaManager, name=UnderReplicatedPartitions><>Value' name: kafka_broker_under_replicated_partitions type: GAUGE - pattern: 'kafka.controller<type=KafkaController, name=OfflinePartitionsCount><>Value' name: kafka_broker_offline_partitions type: GAUGE - pattern: 'kafka.controller<type=KafkaController, name=ActiveControllerCount><>Value' name: kafka_broker_active_controllers type: GAUGE - pattern: 'java.lang<type=Memory><HeapMemoryUsage>used' name: kafka_broker_heap_used_bytes type: GAUGE - pattern: 'java.lang<(?:type=GarbageCollector, name=([^,>]+)|name=([^,>]+), type=GarbageCollector)><>CollectionTime' name: kafka_broker_gc_time_ms labels: gc: "$1$2" type: GAUGE EOFWith Kafka under systemd, add the agent and restart (change
kafkaif the service has another name):sudo mkdir -p /etc/systemd/system/kafka.service.d && sudo tee /etc/systemd/system/kafka.service.d/spitfire-jmx.conf >/dev/null <<'EOF' [Service] Environment="KAFKA_OPTS=-javaagent:/opt/jmx-exporter/jmx_prometheus_javaagent.jar=7071:/opt/jmx-exporter/kafka-jmx.yml" EOF sudo systemctl daemon-reload && sudo systemctl restart kafkaWith Docker compose, add to the broker service, then
docker compose up -d:environment: KAFKA_OPTS: "-javaagent:/opt/jmx-exporter/jmx_prometheus_javaagent.jar=7071:/opt/jmx-exporter/kafka-jmx.yml" volumes: - /opt/jmx-exporter:/opt/jmx-exporter:ro ports: - "7071:7071"Check (the number must be above 0):
curl -s http://localhost:7071/metrics | grep -c kafka_broker_In the Kafka source, write the exporter addresses comma separated in JMX exporters (
kafka1:7071,kafka2:7071) → Save.
Consumer lag table
Below the Kafka dashboard the Consumer lag table shows each consumer group's total lag, the furthest behind first. Click a topic to open its partitions. The values are the newest points of the last 15 minutes; a group over the lag limit (10,000) shows in the warning colour.
RabbitMQ
Quick install (on a RabbitMQ node)
Copy the command, paste it into the terminal and run it.
curl -fsSL "https://<spitfire>/api/v1/setup/ds/rabbitmq.sh?t=<token>" -o /tmp/sf-rabbitmq.sh && bash /tmp/sf-rabbitmq.shOn Windows, run this in PowerShell instead.
Invoke-WebRequest "https://<spitfire>/api/v1/setup/ds/rabbitmq.ps1?t=<token>" -OutFile "$env:TEMP\sf-rabbitmq.ps1"; & "$env:TEMP\sf-rabbitmq.ps1"When you see
OK: rabbitmq ..., you are done.
In the product UI these lines come ready, with your address and a fresh token. The script asks before enabling the management plugin, creates spitfire_monitor with the monitoring tag (an existing one gets the new password), grants read on every vhost and tests the management API.
Manual install
Enable the management plugin.
rabbitmq-plugins enable rabbitmq_managementCreate the monitoring user.
rabbitmqctl add_user spitfire_monitor '<password>' && rabbitmqctl set_user_tags spitfire_monitor monitoringGrant read on every vhost.
for v in $(rabbitmqctl -q --no-table-headers list_vhosts name); do rabbitmqctl set_permissions -p "$v" spitfire_monitor '' '' '.*'; doneTest the management API.
curl -fsS -o /dev/null -u spitfire_monitor:'<password>' http://<host>:15672/api/overview && echo "OK: spitfire_monitor"Add it under Infrastructure sources → RabbitMQ, address
http://<host>:15672.
The monitoring tag reads the management API; the permission '' '' '.*' reads queues but cannot configure or publish. Read on every vhost lets the queue table show all queues.
Live view
The RabbitMQ dashboard has a Live view card. Read now shows every queue with its ready and unacked messages, consumers and publish/deliver rates; click a column header to sort by it (again to flip). A queue with messages and no consumer is marked yellow. Next to it: the nodes with their memory, disk, file descriptors and sockets.
ActiveMQ
ActiveMQ Classic and Artemis are one ActiveMQ monitored system (Beta). The Tower reads the Jolokia REST API of the broker's web console itself; no Collector is needed. A broker or a cluster counts as one monitored system: give the addresses of the cluster, or of a primary and its backup, comma separated.
Quick install (on the broker host)
Copy the command, paste it into a terminal and run it.
curl -fsSL "https://<spitfire>/api/v1/setup/ds/activemq.sh?t=<token>" -o /tmp/sf-activemq.sh && bash /tmp/sf-activemq.shOn Windows run this in an Administrator PowerShell instead.
Invoke-WebRequest "https://<spitfire>/api/v1/setup/ds/activemq.ps1?t=<token>" -OutFile "$env:TEMP\sf-activemq.ps1"; & "$env:TEMP\sf-activemq.ps1"When you see
OK: activemq ..., you're done.
In the product these lines come filled with your address and a new token. The script asks Classic or Artemis, backs every file up once as .spitfire.bak, writes only the files that differ and restarts the broker only when needed, after a confirm. It generates the monitor user's password and sends it only to Spitfire; it never asks for the admin password.
Manual install: ActiveMQ Classic (/opt/apache-activemq)
Back up the files.
for f in users.properties groups.properties jolokia-access.xml; do cp -n /opt/apache-activemq/conf/$f /opt/apache-activemq/conf/$f.spitfire.bak; doneAdd the monitor user.
grep -q '^spitfire_monitor=' /opt/apache-activemq/conf/users.properties || printf '\nspitfire_monitor=%s\n' '<password>' >> /opt/apache-activemq/conf/users.propertiesAdd the user to the
usersgroup.grep -q '^users=.*spitfire_monitor' /opt/apache-activemq/conf/groups.properties || { grep -q '^users=' /opt/apache-activemq/conf/groups.properties && sed -i 's/^users=\(..*\)$/&,spitfire_monitor/; s/^users=$/users=spitfire_monitor/' /opt/apache-activemq/conf/groups.properties || printf '\nusers=spitfire_monitor\n' >> /opt/apache-activemq/conf/groups.properties; }Make Jolokia read-only.
printf '%s\n' '<?xml version="1.0" encoding="UTF-8"?>' '<restrict>' ' <cors><strict-checking/></cors>' ' <commands><command>read</command><command>list</command><command>version</command><command>search</command></commands>' '</restrict>' > /opt/apache-activemq/conf/jolokia-access.xmlRestart the broker.
/opt/apache-activemq/bin/activemq restartTest a read.
curl -fsS -u 'spitfire_monitor:<password>' -H 'Origin: http://localhost' 'http://localhost:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=*/BrokerVersion' | grep -q '"status":200' && echo "OK: spitfire_monitor"Add it under Infrastructure sources → ActiveMQ: flavour
classic, addresshttp://<host>:8161.
Manual install: ActiveMQ Artemis (/var/lib/artemis-instance)
Back up the files.
for f in artemis-users.properties artemis-roles.properties artemis.profile management.xml; do cp -n /var/lib/artemis-instance/etc/$f /var/lib/artemis-instance/etc/$f.spitfire.bak; doneAdd the monitor user with a hashed password.
grep -q '^spitfire_monitor *=' /var/lib/artemis-instance/etc/artemis-users.properties || printf '\nspitfire_monitor = ENC(%s)\n' "$(/var/lib/artemis-instance/bin/artemis mask --hash '<password>' | sed -n 's/^result: //p')" >> /var/lib/artemis-instance/etc/artemis-users.propertiesGive it the
spitfirerole.grep -q '^spitfire *=' /var/lib/artemis-instance/etc/artemis-roles.properties || printf '\nspitfire = spitfire_monitor\n' >> /var/lib/artemis-instance/etc/artemis-roles.propertiesAdd the role to the console.
grep -q '^HAWTIO_ROLES=.*spitfire' /var/lib/artemis-instance/etc/artemis.profile || sed -i "s/^HAWTIO_ROLES='\([^']*\)'/HAWTIO_ROLES='\1,spitfire'/" /var/lib/artemis-instance/etc/artemis.profileGive the role read-only MBean access.
grep -q 'roles="amq,spitfire"' /var/lib/artemis-instance/etc/management.xml || sed -i 's#<match domain="org.apache.activemq.artemis">#&<access method="getFirstMessageAsJSON" roles="amq"/><access method="get*" roles="amq,spitfire"/><access method="is*" roles="amq,spitfire"/>#' /var/lib/artemis-instance/etc/management.xmlRestart the broker.
/var/lib/artemis-instance/bin/artemis-service restartTest a read.
curl -fsS -u 'spitfire_monitor:<password>' -H 'Origin: http://localhost' 'http://localhost:8161/console/jolokia/read/org.apache.activemq.artemis:broker=*/Version' | grep -q '"status":200' && echo "OK: spitfire_monitor"Add it under Infrastructure sources → ActiveMQ: flavour
artemis, addresshttp://<host>:8161.
On Classic the monitor user can run only the read, list, version and search commands; operations such as deleting a queue or sending a message (exec) are closed in Jolokia for everyone, so the console's buttons for them stop working too. Classic's users group can open the web console's read-only pages, which may show message bodies. On Artemis the spitfire role reads only get* and is*, getFirstMessageAsJSON (message bodies) stays with amq and it cannot run operations. Artemis rereads the user and role files by itself; artemis.profile and management.xml need a restart. In a cluster repeat the steps on every broker and restart them one at a time. If the web console listens on localhost only (etc/bootstrap.xml, on Classic conf/jetty.xml), open it to the address the Tower uses.
Queue table
The ActiveMQ dashboard has a table of the 20 deepest queues: pending messages, consumers, in-flight, the age of the oldest message (Artemis) and the DLQs. A queue with messages and no consumer is marked no consumer. A backup broker counts only as up; its metrics come from the primary.
Threshold findings
| Technology | Finding |
|---|---|
| Kafka | A consumer group's lag above 10,000 (warning) |
| Kafka | Under-replicated partitions (warning, JMX) |
| Kafka | Offline partitions (critical, JMX) |
| Kafka | Active controller count is not 1 (critical, JMX) |
| RabbitMQ | Ready messages above 10,000 (warning) |
| RabbitMQ | Memory or disk alarm on a node: publishers are blocked (critical) |
| RabbitMQ | Unacknowledged messages growing by more than 1000 in 15 minutes (warning) |
| RabbitMQ | A queue has messages but no consumer (warning, live view) |
| RabbitMQ | A cluster node is not running (critical, live view) |
| ActiveMQ | The broker does not answer (critical) |
| ActiveMQ | Memory, store or temp usage above 80% (warning), above 95% (critical: flow control stops the producers) |
| ActiveMQ | More than 10,000 messages on a queue (warning) |
| ActiveMQ | A queue with messages and no consumer (warning) |
| ActiveMQ | The DLQ grows or messages expire, in 15 minutes (warning) |
Success check
- Last test = Connected.
- On the Kafka dashboard Brokers equals your broker count; on RabbitMQ Consumers is drawn (RabbitMQ metrics are per queue: with no queue the dashboard stays empty).
- On the ActiveMQ dashboard Broker reachable is 1 and the queue table is filled.