├── .dir-locals.el ├── .dockerignore ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── erlang.mk ├── include └── prometheus_rabbitmq_exporter.hrl ├── priv └── dashboards │ ├── RabbitMQErlangVM.json │ └── RabbitMQErlangVM.png ├── rabbitmq-components.mk └── src ├── collectors ├── prometheus_rabbitmq_core_metrics_collector.erl ├── prometheus_rabbitmq_exchanges_collector.erl ├── prometheus_rabbitmq_message_stats.erl ├── prometheus_rabbitmq_mnesia_tables_collector.erl ├── prometheus_rabbitmq_nodes_collector.erl ├── prometheus_rabbitmq_overview_collector.erl └── prometheus_rabbitmq_queues_collector.erl ├── prometheus_rabbitmq_exporter.erl ├── prometheus_rabbitmq_exporter_config.erl └── prometheus_rabbitmq_exporter_handler.erl /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil . ((indent-tabs-mode . nil) 2 | (fill-column . 80) 3 | (eval . (turn-on-fci-mode)))) 4 | (erlang-mode . ((flycheck-erlang-include-path . ("../include" 5 | "../../include" 6 | "../deps" 7 | "../../deps" 8 | "../../")) 9 | (flycheck-erlang-library-path . ("../ebin" 10 | "../deps/accept/ebin" 11 | "../deps/amqp_client/ebin" 12 | "../deps/cowboy/ebin" 13 | "../deps/cowlib/ebin" 14 | "../deps/prometheus/ebin" 15 | "../deps/prometheus_httpd/ebin" 16 | "../deps/prometheus_process_collector/ebin" 17 | "../deps/rabbit/ebin" 18 | "../deps/rabbit_common/ebin" 19 | "../deps/rabbitmq_management/ebin" 20 | "../deps/rabbitmq_management_agent/ebin" 21 | "../deps/rabbitmq_web_dispatch/ebin" 22 | "../deps/ranch/ebin" 23 | "../../ebin" 24 | "../../deps/accept/ebin" 25 | "../../deps/amqp_client/ebin" 26 | "../../deps/cowboy/ebin" 27 | "../../deps/cowlib/ebin" 28 | "../../deps/prometheus/ebin" 29 | "../../deps/prometheus_httpd/ebin" 30 | "../../deps/prometheus_process_collector/ebin" 31 | "../../deps/rabbit/ebin" 32 | "../../deps/rabbit_common/ebin" 33 | "../../deps/rabbitmq_management/ebin" 34 | "../../deps/rabbitmq_management_agent/ebin" 35 | "../../deps/rabbitmq_web_dispatch/ebin" 36 | "../../deps/ranch/ebin")) 37 | (erlang-indent-level . 2)))) 38 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .erlang.mk 2 | .git 3 | _build 4 | deps 5 | ebin 6 | include 7 | priv 8 | src 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sw? 2 | .*.sw? 3 | *.beam 4 | *~ 5 | \#* 6 | .#* 7 | *.d 8 | /.erlang.mk/ 9 | /cover/ 10 | /deps/ 11 | /doc/ 12 | /ebin/ 13 | /logs/ 14 | /plugins/ 15 | _build 16 | /rabbitmq_management_metrics.d 17 | erl_crash.dump 18 | *.ez 19 | rebar3 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | sudo: false 3 | language: elixir 4 | elixir: 5 | - 1.7.2 6 | otp_release: 7 | - 20.3 8 | install: 'true' 9 | services: 10 | - docker 11 | otp_release: 12 | - 20.1 13 | script: "make test" 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG FROM_IMAGE 2 | ARG PROMETHEUS_RABBITMQ_EXPORTER_VERSION 3 | FROM ${FROM_IMAGE} 4 | MAINTAINER Ilya Khaprov 5 | 6 | COPY tmp/*.ez /plugins/ 7 | RUN chmod a+r /plugins/*.ez && \ 8 | rabbitmq-plugins enable --offline prometheus_rabbitmq_exporter && \ 9 | rabbitmq-plugins is_enabled prometheus_rabbitmq_exporter --offline && \ 10 | rabbitmq-plugins list | grep "prometheus_rabbitmq_exporter.*${PROMETHEUS_RABBITMQ_EXPORTER_VERSION}" 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016, Ilya Khaprov . 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = prometheus_rabbitmq_exporter 2 | PROJECT_DESCRIPTION = RabbitMQ Prometheus.io metrics exporter 3 | RABBITMQ_MINOR_VERSION = 3.7 4 | # PROJECT_VERSION gets set in rabbitmq-components.mk to RABBITMQ_VERSION 5 | RABBITMQ_VERSION = $(RABBITMQ_MINOR_VERSION).9.1 6 | EZ = $(PROJECT)-$(PROJECT_VERSION) 7 | PROJECT_APP_EXTRA_KEYS = {maintainers, ["Ilya Khaprov"]}, \ 8 | {licenses, ["MIT"]}, \ 9 | {links, [{"Github", "https://github.com/deadtrickster/prometheus_rabbitmq_exporter"}]} 10 | 11 | ACCEPT_VERSION = 0.3.5 12 | dep_accept = hex $(ACCEPT_VERSION) 13 | 14 | PROMETHEUS_VERSION = 4.3.0 15 | dep_prometheus = hex $(PROMETHEUS_VERSION) 16 | 17 | PROMETHEUS_COWBOY_VERSION = 0.1.7 18 | dep_prometheus_cowboy = hex $(PROMETHEUS_COWBOY_VERSION) 19 | 20 | PROMETHEUS_HTTPD_VERSION = 2.1.10 21 | dep_prometheus_httpd = hex $(PROMETHEUS_HTTPD_VERSION) 22 | 23 | # prometheus_process_collector will fail to build in otp-*-build-context, skipping 24 | ifneq ($(DOCKER_BUILD_CONTEXT),1) 25 | PROMETHEUS_PROCESS_COLLECTOR_VERSION = 1.4.3 26 | dep_prometheus_process_collector = hex $(PROMETHEUS_PROCESS_COLLECTOR_VERSION) 27 | endif 28 | 29 | DEPS = rabbit rabbitmq_management \ 30 | prometheus prometheus_cowboy prometheus_httpd 31 | 32 | # We do not want these deps defined as applications in app 33 | # prometheus_process_collector will fail to build in otp-*-build-context, skipping 34 | ifneq ($(DOCKER_BUILD_CONTEXT),1) 35 | BUILD_DEPS = rabbit_common rabbitmq_management_agent accept prometheus_process_collector 36 | else 37 | BUILD_DEPS = rabbit_common rabbitmq_management_agent accept 38 | endif 39 | 40 | DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk 41 | DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk 42 | 43 | # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be 44 | # reviewed and merged. 45 | 46 | ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git 47 | ERLANG_MK_COMMIT = rabbitmq-tmp 48 | 49 | RABBITMQ_BRANCH ?= v$(RABBITMQ_MINOR_VERSION).x 50 | RABBITMQ_CURRENT_FETCH_URL ?= https://github.com/rabbitmq/ 51 | 52 | REBAR := $(CURDIR)/rebar3 53 | REBAR_VERSION := 3.9.0 54 | $(REBAR): 55 | @wget --output-document $(REBAR) https://github.com/erlang/rebar3/releases/download/$(REBAR_VERSION)/rebar3 && \ 56 | chmod +x $(REBAR) && \ 57 | $(REBAR) --version | grep $(REBAR_VERSION) 58 | 59 | include rabbitmq-components.mk 60 | include erlang.mk 61 | 62 | .PHONY: distclean 63 | distclean:: 64 | @rm -fr tmp 65 | 66 | DOCKER_IMAGE_VERSION = $(RABBITMQ_MINOR_VERSION) 67 | DOCKER_BASE_IMAGE ?= rabbitmq:$(DOCKER_IMAGE_VERSION)-management 68 | 69 | define BUILD_DOCKER_IMAGE 70 | docker build \ 71 | --pull \ 72 | --build-arg FROM_IMAGE=$(DOCKER_BASE_IMAGE) \ 73 | --build-arg PROMETHEUS_RABBITMQ_EXPORTER_VERSION=$(PROJECT_VERSION) \ 74 | --tag deadtrickster/rabbitmq_prometheus:$(DOCKER_IMAGE_VERSION) . 75 | endef 76 | 77 | .PHONY: docker_build 78 | docker_build: 79 | @$(BUILD_DOCKER_IMAGE) 80 | .PHONY: docker_build_alpine 81 | docker_build_alpine: DOCKER_IMAGE_VERSION = 3.7-alpine 82 | docker_build_alpine: DOCKER_BASE_IMAGE = rabbitmq:3.7-management-alpine 83 | docker_build_alpine: docker_build 84 | 85 | define PUSH_DOCKER_IMAGE 86 | docker push deadtrickster/rabbitmq_prometheus:$(DOCKER_IMAGE_VERSION) 87 | endef 88 | 89 | .PHONY: docker_push 90 | docker_push: 91 | @$(PUSH_DOCKER_IMAGE) 92 | .PHONY: docker_push_alpine 93 | docker_push_alpine: DOCKER_IMAGE_VERSION = 3.7-alpine 94 | docker_push_alpine: docker_push 95 | 96 | define RUN_DOCKER_IMAGE 97 | docker run --interactive --tty --publish=15672:15672 \ 98 | deadtrickster/rabbitmq_prometheus:$(DOCKER_IMAGE_VERSION) 99 | endef 100 | 101 | .PHONY: docker_run 102 | docker_run: 103 | @$(RUN_DOCKER_IMAGE) 104 | .PHONY: docker_run_alpine 105 | docker_run_alpine: DOCKER_IMAGE_VERSION = 3.7-alpine 106 | docker_run_alpine: docker_run 107 | 108 | .PHONY: up 109 | up: $(abspath .)+up $(DEPS:%=$(DEPS_DIR)/%+up) $(BUILD_DEPS:%=$(DEPS_DIR)/%+up) 110 | @: 111 | 112 | %+up: fetch-deps 113 | $(exec_verbose) cd $*; \ 114 | git fetch -p && \ 115 | if [ '$(RABBITMQ_BRANCH)' ]; then \ 116 | git checkout $(RABBITMQ_BRANCH) || : ; \ 117 | fi && \ 118 | if git symbolic-ref -q HEAD >/dev/null; then \ 119 | branch=$$(git symbolic-ref --short HEAD); \ 120 | remote=$$(git config branch.$$branch.remote); \ 121 | merge=$$(git config branch.$$branch.merge | sed 's,refs/heads/,,'); \ 122 | if [ "$$remote" -a "$$merge" ]; then \ 123 | git merge --ff-only "$$remote/$$merge"; \ 124 | fi; \ 125 | fi && \ 126 | echo 127 | 128 | REBAR_DEPS_DIR := _build/default/lib 129 | $(REBAR_DEPS_DIR): up 130 | @mkdir -p _build/default && \ 131 | ln -sfnv $(CURDIR)/deps $(REBAR_DEPS_DIR) 132 | 133 | tmp: 134 | @mkdir -p tmp 135 | 136 | tmp/accept-$(ACCEPT_VERSION).ez: $(REBAR) $(REBAR_DEPS_DIR) tmp 137 | @cd $(REBAR_DEPS_DIR)/accept && \ 138 | $(REBAR) archive && \ 139 | mv accept-$(ACCEPT_VERSION).ez $(CURDIR)/tmp/ 140 | 141 | tmp/prometheus-$(PROMETHEUS_VERSION).ez: $(REBAR) $(REBAR_DEPS_DIR) tmp 142 | @cd $(REBAR_DEPS_DIR)/prometheus && \ 143 | $(REBAR) archive && \ 144 | mv prometheus-$(PROMETHEUS_VERSION).ez $(CURDIR)/tmp/ 145 | 146 | tmp/prometheus_cowboy-$(PROMETHEUS_COWBOY_VERSION).ez: $(REBAR) $(REBAR_DEPS_DIR) tmp 147 | @cd $(REBAR_DEPS_DIR)/prometheus_cowboy && \ 148 | $(REBAR) archive && \ 149 | mv prometheus_cowboy-$(PROMETHEUS_COWBOY_VERSION).ez $(CURDIR)/tmp/ 150 | 151 | tmp/prometheus_httpd-$(PROMETHEUS_HTTPD_VERSION).ez: $(REBAR) $(REBAR_DEPS_DIR) tmp 152 | @cd $(REBAR_DEPS_DIR)/prometheus_httpd && \ 153 | $(REBAR) archive && \ 154 | mv prometheus_httpd-$(PROMETHEUS_HTTPD_VERSION).ez $(CURDIR)/tmp/ 155 | 156 | # prometheus_process_collector will fail to build in otp-*-build-context, skipping 157 | ifneq ($(DOCKER_BUILD_CONTEXT),1) 158 | tmp/prometheus_process_collector-$(PROMETHEUS_PROCESS_COLLECTOR_VERSION).ez: $(REBAR) $(REBAR_DEPS_DIR) tmp 159 | @cd $(REBAR_DEPS_DIR)/prometheus_process_collector && \ 160 | $(REBAR) archive && \ 161 | mv prometheus_process_collector-$(PROMETHEUS_PROCESS_COLLECTOR_VERSION).ez $(CURDIR)/tmp 162 | endif 163 | 164 | tmp/$(EZ).ez: up app tmp 165 | @rm -fr $(EZ) && mkdir $(EZ) && \ 166 | cp -r ebin include priv $(EZ) && \ 167 | rm -f $(EZ).ez && \ 168 | zip --move --recurse-paths --test $(EZ).ez $(EZ) && \ 169 | mv $(EZ).ez tmp/ 170 | 171 | .PHONY: ezs 172 | ezs:: tmp/accept-$(ACCEPT_VERSION).ez 173 | ezs:: tmp/prometheus-$(PROMETHEUS_VERSION).ez 174 | ezs:: tmp/prometheus_cowboy-$(PROMETHEUS_COWBOY_VERSION).ez 175 | ezs:: tmp/prometheus_httpd-$(PROMETHEUS_HTTPD_VERSION).ez 176 | # prometheus_process_collector will fail to build in otp-*-build-context, skipping 177 | ifneq ($(DOCKER_BUILD_CONTEXT),1) 178 | ezs:: tmp/prometheus_process_collector-$(PROMETHEUS_PROCESS_COLLECTOR_VERSION).ez 179 | endif 180 | ezs:: tmp/$(EZ).ez 181 | 182 | define RUN_DOCKER_TEST_IMAGE 183 | docker run \ 184 | --tty \ 185 | --detach \ 186 | --name test_prometheus_rabbitmq_exporter \ 187 | --publish 15672:15672 \ 188 | deadtrickster/rabbitmq_prometheus:$(DOCKER_IMAGE_VERSION) 189 | endef 190 | 191 | define ENSURE_RABBIT_IN_DOCKER_IS_RUNNING 192 | docker exec test_prometheus_rabbitmq_exporter \ 193 | bash -c "while sleep 1; do rabbitmq-diagnostics check_port_listener 15672 2>/dev/null && break; done" 194 | endef 195 | 196 | define CLEAN_DOCKER_TEST_IMAGE 197 | docker rm --force test_prometheus_rabbitmq_exporter 198 | endef 199 | 200 | define VERIFY_METRICS_API 201 | curl --silent --verbose --fail localhost:15672/api/metrics 202 | endef 203 | 204 | .PHONY: test 205 | test: ezs docker_build 206 | @$(CLEAN_DOCKER_TEST_IMAGE) ; \ 207 | $(RUN_DOCKER_TEST_IMAGE) && \ 208 | $(ENSURE_RABBIT_IN_DOCKER_IS_RUNNING) && \ 209 | $(VERIFY_METRICS_API) && \ 210 | $(CLEAN_DOCKER_TEST_IMAGE) 211 | 212 | # This plugin is currently expected to work with RabbitMQ v3.7.9 and above: 213 | # https://github.com/deadtrickster/prometheus_rabbitmq_exporter#versioning 214 | # 215 | # The OTP version that ships in rabbitmq:3.7.9 Docker image is v21.2.5: 216 | # docker run -it --rm rabbitmq:3.7.9 -- cat /usr/local/lib/erlang/releases/21/OTP_VERSION 217 | # 21.2.5 218 | # 219 | # We are creating an Erlang/OTP build context which has the same version as RabbitMQ v3.7.9 Docker image 220 | # The goal is to produce ezs that are compatible with RabbitMQ v3.7.9 Docker image 221 | MIN_SUPPORTED_OTP_VERSION := 21.2.5 222 | .PHONY: otp-$(MIN_SUPPORTED_OTP_VERSION)-build-context 223 | otp-$(MIN_SUPPORTED_OTP_VERSION)-build-context: 224 | @docker run --tty --interactive --rm --name build_prometheus_rabbitmq_export \ 225 | --env LANG=C.UTF-8 \ 226 | --env LANGUAGE=C.UTF-8 \ 227 | --env LC_ALL=C.UTF-8 \ 228 | --env DOCKER_BUILD_CONTEXT=1 \ 229 | --volume $(CURDIR):/prometheus_rabbitmq_exporter \ 230 | --workdir /prometheus_rabbitmq_exporter \ 231 | erlang:$(MIN_SUPPORTED_OTP_VERSION) bash 232 | # make /usr/local/bin/elixir 233 | # apt update && apt install zip 234 | # make ezs 235 | 236 | tmp/elixir: tmp 237 | @cd tmp && \ 238 | cd elixir || git clone https://github.com/elixir-lang/elixir.git; \ 239 | git checkout v1.8 240 | 241 | /usr/local/bin/elixir: tmp/elixir 242 | @cd tmp/elixir && \ 243 | make clean install 244 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ Prometheus.io exporter [![Build Status](https://travis-ci.org/deadtrickster/prometheus_rabbitmq_exporter.svg?branch=master)](https://travis-ci.org/deadtrickster/prometheus_rabbitmq_exporter) [![Docker Pulls](https://img.shields.io/docker/pulls/deadtrickster/rabbitmq_prometheus.svg)](https://hub.docker.com/r/deadtrickster/rabbitmq_prometheus/tags) 2 | 3 | ## STOP! This is abandonware! 4 | 5 | [Modern RabbitMQ release series](https://www.rabbitmq.com/docs/versions) ship with a [built-in Prometheus plugin](https://www.rabbitmq.com/docs/prometheus) and a set 6 | of Grafana dashboards. 7 | 8 | This plugin is obsolete and really should not be used. It will not be compatible with the latest versions of RabbitMQ, 9 | you will not get any support for the RabbitMQ Core team, and there are no reasons to choose this plugin 10 | over the built-in one. 11 | 12 | ## What does this plugin do? 13 | 14 | Implemented as RabbitMQ Management Plugin plugin. 15 | Also exports Erlang VM and process metrics (~ 100 metrics in total). 16 | 17 | Implemented using [Erlang Prometheus.io client](https://github.com/deadtrickster/prometheus.erl) 18 | 19 | ![rabbitmq prometheus exporter grafana dashboard](http://i.imgur.com/tWiDw56.png?1) 20 | 21 | ## TOC 22 | - [Versioning](#versioning) 23 | - [Installation](#installation) 24 | - [Troubleshooting](#troubleshooting) 25 | - [Configuration](#configuration) 26 | - [Metrics](#metrics) 27 | - [RabbitMQ specific metrics](#rabbitmq-specific-metrics) 28 | - [Overview](#overview) 29 | - [Queues](#queues) 30 | - [Exchanges](#exchanges) 31 | - [Mnesia tables](#mnesia-tables) 32 | - [Nodes](#nodes) 33 | - [Erlang VM & OTP metrics](#erlang-vm--otp-metrics) 34 | - [System Info](#system-info) 35 | - [Statistics](#statistics) 36 | - [Memory](#memory) 37 | - [Mnesia](#mnesia) 38 | - [Process metrics](#process-metrics) 39 | - [Exporter metrics](#exporter-metrics) 40 | - [License](#license) 41 | 42 | ## Versioning 43 | 44 | While RabbitMQ transitions from webmachine to cowboy we maintain two branches one for 3.6.x and one for 3.7.x. 45 | Plugin version should be read as follows: 3.7.1.x - where 3.7.1 is required RabbitMQ version and x is just incremental version of the plugin. 46 | 47 | ## Installation 48 | 49 | - [Release for latest RabbitMQ 3.7.x](https://github.com/deadtrickster/prometheus_rabbitmq_exporter/releases/tag/v3.7.2.3) 50 | - [Release for latest RabbitMQ 3.6.x](https://github.com/deadtrickster/prometheus_rabbitmq_exporter/releases/tag/rabbitmq-3.6.14.1); 51 | - [Release for RabbitMQ 3.6.8 and 3.6.9](https://github.com/deadtrickster/prometheus_rabbitmq_exporter/releases/tag/rabbitmq-3.6.9.1); 52 | - [Release for RabbitMQ 3.6.5](https://github.com/deadtrickster/prometheus_rabbitmq_exporter/releases/tag/rabbitmq-3.6.5.9). 53 | 54 | Download suitable version and follow regular [RabbitMQ plugin installation instructions](http://www.rabbitmq.com/installing-plugins.html). 55 | 56 | ``` 57 | rabbitmq-plugins enable prometheus_rabbitmq_exporter 58 | ``` 59 | 60 | If you are running on Linux/FreeBSD/Mac, you may find `prometheus_process_exporter` useful: 61 | 62 | ``` 63 | rabbitmq-plugins enable prometheus_process_collector 64 | ``` 65 | 66 | [Prometheus process collector](https://github.com/deadtrickster/prometheus_process_collector). 67 | 68 | ### Troubleshooting 69 | 70 | #### `undef` error 71 | 72 | If you see something like this: 73 | 74 | ``` 75 | {could_not_start,rabbitmq_management, 76 | {undef, 77 | [{prometheus_http,setup,[],[]} 78 | ``` 79 | 80 | I.e. `undef` error mentioning a module starting with `prometheus_`, chances you forgot to enable a plugin (see https://github.com/deadtrickster/prometheus_rabbitmq_exporter/issues/27 for example). 81 | 82 | #### Module `prometheus_process_collector` is unloadable 83 | 84 | ``` 85 | {plugin_module_unloadable,"prometheus_process_collector", 86 | {error,on_load_failure}} 87 | ``` 88 | 89 | or 90 | 91 | ``` 92 | {error,{load_failed,"Failed to load NIF library: 93 | '/<...>/plugins/prometheus_process_collector-1.1.0/priv/prometheus_process_collector.so: 94 | failed to map segment from shared object'"}} 95 | ``` 96 | 97 | Prometheus process collector uses NIFs underneath and failed to load shared object in module on_load callback. 98 | Please check that `RABBITMQ_PLUGINS_EXPAND_DIR` doesn't have `noexec` flag set (see https://github.com/deadtrickster/prometheus_rabbitmq_exporter/issues/26). 99 | 100 | #### Crashes with something like {error,{bad_lib,"Library version (2.11) not compatible (with 2.10)."}} 101 | 102 | This means [erl_nif](http://erlang.org/doc/man/erl_nif.html) version `prometheus_process_collector` built with differs from yours (see Version Management section). 103 | You can rebuild the plugin yourself very easily - `clone https://github.com/deadtrickster/prometheus_process_collector.git` and run `rebar3 archive` 104 | 105 | #### Glibc-related errors when `prometheus_process_collector` enabled 106 | 107 | `prometheus_process_collector` plugin comes with prebuilt shared object. And it looks like my Glibc version differs from yours. 108 | You can rebuild the plugin yourself very easily - `clone https://github.com/deadtrickster/prometheus_process_collector.git` and run `rebar3 archive` 109 | 110 | ### Latest Docker: 111 | `docker run -p 8080:15672 deadtrickster/rabbitmq_prometheus` 112 | 113 | Alpine-based image is also available: 114 | `docker run -p 8080:15672 deadtrickster/rabbitmq_prometheus:latest-alpine` 115 | 116 | ## Configuration 117 | 118 | This exporter supports the following options via `rabbitmq_exporter` entry of `prometheus` app env: 119 | - `path` - scrape endpoint. Default is `"metrics"`. Note RabbitMQ translates this to `"{management_plugin_path_prefix}/api/metrics"`; 120 | - `use_mgmt_auth` - use built-in management auth. Default is `false`. If true, relies on management plugin for authentication (that guest:guest on fresh setups); 121 | - `format` - scrape format. Default is `prometheus_text_format`; 122 | - `exchange_messages_stat` - same as `queue_messages_state` but for the exchanges; 123 | - `queue_messages_stat` - messages state to export. Default is hopefully reasonable. You can read more about possible values [here](https://raw.githack.com/rabbitmq/rabbitmq-management/rabbitmq_v3_6_5/priv/www/doc/stats.html); 124 | - `connections_total_enabled` - Default is `false`. If `true`, the exporter will iterate over all connections and export count grouped by connection state (running, flow, etc). 125 | 126 | Sample `/etc/rabbitmq/rabbitmq.config` showing how to customize the scrape `path`, and `connections_total_enabled`: 127 | 128 | ```erlang 129 | [ 130 | {rabbit, [ 131 | {loopback_users, []}, 132 | {tcp_listeners, [5672]}, 133 | {ssl_listeners, []} 134 | ]}, 135 | {prometheus, [ 136 | {rabbitmq_exporter, [ 137 | {path, "/mymetrics"}, 138 | {connections_total_enabled, true} 139 | ]} 140 | ]}, 141 | {rabbitmq_management, [ 142 | {listener, [ 143 | {port, 15672}, 144 | {ssl, false} 145 | ]} 146 | ]} 147 | ]. 148 | ``` 149 | 150 | For the latest list of supported options look [here](https://github.com/deadtrickster/prometheus_rabbitmq_exporter/blob/master/src/prometheus_rabbitmq_exporter_config.erl). 151 | 152 | ## Metrics 153 | 154 | ### RabbitMQ Specific Metrics 155 | 156 | #### Overview 157 | 158 | * `rabbitmq_connections`
159 | Type: gauge.
160 | RabbitMQ Connections count. 161 | 162 | * `rabbitmq_connections_total` (disabled by default)
163 | Type: gauge.
164 | Labels: state.
165 | RabbitMQ connections count grouped by connection state. 166 | 167 | * `rabbitmq_channels`
168 | Type: gauge.
169 | RabbitMQ Channels count. 170 | 171 | * `rabbitmq_queues`
172 | Type: gauge.
173 | RabbitMQ Queues count. 174 | 175 | * `rabbitmq_exchanges`
176 | Type: gauge.
177 | RabbitMQ Exchanges count. 178 | 179 | * `rabbitmq_consumers`
180 | Type: gauge.
181 | RabbitMQ Consumers count. 182 | 183 | * `rabbitmq_queues_disk_reads`
184 | Type: counter.
185 | Total number of times messages have been read from disk by all queues. 186 | 187 | * `rabbitmq_queues_disk_writes`
188 | Type: counter.
189 | Total number of times messages have been written to disk by all queues. 190 | 191 | * `rabbitmq_messages_ready`
192 | Type: gauge.
193 | Messages ready for delivery. 194 | 195 | * `rabbitmq_messages_unacknowledged`
196 | Type: gauge.
197 | Delivered but unacknowledged messages. 198 | 199 | * `rabbitmq_messages_published_total`
200 | Type: counter.
201 | Count of messages published. 202 | 203 | * `rabbitmq_messages_confirmed_total`
204 | Type: counter.
205 | Count of messages confirmed. 206 | 207 | * `rabbitmq_messages_delivered_total`
208 | Type: counter.
209 | Count of messages delivered in acknowledgement mode to consumers. 210 | 211 | * `rabbitmq_messages_delivered_no_ack_total`
212 | Type: counter.
213 | Count of messages delivered in no-acknowledgement mode to consumers. 214 | 215 | * `rabbitmq_messages_get_total`
216 | Type: counter.
217 | Count of messages delivered in acknowledgement mode in response to basic.get. 218 | 219 | * `rabbitmq_messages_get_no_ack_total`
220 | Type: counter.
221 | Count of messages delivered in no-acknowledgement mode in response to basic.get. 222 | 223 | * `rabbitmq_messages_deliver_get_total`
224 | Type: counter.
225 | Sum of messages_delivered_total, messages_delivered_no_ack_total, messages_get_total and messages_get_no_ack_total. 226 | 227 | * `rabbitmq_messages_redelivered_total`
228 | Type: counter.
229 | Count of subset of delivered messages which had the redelivered flag set. 230 | 231 | * `rabbitmq_messages_returned_total`
232 | Type: counter.
233 | Count of messages returned to publisher as unroutable. 234 | 235 | #### Queues 236 | 237 | Labels: `vhost`, `queue`. 238 | 239 | * `rabbitmq_queue_durable`
240 | Type: boolean.
241 | Whether or not the queue survives server restarts. 242 | 243 | * `rabbitmq_queue_auto_delete`
244 | Type: boolean.
245 | Whether the queue will be deleted automatically when no longer used. 246 | 247 | * `rabbitmq_queue_exclusive`
248 | Type: boolean.
249 | True if queue is exclusive (i.e. has owner_pid), false otherwise. 250 | 251 | * `rabbitmq_queue_messages_ready`
252 | Type: gauge.
253 | Number of messages ready to be delivered to clients. 254 | 255 | * `rabbitmq_queue_messages_unacknowledged`
256 | Type: gauge.
257 | Number of messages delivered to client but not yet acknowledged. 258 | 259 | * `rabbitmq_queue_messages`
260 | Type: gauge.
261 | Sum of ready and unacknowledged messages (queue depth). 262 | 263 | * `rabbitmq_queue_messages_ready_ram`
264 | Type: gauge.
265 | Number of messages from messages_ready which are resident in ram. 266 | 267 | * `rabbitmq_queue_messages_unacknowledged_ram`
268 | Type: gauge.
269 | Number of messages from messages_unacknowledged which are resident in ram. 270 | 271 | * `rabbitmq_queue_messages_ram`
272 | Type: gauge.
273 | Total number of messages which are resident in ram. 274 | 275 | * `rabbitmq_queue_messages_persistent`
276 | Type: gauge.
277 | Total number of persisted messages in the queue (will always be 0 for transient queues). 278 | 279 | * `rabbitmq_queue_message_bytes`
280 | Type: gauge.
281 | Sum of the size of all message bodies in the queue. This does not include the message properties (including headers) or any overhead. 282 | 283 | * `rabbitmq_queue_message_bytes_ready`
284 | Type: gauge.
285 | Like message_bytes but counting only those messages ready to be delivered to clients. 286 | 287 | * `rabbitmq_queue_message_bytes_unacknowledged`
288 | Type: gauge.
289 | Like message_bytes but counting only those messages delivered to clients but not yet acknowledged. 290 | 291 | * `rabbitmq_queue_message_bytes_ram`
292 | Type: gauge.
293 | Like message_bytes but counting only those messages which are in RAM. 294 | 295 | * `rabbitmq_queue_message_bytes_persistent`
296 | Type: gauge.
297 | Like message_bytes but counting only those messages which are persistent. 298 | 299 | * `rabbitmq_queue_head_message_timestamp`
300 | Type: gauge.
301 | The timestamp property of the first message in the queue, if present. Timestamps of messages only appear when they are in the paged-in state. 302 | 303 | * `rabbitmq_queue_disk_reads`
304 | Type: counter.
305 | Total number of times messages have been read from disk by this queue since it started. 306 | 307 | * `rabbitmq_queue_disk_writes`
308 | Type: counter.
309 | Total number of times messages have been written to disk by this queue since it started. 310 | 311 | * `rabbitmq_queue_disk_size_bytes`
312 | Type: gauge.
313 | Disk space occupied by the queue. 314 | 315 | * `rabbitmq_queue_consumers`
316 | Type: gauge.
317 | Number of consumers. 318 | 319 | * `rabbitmq_queue_consumer_utilisation`
320 | Type: gauge.
321 | Fraction of the time (between 0.0 and 1.0) that the queue is able to immediately deliver messages to consumers. This can be less than 1.0 if consumers are limited by network congestion or prefetch count. 322 | 323 | * `rabbitmq_queue_memory`
324 | Type: gauge.
325 | Bytes of memory consumed by the Erlang process associated with the queue, including stack, heap and internal structures. 326 | 327 | * `rabbitmq_queue_state`
328 | Type: gauge.
329 | The state of the queue. NaN if queue is located on cluster nodes that are currently down. 0 if queue is running normally. MsgCount if queue is synchronising. 330 | 331 | * `rabbitmq_queue_messages_published_total`
332 | Type: counter.
333 | Count of messages published. 334 | 335 | * `rabbitmq_queue_messages_confirmed_total`
336 | Type: counter.
337 | Count of messages confirmed. 338 | 339 | * `rabbitmq_queue_messages_delivered_total`
340 | Type: counter.
341 | Count of messages delivered in acknowledgement mode to consumers. 342 | 343 | * `rabbitmq_queue_messages_delivered_no_ack_total`
344 | Type: counter.
345 | Count of messages delivered in no-acknowledgement mode to consumers. 346 | 347 | * `rabbitmq_queue_messages_get_total`
348 | Type: counter.
349 | Count of messages delivered in acknowledgement mode in response to basic.get. 350 | 351 | * `rabbitmq_queue_messages_get_no_ack_total`
352 | Type: counter.
353 | Count of messages delivered in no-acknowledgement mode in response to basic.get. 354 | 355 | * `rabbitmq_queue_messages_deliver_get_total`
356 | Type: counter.
357 | Sum of messages_delivered_total, messages_delivered_no_ack_total, messages_get_total and messages_get_no_ack_total. 358 | 359 | * `rabbitmq_queue_messages_redelivered_total`
360 | Type: counter.
361 | Count of subset of delivered messages which had the redelivered flag set. 362 | 363 | * `rabbitmq_queue_messages_returned_total`
364 | Type: counter.
365 | Count of messages returned to publisher as unroutable. 366 | 367 | #### Exchanges 368 | 369 | Labels: `vhost`, `exchange`. 370 | 371 | * `rabbitmq_exchange_messages_published_total`
372 | Type: counter.
373 | Count of messages published. 374 | 375 | * `rabbitmq_exchange_messages_published_in_total`
376 | Type: counter.
377 | Count of messages published \"in\" to an exchange, i.e. not taking account of routing. 378 | 379 | * `rabbitmq_exchange_messages_published_out_total`
380 | Type: counter.
381 | Count of messages published \"out\" of an exchange, i.e. taking account of routing. 382 | 383 | * `rabbitmq_exchange_messages_confirmed_total`
384 | Type: counter.
385 | Count of messages confirmed. 386 | 387 | * `rabbitmq_exchange_messages_delivered_total`
388 | Type: counter.
389 | Count of messages delivered in acknowledgement mode to consumers. 390 | 391 | * `rabbitmq_exchange_messages_delivered_no_ack_total`
392 | Type: counter.
393 | Count of messages delivered in no-acknowledgement mode to consumers. 394 | 395 | * `rabbitmq_exchange_messages_get_total`
396 | Type: counter.
397 | Count of messages delivered in acknowledgement mode in response to basic.get. 398 | 399 | * `rabbitmq_exchange_messages_get_no_ack_total`
400 | Type: counter.
401 | Count of messages delivered in no-acknowledgement mode in response to basic.get. 402 | 403 | * `rabbitmq_exchange_messages_deliver_get_total`
404 | Type: counter.
405 | Sum of *messages_delivered_total, *messages_delivered_no_ack_total, *messages_get_total and *messages_get_no_ack_total. 406 | 407 | * `rabbitmq_exchange_messages_redelivered_total`
408 | Type: counter.
409 | Count of subset of delivered messages which had the redelivered flag set. 410 | 411 | * `rabbitmq_exchange_messages_returned_total`
412 | Type: counter.
413 | Count of messages returned to publisher as unroutable. 414 | 415 | #### Mnesia Tables 416 | 417 | Various metrics for RabbitMQ-specific Mnesia tables. 418 | 419 | Labels: `table`. 420 | 421 | * `rabbitmq_mnesia_table_read_only`
422 | Type: boolean.
423 | Access mode of the table, 1 if table is read_only or 0 otherwise. 424 | 425 | * `rabbitmq_mnesia_table_disc_copies`
426 | Type: gauge.
427 | Number of the nodes where a disc_copy of the table resides according to the schema. 428 | 429 | * `rabbitmq_mnesia_table_disc_only_copies`
430 | Type: gauge.
431 | Number of the nodes where a disc_only_copy of the table resides according to the schema. 432 | 433 | * `rabbitmq_mnesia_table_local_content`
434 | Type: boolean.
435 | If the table is configured to have locally unique content on each node, value is 1 or 0 otherwise. 436 | 437 | * `rabbitmq_mnesia_table_majority_required`
438 | Type: boolean.
439 | If 1, a majority of the table replicas must be available for an update to succeed. 440 | 441 | * `rabbitmq_mnesia_table_master_nodes`
442 | Type: gauge.
443 | Number of the master nodes of a table. 444 | 445 | * `rabbitmq_mnesia_table_memory_bytes`
446 | Type: gauge.
447 | The number of bytes allocated to the table on this node. 448 | 449 | * `rabbitmq_mnesia_table_ram_copies`
450 | Type: gauge.
451 | Number of the nodes where a ram_copy of the table resides according to the schema. 452 | 453 | * `rabbitmq_mnesia_table_records_count`
454 | Type: gauge.
455 | Number of records inserted in the table. 456 | 457 | * `rabbitmq_mnesia_table_disk_size_bytes`
458 | Type: gauge.
459 | Disk space occupied by the table (DCL + DCD). 460 | 461 | #### Nodes 462 | 463 | Cluster/nodes metrics. 464 | 465 | * `rabbitmq_node_up`
466 | Type: boolean.
467 | Labels: name, type.
468 | Node running status. 469 | 470 | ### Erlang VM & OTP Metrics 471 | 472 | #### System Info 473 | 474 | * `erlang_vm_ets_limit`
475 | Type: gauge.
476 | The maximum number of ETS tables allowed. 477 | 478 | * `erlang_vm_logical_processors`
479 | Type: gauge.
480 | The detected number of logical processors configured in the system. 481 | 482 | * `erlang_vm_logical_processors_available`
483 | Type: gauge.
484 | The detected number of logical processors 485 | available to the Erlang runtime system. 486 | 487 | * `erlang_vm_logical_processors_online`
488 | Type: gauge.
489 | The detected number of logical processors online on the system. 490 | 491 | * `erlang_vm_port_count`
492 | Type: gauge.
493 | The number of ports currently existing at the local node. 494 | 495 | * `erlang_vm_port_limit`
496 | Type: gauge.
497 | The maximum number of simultaneously existing ports at the local node. 498 | 499 | * `erlang_vm_process_count`
500 | Type: gauge.
501 | The number of processes currently existing at the local node. 502 | 503 | * `erlang_vm_process_limit`
504 | Type: gauge.
505 | The maximum number of simultaneously existing processes 506 | at the local node. 507 | 508 | * `erlang_vm_schedulers`
509 | Type: gauge.
510 | The number of scheduler threads used by the emulator. 511 | 512 | * `erlang_vm_schedulers_online`
513 | Type: gauge.
514 | The number of schedulers online. 515 | 516 | * `erlang_vm_smp_support`
517 | Type: boolean.
518 | 1 if the emulator has been compiled with SMP support, otherwise 0. 519 | 520 | * `erlang_vm_threads`
521 | Type: boolean.
522 | 1 if the emulator has been compiled with thread support, otherwise 0. 523 | 524 | * `erlang_vm_thread_pool_size`
525 | Type: gauge.
526 | The number of async threads in the async thread pool 527 | used for asynchronous driver calls. 528 | 529 | * `erlang_vm_time_correction`
530 | Type: boolean.
531 | 1 if time correction is enabled, otherwise 0. 532 | 533 | #### Statistics 534 | 535 | * `erlang_vm_statistics_bytes_output_total`
536 | Type: counter.
537 | The total number of bytes output to ports. 538 | 539 | * `erlang_vm_statistics_bytes_received_total`
540 | Type: counter.
541 | The total number of bytes received through ports. 542 | 543 | * `erlang_vm_statistics_context_switches`
544 | Type: counter.
545 | The total number of context switches since the system started. 546 | 547 | * `erlang_vm_statistics_garbage_collection_number_of_gcs`
548 | Type: counter.
549 | The total number of garbage collections since the system started. 550 | 551 | * `erlang_vm_statistics_garbage_collection_bytes_reclaimed`
552 | Type: counter.
553 | The total number of bytes reclaimed by GC since the system started. 554 | 555 | * `erlang_vm_statistics_garbage_collection_words_reclaimed`
556 | Type: counter.
557 | The total number of words reclaimed by GC since the system started. 558 | 559 | * `erlang_vm_statistics_reductions_total`
560 | Type: counter.
561 | Total reductions count. 562 | 563 | * `erlang_vm_statistics_run_queues_length_total`
564 | Type: gauge.
565 | The total length of the run-queues. That is, the number of 566 | processes and ports that are ready to run on all available run-queues. 567 | 568 | * `erlang_vm_statistics_runtime_milliseconds`
569 | Type: counter.
570 | The sum of the runtime for all threads in the Erlang runtime system. 571 | 572 | * `erlang_vm_statistics_wallclock_time_milliseconds`
573 | Type: counter.
574 | Can be used in the same manner as 575 | `erlang_vm_statistics_runtime_milliseconds`, except that real time is 576 | measured as opposed to runtime or CPU time. 577 | 578 | #### Memory 579 | 580 | * `erlang_vm_memory_atom_bytes_total{usage="free|used"}`
581 | Type: gauge.
582 | The total amount of memory currently allocated for atoms. 583 | This memory is part of the memory presented as system memory. 584 | 585 | * `erlang_vm_memory_bytes_total{kind="system|processes"}`
586 | Type: gauge.
587 | The total amount of memory currently allocated. 588 | This is the same as the sum of the memory size for processes and system. 589 | 590 | * `erlang_vm_dets_tables`
591 | Type: gauge.
592 | Erlang VM DETS Tables count. 593 | 594 | * `erlang_vm_ets_tables`
595 | Type: gauge.
596 | Erlang VM ETS Tables count. 597 | 598 | * `erlang_vm_memory_processes_bytes_total{usage="free|used"}`
599 | Type: gauge.
600 | The total amount of memory currently allocated for the Erlang processes. 601 | 602 | * `erlang_vm_memory_system_bytes_total{usage="atom|binary|code|ets|other"}`
603 | Type: gauge.
604 | The total amount of memory currently allocated for the emulator 605 | that is not directly related to any Erlang process. 606 | Memory presented as processes is not included in this memory. 607 | 608 | ### Mnesia 609 | 610 | * `erlang_mnesia_held_locks`
611 | Type: gauge.
612 | Number of held locks. 613 | 614 | * `erlang_mnesia_lock_queue`
615 | Type: gauge.
616 | Number of transactions waiting for a lock. 617 | 618 | * `erlang_mnesia_transaction_participants`
619 | Type: gauge.
620 | Number of participant transactions. 621 | 622 | * `erlang_mnesia_transaction_coordinators`
623 | Type: gauge.
624 | Number of coordinator transactions. 625 | 626 | * `erlang_mnesia_failed_transactions`
627 | Type: counter.
628 | Number of failed (i.e. aborted) transactions. 629 | 630 | * `erlang_mnesia_committed_transactions`
631 | Type: gauge.
632 | Number of committed transactions. 633 | 634 | * `erlang_mnesia_logged_transactions`
635 | Type: counter.
636 | Number of transactions logged. 637 | 638 | * `erlang_mnesia_restarted_transactions`
639 | Type: counter.
640 | Total number of transaction restarts. 641 | 642 | ### Process Metrics 643 | (Process info collector must be enabled) 644 | 645 | * `process_open_fds`
646 | Type: gauge.
647 | Number of open file descriptors. 648 | 649 | * `process_max_fds`
650 | Type: gauge.
651 | Maximum number of open file descriptors. 652 | 653 | * `process_start_time_seconds`
654 | Type: gauge.
655 | Start time of the process since unix epoch in seconds. 656 | 657 | * `process_uptime_seconds`
658 | Type: gauge.
659 | Process uptime in seconds. 660 | 661 | * `process_threads_total`
662 | Type: gauge.
663 | Process threads count. 664 | 665 | * `process_virtual_memory_bytes`
666 | Type: gauge.
667 | Virtual memory size in bytes. 668 | 669 | * `process_resident_memory_bytes`
670 | Type: gauge.
671 | Resident memory size in bytes; 672 | 673 | * `process_cpu_seconds_total{kind="utime|stime"}`
674 | Type: counter.
675 | Process CPU time. 676 | 677 | ### Exporter Metrics 678 | 679 | Labels: `registry`, `content_type`. 680 | 681 | * `telemetry_scrape_duration_seconds`
682 | Type: summary.
683 | Scrape duration. 684 | 685 | * `telemetry_scrape_size_bytes`
686 | Type: summary.
687 | Scrape size, uncompressed. 688 | 689 | ## License 690 | MIT 691 | -------------------------------------------------------------------------------- /include/prometheus_rabbitmq_exporter.hrl: -------------------------------------------------------------------------------- 1 | -include_lib("prometheus/include/prometheus.hrl"). 2 | -include_lib("rabbit_common/include/rabbit.hrl"). 3 | 4 | -define(NO_RANGE, {no_range, no_range, no_range, no_range}). 5 | 6 | -------------------------------------------------------------------------------- /priv/dashboards/RabbitMQErlangVM.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_PROM", 5 | "label": "prom", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "panel", 15 | "id": "singlestat", 16 | "name": "Singlestat", 17 | "version": "" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "" 24 | }, 25 | { 26 | "type": "grafana", 27 | "id": "grafana", 28 | "name": "Grafana", 29 | "version": "3.1.1" 30 | }, 31 | { 32 | "type": "datasource", 33 | "id": "prometheus", 34 | "name": "Prometheus", 35 | "version": "1.0.0" 36 | } 37 | ], 38 | "id": null, 39 | "title": "RabbitMQ", 40 | "tags": [], 41 | "style": "dark", 42 | "timezone": "browser", 43 | "editable": true, 44 | "hideControls": false, 45 | "sharedCrosshair": false, 46 | "rows": [ 47 | { 48 | "collapse": false, 49 | "editable": true, 50 | "height": "250px", 51 | "panels": [ 52 | { 53 | "title": "Uptime", 54 | "error": false, 55 | "span": 2, 56 | "editable": true, 57 | "type": "singlestat", 58 | "isNew": true, 59 | "id": 9, 60 | "targets": [ 61 | { 62 | "refId": "A", 63 | "expr": "process_uptime_seconds{job=\"rabbitmq\"}", 64 | "intervalFactor": 2, 65 | "step": 20, 66 | "legendFormat": "" 67 | } 68 | ], 69 | "links": [], 70 | "datasource": "${DS_PROM}", 71 | "maxDataPoints": 100, 72 | "interval": null, 73 | "cacheTimeout": null, 74 | "format": "dtdurations", 75 | "prefix": "", 76 | "postfix": "", 77 | "nullText": null, 78 | "valueMaps": [ 79 | { 80 | "value": "null", 81 | "op": "=", 82 | "text": "N/A" 83 | } 84 | ], 85 | "mappingTypes": [ 86 | { 87 | "name": "value to text", 88 | "value": 1 89 | }, 90 | { 91 | "name": "range to text", 92 | "value": 2 93 | } 94 | ], 95 | "rangeMaps": [ 96 | { 97 | "from": "null", 98 | "to": "null", 99 | "text": "N/A" 100 | } 101 | ], 102 | "mappingType": 1, 103 | "nullPointMode": "connected", 104 | "valueName": "avg", 105 | "prefixFontSize": "50%", 106 | "valueFontSize": "80%", 107 | "postfixFontSize": "50%", 108 | "thresholds": "", 109 | "colorBackground": false, 110 | "colorValue": false, 111 | "colors": [ 112 | "rgba(245, 54, 54, 0.9)", 113 | "rgba(237, 129, 40, 0.89)", 114 | "rgba(50, 172, 45, 0.97)" 115 | ], 116 | "sparkline": { 117 | "show": false, 118 | "full": false, 119 | "lineColor": "rgb(31, 120, 193)", 120 | "fillColor": "rgba(31, 118, 189, 0.18)" 121 | }, 122 | "gauge": { 123 | "show": false, 124 | "minValue": 0, 125 | "maxValue": 100, 126 | "thresholdMarkers": true, 127 | "thresholdLabels": false 128 | }, 129 | "decimals": 0 130 | }, 131 | { 132 | "aliasColors": {}, 133 | "bars": false, 134 | "datasource": "${DS_PROM}", 135 | "editable": true, 136 | "error": false, 137 | "fill": 1, 138 | "grid": { 139 | "threshold1": null, 140 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 141 | "threshold2": null, 142 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 143 | }, 144 | "height": "", 145 | "id": 2, 146 | "isNew": true, 147 | "legend": { 148 | "alignAsTable": false, 149 | "avg": false, 150 | "current": false, 151 | "max": false, 152 | "min": false, 153 | "show": true, 154 | "total": false, 155 | "values": false 156 | }, 157 | "lines": true, 158 | "linewidth": 2, 159 | "links": [], 160 | "nullPointMode": "connected", 161 | "percentage": false, 162 | "pointradius": 5, 163 | "points": false, 164 | "renderer": "flot", 165 | "seriesOverrides": [], 166 | "span": 5, 167 | "stack": false, 168 | "steppedLine": false, 169 | "targets": [ 170 | { 171 | "expr": "sum by (job) (irate(rabbitmq_queue_messages_published_total[5m]))", 172 | "intervalFactor": 2, 173 | "legendFormat": "Messages Published", 174 | "metric": "", 175 | "refId": "A", 176 | "step": 2 177 | }, 178 | { 179 | "expr": "sum by (job) (irate(rabbitmq_queue_messages_delivered_total[5m]) + irate(rabbitmq_queue_messages_delivered_no_ack_total[5m]) + irate(rabbitmq_queue_messages_get_total[5m]) + irate(rabbitmq_queue_messages_get_no_ack_total[5m]))", 180 | "hide": false, 181 | "intervalFactor": 2, 182 | "legendFormat": "Messages delivered", 183 | "metric": "", 184 | "refId": "B", 185 | "step": 2 186 | } 187 | ], 188 | "timeFrom": null, 189 | "timeShift": null, 190 | "title": "Messages Rates", 191 | "tooltip": { 192 | "shared": true, 193 | "value_type": "cumulative", 194 | "sort": 0, 195 | "msResolution": false 196 | }, 197 | "transparent": false, 198 | "type": "graph", 199 | "yaxes": [ 200 | { 201 | "show": true, 202 | "min": null, 203 | "max": null, 204 | "logBase": 1, 205 | "format": "none", 206 | "label": "Messages" 207 | }, 208 | { 209 | "show": true, 210 | "min": null, 211 | "max": null, 212 | "logBase": 1, 213 | "format": "short", 214 | "label": "" 215 | } 216 | ], 217 | "xaxis": { 218 | "show": true 219 | } 220 | }, 221 | { 222 | "aliasColors": {}, 223 | "bars": false, 224 | "datasource": "${DS_PROM}", 225 | "editable": true, 226 | "error": false, 227 | "fill": 1, 228 | "grid": { 229 | "threshold1": null, 230 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 231 | "threshold2": null, 232 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 233 | }, 234 | "id": 1, 235 | "isNew": true, 236 | "legend": { 237 | "avg": false, 238 | "current": false, 239 | "max": false, 240 | "min": false, 241 | "show": true, 242 | "total": false, 243 | "values": false 244 | }, 245 | "lines": true, 246 | "linewidth": 2, 247 | "links": [], 248 | "nullPointMode": "connected", 249 | "percentage": false, 250 | "pointradius": 5, 251 | "points": false, 252 | "renderer": "flot", 253 | "seriesOverrides": [], 254 | "span": 5, 255 | "stack": false, 256 | "steppedLine": false, 257 | "targets": [ 258 | { 259 | "expr": "rabbitmq_connections", 260 | "intervalFactor": 2, 261 | "legendFormat": "Connections", 262 | "metric": "rabbitmq_connections", 263 | "refId": "A", 264 | "step": 2 265 | }, 266 | { 267 | "expr": "rabbitmq_channels", 268 | "intervalFactor": 2, 269 | "legendFormat": "Channels", 270 | "metric": "rabbitmq_channels", 271 | "refId": "B", 272 | "step": 2 273 | }, 274 | { 275 | "expr": "rabbitmq_consumers", 276 | "intervalFactor": 2, 277 | "legendFormat": "Consumers", 278 | "metric": "rabbitmq_consumers", 279 | "refId": "C", 280 | "step": 2 281 | }, 282 | { 283 | "expr": "rabbitmq_exchanges", 284 | "intervalFactor": 2, 285 | "legendFormat": "Exchanges", 286 | "metric": "rabbitmq_exchanges", 287 | "refId": "D", 288 | "step": 2 289 | }, 290 | { 291 | "expr": "rabbitmq_queues", 292 | "intervalFactor": 2, 293 | "legendFormat": "Queues", 294 | "metric": "rabbitmq_queues", 295 | "refId": "E", 296 | "step": 2 297 | } 298 | ], 299 | "timeFrom": null, 300 | "timeShift": null, 301 | "title": "Default VHost stat", 302 | "tooltip": { 303 | "shared": true, 304 | "value_type": "cumulative", 305 | "sort": 0, 306 | "msResolution": false 307 | }, 308 | "type": "graph", 309 | "yaxes": [ 310 | { 311 | "show": true, 312 | "min": null, 313 | "max": null, 314 | "logBase": 1, 315 | "format": "short" 316 | }, 317 | { 318 | "show": true, 319 | "min": null, 320 | "max": null, 321 | "logBase": 1, 322 | "format": "short" 323 | } 324 | ], 325 | "xaxis": { 326 | "show": true 327 | } 328 | } 329 | ], 330 | "title": "New row" 331 | }, 332 | { 333 | "collapse": false, 334 | "editable": true, 335 | "height": "250px", 336 | "panels": [ 337 | { 338 | "aliasColors": {}, 339 | "bars": false, 340 | "datasource": "${DS_PROM}", 341 | "editable": true, 342 | "error": false, 343 | "fill": 1, 344 | "grid": { 345 | "threshold1": null, 346 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 347 | "threshold2": null, 348 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 349 | }, 350 | "id": 6, 351 | "isNew": true, 352 | "legend": { 353 | "avg": false, 354 | "current": false, 355 | "max": false, 356 | "min": false, 357 | "show": true, 358 | "total": false, 359 | "values": false 360 | }, 361 | "lines": true, 362 | "linewidth": 2, 363 | "links": [], 364 | "nullPointMode": "connected", 365 | "percentage": false, 366 | "pointradius": 5, 367 | "points": false, 368 | "renderer": "flot", 369 | "seriesOverrides": [], 370 | "span": 4, 371 | "stack": false, 372 | "steppedLine": false, 373 | "targets": [ 374 | { 375 | "expr": "irate(erlang_vm_statistics_bytes_output_total[5m])", 376 | "intervalFactor": 2, 377 | "legendFormat": "Output Bytes", 378 | "metric": "erlang_vm_statistics_bytes_output_total", 379 | "refId": "A", 380 | "step": 2 381 | }, 382 | { 383 | "expr": "irate(erlang_vm_statistics_bytes_received_total[5m])", 384 | "intervalFactor": 2, 385 | "legendFormat": "Received Bytes", 386 | "metric": "erlang_vm_statistics_bytes_received_total", 387 | "refId": "B", 388 | "step": 2 389 | } 390 | ], 391 | "timeFrom": null, 392 | "timeShift": null, 393 | "title": "Erlang VM IO", 394 | "tooltip": { 395 | "shared": true, 396 | "value_type": "cumulative", 397 | "sort": 0, 398 | "msResolution": false 399 | }, 400 | "type": "graph", 401 | "yaxes": [ 402 | { 403 | "show": true, 404 | "min": null, 405 | "max": null, 406 | "logBase": 1, 407 | "format": "bytes" 408 | }, 409 | { 410 | "show": true, 411 | "min": null, 412 | "max": null, 413 | "logBase": 1, 414 | "format": "short" 415 | } 416 | ], 417 | "xaxis": { 418 | "show": true 419 | } 420 | }, 421 | { 422 | "aliasColors": {}, 423 | "bars": false, 424 | "datasource": "${DS_PROM}", 425 | "editable": true, 426 | "error": false, 427 | "fill": 1, 428 | "grid": { 429 | "threshold1": null, 430 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 431 | "threshold2": null, 432 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 433 | }, 434 | "id": 7, 435 | "isNew": true, 436 | "legend": { 437 | "alignAsTable": false, 438 | "avg": false, 439 | "current": false, 440 | "max": false, 441 | "min": false, 442 | "rightSide": false, 443 | "show": true, 444 | "total": false, 445 | "values": false 446 | }, 447 | "lines": true, 448 | "linewidth": 2, 449 | "links": [], 450 | "nullPointMode": "connected", 451 | "percentage": false, 452 | "pointradius": 5, 453 | "points": false, 454 | "renderer": "flot", 455 | "seriesOverrides": [ 456 | { 457 | "alias": "Words Reclaimed", 458 | "yaxis": 2 459 | } 460 | ], 461 | "span": 4, 462 | "stack": false, 463 | "steppedLine": false, 464 | "targets": [ 465 | { 466 | "expr": "irate(erlang_vm_statistics_garbage_collection_number_of_gcs[5m])", 467 | "intervalFactor": 2, 468 | "legendFormat": "Number of GCs", 469 | "metric": "erlang_vm_statistics_garbage_collection_number_of_gcs", 470 | "refId": "A", 471 | "step": 2 472 | }, 473 | { 474 | "expr": "irate(erlang_vm_statistics_garbage_collection_words_reclaimed[5m])", 475 | "intervalFactor": 2, 476 | "legendFormat": "Words Reclaimed", 477 | "metric": "erlang_vm_statistics_garbage_collection_words_reclaimed", 478 | "refId": "B", 479 | "step": 2 480 | } 481 | ], 482 | "timeFrom": null, 483 | "timeShift": null, 484 | "title": "Erlang VM GC", 485 | "tooltip": { 486 | "shared": true, 487 | "value_type": "cumulative", 488 | "sort": 0, 489 | "msResolution": false 490 | }, 491 | "type": "graph", 492 | "yaxes": [ 493 | { 494 | "show": true, 495 | "min": null, 496 | "max": null, 497 | "logBase": 1, 498 | "format": "short" 499 | }, 500 | { 501 | "show": true, 502 | "min": null, 503 | "max": null, 504 | "logBase": 1, 505 | "format": "short" 506 | } 507 | ], 508 | "xaxis": { 509 | "show": true 510 | } 511 | }, 512 | { 513 | "aliasColors": {}, 514 | "bars": false, 515 | "datasource": "${DS_PROM}", 516 | "editable": true, 517 | "error": false, 518 | "fill": 1, 519 | "grid": { 520 | "threshold1": null, 521 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 522 | "threshold2": null, 523 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 524 | }, 525 | "id": 3, 526 | "isNew": true, 527 | "legend": { 528 | "avg": false, 529 | "current": false, 530 | "max": false, 531 | "min": false, 532 | "show": true, 533 | "total": false, 534 | "values": false 535 | }, 536 | "lines": true, 537 | "linewidth": 2, 538 | "links": [], 539 | "nullPointMode": "connected", 540 | "percentage": false, 541 | "pointradius": 5, 542 | "points": false, 543 | "renderer": "flot", 544 | "seriesOverrides": [], 545 | "span": 4, 546 | "stack": true, 547 | "steppedLine": false, 548 | "targets": [ 549 | { 550 | "expr": "erlang_vm_memory_bytes_total{kind=\"processes\"}", 551 | "intervalFactor": 2, 552 | "legendFormat": "Processes Memory", 553 | "refId": "B", 554 | "step": 2 555 | }, 556 | { 557 | "expr": "erlang_vm_memory_system_bytes_total{usage=\"atom\"}", 558 | "intervalFactor": 2, 559 | "legendFormat": "Atoms", 560 | "refId": "C", 561 | "step": 2 562 | }, 563 | { 564 | "expr": "erlang_vm_memory_system_bytes_total{usage=\"binary\"}", 565 | "intervalFactor": 2, 566 | "legendFormat": "Binary", 567 | "refId": "D", 568 | "step": 2 569 | }, 570 | { 571 | "expr": "erlang_vm_memory_system_bytes_total{usage=\"code\"}", 572 | "intervalFactor": 2, 573 | "legendFormat": "Code", 574 | "refId": "E", 575 | "step": 2 576 | }, 577 | { 578 | "expr": "erlang_vm_memory_system_bytes_total{usage=\"ets\"}", 579 | "intervalFactor": 2, 580 | "legendFormat": "ETS", 581 | "refId": "F", 582 | "step": 2 583 | } 584 | ], 585 | "timeFrom": null, 586 | "timeShift": null, 587 | "title": "Erlang VM Memory", 588 | "tooltip": { 589 | "shared": true, 590 | "value_type": "individual", 591 | "sort": 0, 592 | "msResolution": false 593 | }, 594 | "type": "graph", 595 | "yaxes": [ 596 | { 597 | "show": true, 598 | "min": null, 599 | "max": null, 600 | "logBase": 1, 601 | "format": "bytes" 602 | }, 603 | { 604 | "show": true, 605 | "min": null, 606 | "max": null, 607 | "logBase": 1, 608 | "format": "short" 609 | } 610 | ], 611 | "xaxis": { 612 | "show": true 613 | } 614 | } 615 | ], 616 | "title": "New row" 617 | }, 618 | { 619 | "collapse": false, 620 | "editable": true, 621 | "height": "250px", 622 | "panels": [ 623 | { 624 | "title": "Process Memory", 625 | "error": false, 626 | "span": 4, 627 | "editable": true, 628 | "type": "graph", 629 | "isNew": true, 630 | "id": 11, 631 | "targets": [ 632 | { 633 | "refId": "A", 634 | "expr": "process_virtual_memory_bytes{job=\"rabbitmq\"}", 635 | "intervalFactor": 2, 636 | "step": 2, 637 | "legendFormat": "Virtual Memory" 638 | }, 639 | { 640 | "expr": "process_resident_memory_bytes{job=\"rabbitmq\"}", 641 | "intervalFactor": 2, 642 | "refId": "B", 643 | "step": 2, 644 | "legendFormat": "Resident Memory" 645 | } 646 | ], 647 | "datasource": "${DS_PROM}", 648 | "renderer": "flot", 649 | "yaxes": [ 650 | { 651 | "label": null, 652 | "show": true, 653 | "logBase": 1, 654 | "min": null, 655 | "max": null, 656 | "format": "bytes" 657 | }, 658 | { 659 | "label": null, 660 | "show": true, 661 | "logBase": 1, 662 | "min": null, 663 | "max": null, 664 | "format": "short" 665 | } 666 | ], 667 | "xaxis": { 668 | "show": true 669 | }, 670 | "grid": { 671 | "threshold1": null, 672 | "threshold2": null, 673 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 674 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 675 | }, 676 | "lines": true, 677 | "fill": 1, 678 | "linewidth": 2, 679 | "points": false, 680 | "pointradius": 5, 681 | "bars": false, 682 | "stack": false, 683 | "percentage": false, 684 | "legend": { 685 | "show": true, 686 | "values": false, 687 | "min": false, 688 | "max": false, 689 | "current": false, 690 | "total": false, 691 | "avg": false 692 | }, 693 | "nullPointMode": "connected", 694 | "steppedLine": false, 695 | "tooltip": { 696 | "value_type": "cumulative", 697 | "shared": true, 698 | "sort": 0, 699 | "msResolution": true 700 | }, 701 | "timeFrom": null, 702 | "timeShift": null, 703 | "aliasColors": {}, 704 | "seriesOverrides": [], 705 | "links": [] 706 | }, 707 | { 708 | "title": "File Descriptors", 709 | "error": false, 710 | "span": 4, 711 | "editable": true, 712 | "type": "graph", 713 | "isNew": true, 714 | "id": 8, 715 | "targets": [ 716 | { 717 | "refId": "A", 718 | "expr": "process_open_fds{job=\"rabbitmq\"}", 719 | "intervalFactor": 2, 720 | "step": 2, 721 | "metric": "", 722 | "legendFormat": "Open FDs" 723 | }, 724 | { 725 | "expr": "process_max_fds{job=\"rabbitmq\"}", 726 | "intervalFactor": 2, 727 | "refId": "B", 728 | "step": 2, 729 | "legendFormat": "Max FDs" 730 | } 731 | ], 732 | "datasource": "${DS_PROM}", 733 | "renderer": "flot", 734 | "yaxes": [ 735 | { 736 | "label": null, 737 | "show": true, 738 | "logBase": 1, 739 | "min": null, 740 | "max": null, 741 | "format": "none" 742 | }, 743 | { 744 | "label": null, 745 | "show": true, 746 | "logBase": 1, 747 | "min": null, 748 | "max": null, 749 | "format": "short" 750 | } 751 | ], 752 | "xaxis": { 753 | "show": true 754 | }, 755 | "grid": { 756 | "threshold1": null, 757 | "threshold2": null, 758 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 759 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 760 | }, 761 | "lines": true, 762 | "fill": 1, 763 | "linewidth": 2, 764 | "points": false, 765 | "pointradius": 5, 766 | "bars": false, 767 | "stack": false, 768 | "percentage": false, 769 | "legend": { 770 | "show": true, 771 | "values": false, 772 | "min": false, 773 | "max": false, 774 | "current": false, 775 | "total": false, 776 | "avg": false 777 | }, 778 | "nullPointMode": "connected", 779 | "steppedLine": false, 780 | "tooltip": { 781 | "value_type": "cumulative", 782 | "shared": true, 783 | "sort": 0, 784 | "msResolution": true 785 | }, 786 | "timeFrom": null, 787 | "timeShift": null, 788 | "aliasColors": {}, 789 | "seriesOverrides": [], 790 | "links": [] 791 | }, 792 | { 793 | "title": "Native Threads & CPU", 794 | "error": false, 795 | "span": 4, 796 | "editable": true, 797 | "type": "graph", 798 | "isNew": true, 799 | "id": 10, 800 | "targets": [ 801 | { 802 | "refId": "A", 803 | "expr": "process_threads_total{job=\"rabbitmq\"}", 804 | "intervalFactor": 2, 805 | "step": 2, 806 | "legendFormat": "Threads" 807 | }, 808 | { 809 | "expr": "sum(irate(process_cpu_seconds_total{job=\"rabbitmq\"}[30s])) without (kind) * 100", 810 | "intervalFactor": 2, 811 | "refId": "B", 812 | "step": 2, 813 | "legendFormat": "CPU" 814 | } 815 | ], 816 | "datasource": "${DS_PROM}", 817 | "renderer": "flot", 818 | "yaxes": [ 819 | { 820 | "label": null, 821 | "show": true, 822 | "logBase": 1, 823 | "min": null, 824 | "max": null, 825 | "format": "percent" 826 | }, 827 | { 828 | "label": null, 829 | "show": true, 830 | "logBase": 1, 831 | "min": null, 832 | "max": null, 833 | "format": "short" 834 | } 835 | ], 836 | "xaxis": { 837 | "show": true 838 | }, 839 | "grid": { 840 | "threshold1": null, 841 | "threshold2": null, 842 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 843 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 844 | }, 845 | "lines": true, 846 | "fill": 1, 847 | "linewidth": 2, 848 | "points": false, 849 | "pointradius": 5, 850 | "bars": false, 851 | "stack": false, 852 | "percentage": false, 853 | "legend": { 854 | "show": true, 855 | "values": false, 856 | "min": false, 857 | "max": false, 858 | "current": false, 859 | "total": false, 860 | "avg": false 861 | }, 862 | "nullPointMode": "connected", 863 | "steppedLine": false, 864 | "tooltip": { 865 | "value_type": "cumulative", 866 | "shared": true, 867 | "sort": 0, 868 | "msResolution": true 869 | }, 870 | "timeFrom": null, 871 | "timeShift": null, 872 | "aliasColors": {}, 873 | "seriesOverrides": [ 874 | { 875 | "alias": "Threads", 876 | "yaxis": 2 877 | } 878 | ], 879 | "links": [], 880 | "decimals": null 881 | } 882 | ], 883 | "title": "New row" 884 | } 885 | ], 886 | "time": { 887 | "from": "now-15m", 888 | "to": "now" 889 | }, 890 | "timepicker": { 891 | "now": true, 892 | "refresh_intervals": [ 893 | "5s", 894 | "10s", 895 | "30s", 896 | "1m", 897 | "5m", 898 | "15m", 899 | "30m", 900 | "1h", 901 | "2h", 902 | "1d" 903 | ], 904 | "time_options": [ 905 | "5m", 906 | "15m", 907 | "1h", 908 | "6h", 909 | "12h", 910 | "24h", 911 | "2d", 912 | "7d", 913 | "30d" 914 | ] 915 | }, 916 | "templating": { 917 | "list": [] 918 | }, 919 | "annotations": { 920 | "list": [] 921 | }, 922 | "refresh": "5s", 923 | "schemaVersion": 12, 924 | "version": 18, 925 | "links": [], 926 | "gnetId": null 927 | } 928 | -------------------------------------------------------------------------------- /priv/dashboards/RabbitMQErlangVM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prometheus-erl/prometheus_rabbitmq_exporter/4bb013dc21cc40097d044be78aa3ee0443e17dfd/priv/dashboards/RabbitMQErlangVM.png -------------------------------------------------------------------------------- /rabbitmq-components.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(.DEFAULT_GOAL),) 2 | # Define default goal to `all` because this file defines some targets 3 | # before the inclusion of erlang.mk leading to the wrong target becoming 4 | # the default. 5 | .DEFAULT_GOAL = all 6 | endif 7 | 8 | # PROJECT_VERSION defaults to: 9 | # 1. the version exported by rabbitmq-server-release; 10 | # 2. the version stored in `git-revisions.txt`, if it exists; 11 | # 3. a version based on git-describe(1), if it is a Git clone; 12 | # 4. 0.0.0 13 | 14 | PROJECT_VERSION := $(RABBITMQ_VERSION) 15 | 16 | ifeq ($(PROJECT_VERSION),) 17 | PROJECT_VERSION := $(shell \ 18 | if test -f git-revisions.txt; then \ 19 | head -n1 git-revisions.txt | \ 20 | awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ 21 | else \ 22 | (git describe --dirty --abbrev=7 --tags --always --first-parent \ 23 | 2>/dev/null || echo rabbitmq_v0_0_0) | \ 24 | sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ 25 | -e 's/-/./g'; \ 26 | fi) 27 | endif 28 | 29 | # -------------------------------------------------------------------- 30 | # RabbitMQ components. 31 | # -------------------------------------------------------------------- 32 | 33 | # For RabbitMQ repositories, we want to checkout branches which match 34 | # the parent project. For instance, if the parent project is on a 35 | # release tag, dependencies must be on the same release tag. If the 36 | # parent project is on a topic branch, dependencies must be on the same 37 | # topic branch or fallback to `stable` or `master` whichever was the 38 | # base of the topic branch. 39 | 40 | dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master 41 | dep_amqp10_client = git_rmq rabbitmq-amqp1.0-client $(current_rmq_ref) $(base_rmq_ref) master 42 | dep_amqp10_common = git_rmq rabbitmq-amqp1.0-common $(current_rmq_ref) $(base_rmq_ref) master 43 | dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master 44 | dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master 45 | dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master 46 | dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master 47 | dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master 48 | dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master 49 | dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master 50 | dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master 51 | dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master 52 | dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master 53 | dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master 54 | dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master 55 | dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master 56 | dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master 57 | dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master 58 | dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master 59 | dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master 60 | dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master 61 | dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master 62 | dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master 63 | dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master 64 | dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master 65 | dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master 66 | dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master 67 | dep_rabbitmq_lvc_exchange = git_rmq rabbitmq-lvc-exchange $(current_rmq_ref) $(base_rmq_ref) master 68 | dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master 69 | dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master 70 | dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master 71 | dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master 72 | dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master 73 | dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master 74 | dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master 75 | dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master 76 | dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master 77 | dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master 78 | dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master 79 | dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master 80 | dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master 81 | dep_rabbitmq_random_exchange = git_rmq rabbitmq-random-exchange $(current_rmq_ref) $(base_rmq_ref) master 82 | dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master 83 | dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master 84 | dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master 85 | dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master 86 | dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master 87 | dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master 88 | dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master 89 | dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master 90 | dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master 91 | dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master 92 | dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master 93 | dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master 94 | dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master 95 | dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master 96 | dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master 97 | dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master 98 | dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master 99 | dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master 100 | dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master 101 | dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master 102 | 103 | dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master 104 | 105 | # Third-party dependencies version pinning. 106 | # 107 | # We do that in this file, which is copied in all projects, to ensure 108 | # all projects use the same versions. It avoids conflicts and makes it 109 | # possible to work with rabbitmq-public-umbrella. 110 | 111 | dep_cowboy = hex 2.6.1 112 | dep_cowlib = hex 2.7.0 113 | dep_jsx = hex 2.9.0 114 | dep_lager = hex 3.6.5 115 | dep_ra = git https://github.com/rabbitmq/ra.git master 116 | dep_ranch = hex 1.7.1 117 | dep_recon = hex 2.3.6 118 | dep_sysmon_handler = hex 1.1.0 119 | 120 | RABBITMQ_COMPONENTS = amqp_client \ 121 | amqp10_common \ 122 | amqp10_client \ 123 | rabbit \ 124 | rabbit_common \ 125 | rabbitmq_amqp1_0 \ 126 | rabbitmq_auth_backend_amqp \ 127 | rabbitmq_auth_backend_cache \ 128 | rabbitmq_auth_backend_http \ 129 | rabbitmq_auth_backend_ldap \ 130 | rabbitmq_auth_mechanism_ssl \ 131 | rabbitmq_aws \ 132 | rabbitmq_boot_steps_visualiser \ 133 | rabbitmq_cli \ 134 | rabbitmq_codegen \ 135 | rabbitmq_consistent_hash_exchange \ 136 | rabbitmq_ct_client_helpers \ 137 | rabbitmq_ct_helpers \ 138 | rabbitmq_delayed_message_exchange \ 139 | rabbitmq_dotnet_client \ 140 | rabbitmq_event_exchange \ 141 | rabbitmq_federation \ 142 | rabbitmq_federation_management \ 143 | rabbitmq_java_client \ 144 | rabbitmq_jms_client \ 145 | rabbitmq_jms_cts \ 146 | rabbitmq_jms_topic_exchange \ 147 | rabbitmq_lvc_exchange \ 148 | rabbitmq_management \ 149 | rabbitmq_management_agent \ 150 | rabbitmq_management_exchange \ 151 | rabbitmq_management_themes \ 152 | rabbitmq_message_timestamp \ 153 | rabbitmq_metronome \ 154 | rabbitmq_mqtt \ 155 | rabbitmq_objc_client \ 156 | rabbitmq_peer_discovery_aws \ 157 | rabbitmq_peer_discovery_common \ 158 | rabbitmq_peer_discovery_consul \ 159 | rabbitmq_peer_discovery_etcd \ 160 | rabbitmq_peer_discovery_k8s \ 161 | rabbitmq_random_exchange \ 162 | rabbitmq_recent_history_exchange \ 163 | rabbitmq_routing_node_stamp \ 164 | rabbitmq_rtopic_exchange \ 165 | rabbitmq_server_release \ 166 | rabbitmq_sharding \ 167 | rabbitmq_shovel \ 168 | rabbitmq_shovel_management \ 169 | rabbitmq_stomp \ 170 | rabbitmq_toke \ 171 | rabbitmq_top \ 172 | rabbitmq_tracing \ 173 | rabbitmq_trust_store \ 174 | rabbitmq_web_dispatch \ 175 | rabbitmq_web_mqtt \ 176 | rabbitmq_web_mqtt_examples \ 177 | rabbitmq_web_stomp \ 178 | rabbitmq_web_stomp_examples \ 179 | rabbitmq_website 180 | 181 | # Several components have a custom erlang.mk/build.config, mainly 182 | # to disable eunit. Therefore, we can't use the top-level project's 183 | # erlang.mk copy. 184 | NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) 185 | 186 | ifeq ($(origin current_rmq_ref),undefined) 187 | ifneq ($(wildcard .git),) 188 | current_rmq_ref := $(shell (\ 189 | ref=$$(LANG=C git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ 190 | if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) 191 | else 192 | current_rmq_ref := master 193 | endif 194 | endif 195 | export current_rmq_ref 196 | 197 | ifeq ($(origin base_rmq_ref),undefined) 198 | ifneq ($(wildcard .git),) 199 | possible_base_rmq_ref := v3.7.x 200 | ifeq ($(possible_base_rmq_ref),$(current_rmq_ref)) 201 | base_rmq_ref := $(current_rmq_ref) 202 | else 203 | base_rmq_ref := $(shell \ 204 | (git rev-parse --verify -q master >/dev/null && \ 205 | git rev-parse --verify -q $(possible_base_rmq_ref) >/dev/null && \ 206 | git merge-base --is-ancestor $$(git merge-base master HEAD) $(possible_base_rmq_ref) && \ 207 | echo $(possible_base_rmq_ref)) || \ 208 | echo master) 209 | endif 210 | else 211 | base_rmq_ref := master 212 | endif 213 | endif 214 | export base_rmq_ref 215 | 216 | # Repository URL selection. 217 | # 218 | # First, we infer other components' location from the current project 219 | # repository URL, if it's a Git repository: 220 | # - We take the "origin" remote URL as the base 221 | # - The current project name and repository name is replaced by the 222 | # target's properties: 223 | # eg. rabbitmq-common is replaced by rabbitmq-codegen 224 | # eg. rabbit_common is replaced by rabbitmq_codegen 225 | # 226 | # If cloning from this computed location fails, we fallback to RabbitMQ 227 | # upstream which is GitHub. 228 | 229 | # Macro to transform eg. "rabbit_common" to "rabbitmq-common". 230 | rmq_cmp_repo_name = $(word 2,$(dep_$(1))) 231 | 232 | # Upstream URL for the current project. 233 | RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) 234 | RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git 235 | RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git 236 | 237 | # Current URL for the current project. If this is not a Git clone, 238 | # default to the upstream Git repository. 239 | ifneq ($(wildcard .git),) 240 | git_origin_fetch_url := $(shell git config remote.origin.url) 241 | git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) 242 | RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) 243 | RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) 244 | else 245 | RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) 246 | RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) 247 | endif 248 | 249 | # Macro to replace the following pattern: 250 | # 1. /foo.git -> /bar.git 251 | # 2. /foo -> /bar 252 | # 3. /foo/ -> /bar/ 253 | subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) 254 | 255 | # Macro to replace both the project's name (eg. "rabbit_common") and 256 | # repository name (eg. "rabbitmq-common") by the target's equivalent. 257 | # 258 | # This macro is kept on one line because we don't want whitespaces in 259 | # the returned value, as it's used in $(dep_fetch_git_rmq) in a shell 260 | # single-quoted string. 261 | dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) 262 | 263 | dep_rmq_commits = $(if $(dep_$(1)), \ 264 | $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ 265 | $(pkg_$(1)_commit)) 266 | 267 | define dep_fetch_git_rmq 268 | fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ 269 | fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ 270 | if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ 271 | git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ 272 | fetch_url="$$$$fetch_url1"; \ 273 | push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ 274 | elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ 275 | fetch_url="$$$$fetch_url2"; \ 276 | push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ 277 | fi; \ 278 | cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ 279 | $(foreach ref,$(call dep_rmq_commits,$(1)), \ 280 | git checkout -q $(ref) >/dev/null 2>&1 || \ 281 | ) \ 282 | (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ 283 | 1>&2 && false) ) && \ 284 | (test "$$$$fetch_url" = "$$$$push_url" || \ 285 | git remote set-url --push origin "$$$$push_url") 286 | endef 287 | 288 | # -------------------------------------------------------------------- 289 | # Component distribution. 290 | # -------------------------------------------------------------------- 291 | 292 | list-dist-deps:: 293 | @: 294 | 295 | prepare-dist:: 296 | @: 297 | 298 | # -------------------------------------------------------------------- 299 | # Umbrella-specific settings. 300 | # -------------------------------------------------------------------- 301 | 302 | # If this project is under the Umbrella project, we override $(DEPS_DIR) 303 | # to point to the Umbrella's one. We also disable `make distclean` so 304 | # $(DEPS_DIR) is not accidentally removed. 305 | 306 | ifneq ($(wildcard ../../UMBRELLA.md),) 307 | UNDER_UMBRELLA = 1 308 | else ifneq ($(wildcard UMBRELLA.md),) 309 | UNDER_UMBRELLA = 1 310 | endif 311 | 312 | ifeq ($(UNDER_UMBRELLA),1) 313 | ifneq ($(PROJECT),rabbitmq_public_umbrella) 314 | DEPS_DIR ?= $(abspath ..) 315 | endif 316 | 317 | ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) 318 | SKIP_DEPS = 1 319 | endif 320 | endif 321 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_core_metrics_collector.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_core_metrics_collector). 2 | -export([register/0, 3 | register/1, 4 | deregister_cleanup/1, 5 | collect_mf/2, 6 | collect_metrics/2]). 7 | 8 | -import(prometheus_model_helpers, [create_mf/4, 9 | create_mf/5, 10 | label_pairs/1, 11 | gauge_metrics/1, 12 | gauge_metric/1, 13 | gauge_metric/2, 14 | counter_metric/1, 15 | counter_metric/2, 16 | untyped_metric/1, 17 | untyped_metric/2]). 18 | 19 | -include("prometheus_rabbitmq_exporter.hrl"). 20 | -behaviour(prometheus_collector). 21 | 22 | -define(METRIC_NAME_PREFIX, "rabbitmq_core_"). 23 | 24 | % These metrics are mapped to ETS tables 25 | -define(METRICS, 26 | [ 27 | {channel_metrics, [ 28 | {2, channel_consumer_count, gauge, "Consumers count.", consumer_count}, 29 | {2, channel_messages_unacknowledged, gauge, "Count of messages unacknowledged.", messages_unacknowledged}, 30 | {2, channel_messages_unconfirmed, gauge, "Count of messages unconfirmed.", messages_unconfirmed}, 31 | {2, channel_messages_uncommited, gauge, "Count of messages uncommited.", messages_uncommited}, 32 | {2, channel_messages_prefetch_count, gauge, "Limit to the number of unacknowledged messages on every connection on a channel.", prefetch_count}, 33 | {2, channel_messages_global_prefetch_count, gauge, "Global limit to the number of unacknowledged messages shared between all connections on a channel.", global_prefetch_count} 34 | ]}, 35 | 36 | {channel_exchange_metrics, [ 37 | {2, channel_exchange_publish, gauge, "Count of messages published."}, 38 | {3, channel_exchange_confirm, gauge, "Count of messages confirmed."}, 39 | {4, channel_exchange_return_unroutable, gauge, "Count of messages returned to publisher as unroutable."} 40 | ]}, 41 | 42 | {channel_process_metrics, [ 43 | {2, channel_process_reductions, counter, "Count of reductions that take place on the channel process."} 44 | ]}, 45 | 46 | {channel_queue_metrics, [ 47 | {2, channel_queue_get, counter, "Count of messages delivered in acknowledgement mode in response to basic.get."}, 48 | {3, channel_queue_get_no_ack, counter, "Count of messages delivered in no-acknowledgement mode in response to basic.get."}, 49 | {4, channel_queue_deliver, counter, "Count of messages delivered in acknowledgement mode to consumers."}, 50 | {5, channel_queue_deliver_no_ack, counter, "Count of messages delivered in no-acknowledgement mode to consumers."}, 51 | {6, channel_queue_redeliver, counter, "Count of subset of delivered messages which had the redelivered flag set."}, 52 | {7, channel_queue_ack, counter, "Count of messages acknowledged."} 53 | ]}, 54 | 55 | {connection_churn_metrics, [ 56 | {2, connection_created, counter, "Connections created."}, 57 | {3, connection_closed, counter, "Connections closed."}, 58 | {4, channel_created, counter, "Channels created."}, 59 | {5, channel_closed, counter, "Channels closed."}, 60 | {6, queue_declared, counter, "Queues declared."}, 61 | {7, queue_created, counter, "Queues created."}, 62 | {8, queue_deleted, counter, "Queues deleted."} 63 | ]}, 64 | 65 | {connection_coarse_metrics, [ 66 | {2, connection_recv_oct, counter, "Count of octects received on the connection."}, 67 | {3, connection_send_oct, counter, "Count of octects sent on the connection."}, 68 | {4, connection_reductions, counter, "Count of reductions that take place on the queue process."} 69 | ]}, 70 | 71 | {connection_metrics, [ 72 | {2, connection_recv_count, counter, "Count of bytes received on the connection.", recv_cnt}, 73 | {2, connection_send_count, counter, "Count of bytes send on the connection.", send_cnt} 74 | ]}, 75 | 76 | {channel_queue_exchange_metrics, [ 77 | {2, channel_queue_exchange_publish, counter, "Count of messages published."} 78 | ]}, 79 | 80 | {node_coarse_metrics, [ 81 | {2, node_fd_used, gauge, "File descriptors used.", fd_used}, 82 | {2, node_sockets_used, gauge, "Sockets used.", sockets_used}, 83 | {2, node_mem_used, gauge, "Memory used in bytes.", mem_used}, 84 | {2, node_disk_free, gauge, "Disk free in bytes.", disk_free}, 85 | {2, node_proc_used, gauge, "Erlang processes used.", proc_used}, 86 | {2, node_gc_num, counter, "GC runs.", gc_num}, 87 | {2, node_gc_bytes_reclaimed, counter, "Bytes reclaimed by GC.", gc_bytes_reclaimed}, 88 | {2, node_context_switches, counter, "Context switches since node start.", context_switches} 89 | ]}, 90 | 91 | {node_metrics, [ 92 | {2, node_fd_total, gauge, "File descriptors available.", fd_total}, 93 | {2, node_sockets_total, gauge, "Sockets available.", sockets_total}, 94 | {2, node_mem_limit, gauge, "Memory usage high watermark.", mem_limit}, 95 | {2, node_disk_free_limit, gauge, "Free disk space low watermark.", disk_free_limit}, 96 | {2, node_proc_total, gauge, "Erlang processes limit.", proc_total}, 97 | {2, node_uptime, gauge, "Time in milliseconds since node start.", uptime}, 98 | {2, node_run_queue, gauge, "Runtime run queue.", run_queue}, 99 | {2, node_processors, gauge, "Logical processors.", processors}, 100 | {2, node_net_ticktime, gauge, "Periodic tick interval between all pairs of nodes to maintain the connections and to detect disconnections.", net_ticktime} 101 | ]}, 102 | 103 | {node_node_metrics, [ 104 | {2, node_node_send_bytes, counter, "Count of bytes sent to node.", send_bytes}, 105 | {2, node_node_recv_bytes, counter, "Count of bytes received from node.", recv_bytes} 106 | ]}, 107 | 108 | {node_persister_metrics, [ 109 | {2, node_io_read_count, counter, "Read operations since node start.", io_read_count}, 110 | {2, node_io_read_bytes, gauge, "Bytes read since node start.", io_read_bytes}, 111 | {2, node_io_read_time, gauge, "Total time of read operations.", io_read_time}, 112 | {2, node_io_write_count, counter, "Write operations since node start.", io_write_count}, 113 | {2, node_io_write_bytes, gauge, "Bytes written since node start.", io_write_bytes}, 114 | {2, node_io_write_time, gauge, "Total time of write operations.", io_write_time}, 115 | {2, node_io_sync_count, counter, "Sync operations since node start.", io_sync_count}, 116 | {2, node_io_sync_time, gauge, "Total time of sync operations.", io_sync_time}, 117 | {2, node_io_seek_count, counter, "Seek operations since node start.", io_seek_count}, 118 | {2, node_io_seek_time, gauge, "Total time of seek operations.", io_seek_time}, 119 | {2, node_io_reopen_count, counter, "Times files have been reopened by the file handle cache.", io_reopen_count}, 120 | {2, node_mnesia_ram_tx_count, counter, "Mnesia transactions in RAM since node start.", mnesia_ram_tx_count}, 121 | {2, node_mnesia_disk_tx_count, counter, "Mnesia transactions in disk since node start.", mnesia_disk_tx_count}, 122 | {2, node_msg_store_read_count, counter, "Read operations in the message store since node start.", msg_store_read_count}, 123 | {2, node_msg_store_write_count, counter, "Write operations in the message store since node start.", msg_store_write_count}, 124 | {2, queue_index_journal_write_count, counter, "Write operations in the queue index journal since node start.", queue_index_journal_write_count}, 125 | {2, queue_index_write_count, counter, "Queue index write operations since node start.", queue_index_write_count}, 126 | {2, queue_index_read_count, counter, "Queue index read operations since node start.", queue_index_read_count}, 127 | {2, queue_io_file_handle_open_attempt_count, counter, "File descriptor open attempts.", io_file_handle_open_attempt_count}, 128 | {2, queue_io_file_handle_open_attempt_time, gauge, "Total time of file descriptor open attempts.", io_file_handle_open_attempt_time} 129 | ]}, 130 | 131 | {queue_coarse_metrics, [ 132 | {2, queue_messages_ready, gauge, "Number of messages ready to be delivered to clients."}, 133 | {3, queue_messages_unacknowledge, gauge, "Number of messages delivered to clients but not yet acknowledged."}, 134 | {4, queue_messages, gauge, "Sum of ready and unacknowledged messages (queue depth)."}, 135 | {5, queue_reductions, counter, "Count of reductions that take place on the queue process."} 136 | ]}, 137 | 138 | {queue_metrics, [ 139 | {2, queue_disk_reads, gauge, "Total number of times messages have been read from disk by this queue.", disk_reads}, 140 | {2, queue_disk_writes, gauge, "Total number of times messages have been written to disk by this queue.", disk_writes} 141 | ]} 142 | ]). 143 | 144 | -define(TOTALS, [ 145 | {connection_created, connections, gauge, "RabbitMQ Connections count."}, 146 | {channel_created, channels, gauge, "RabbitMQ Channels count."}, 147 | {consumer_created, consumers, gauge, "RabbitMQ Consumers count."}, 148 | {queue_metrics, queues, gauge, "RabbitMQ Queues count."} 149 | ]). 150 | 151 | %%==================================================================== 152 | %% Collector API 153 | %%==================================================================== 154 | 155 | register() -> 156 | register(default). 157 | 158 | register(Registry) -> 159 | ok = prometheus_registry:register_collector(Registry, ?MODULE). 160 | 161 | deregister_cleanup(_) -> ok. 162 | 163 | collect_mf(_Registry, Callback) -> 164 | [begin 165 | Data = ets:tab2list(Table), 166 | mf(Callback, Contents, Data) 167 | end || {Table, Contents} <- ?METRICS], 168 | [begin 169 | Size = ets:info(Table, size), 170 | mf_totals(Callback, Name, Type, Help, Size) 171 | end || {Table, Name, Type, Help} <- ?TOTALS], 172 | ok. 173 | 174 | mf(Callback, Contents, Data) -> 175 | [begin 176 | Fun = fun(D) -> element(Index, D) end, 177 | Callback(create_mf(?METRIC_NAME(Name), Help, catch_boolean(Type), ?MODULE, 178 | {Type, Fun, Data})) 179 | end || {Index, Name, Type, Help} <- Contents], 180 | [begin 181 | Fun = fun(D) -> proplists:get_value(Key, element(Index, D)) end, 182 | Callback(create_mf(?METRIC_NAME(Name), Help, catch_boolean(Type), ?MODULE, 183 | {Type, Fun, Data})) 184 | end || {Index, Name, Type, Help, Key} <- Contents]. 185 | 186 | mf_totals(Callback, Name, Type, Help, Size) -> 187 | Callback(create_mf(?METRIC_NAME(Name), Help, catch_boolean(Type), Size)). 188 | 189 | collect_metrics(_, {Type, Fun, Items}) -> 190 | [metric(Type, labels(Item), Fun(Item)) || Item <- Items]. 191 | 192 | labels(Item) -> 193 | label(element(1, Item)). 194 | 195 | label(#resource{virtual_host = VHost, kind = exchange, name = Name}) -> 196 | [{vhost, VHost}, {exchange, Name}]; 197 | label(#resource{virtual_host = VHost, kind = queue, name = Name}) -> 198 | [{vhost, VHost}, {queue, Name}]; 199 | label({P, {#resource{virtual_host = QVHost, kind = queue, name = QName}, 200 | #resource{virtual_host = EVHost, kind = exchange, name = EName}}}) when is_pid(P) -> 201 | %% channel_queue_exchange_metrics {channel_id, {queue_id, exchange_id}} 202 | [{channel, P}, {queue_vhost, QVHost}, {queue_name, QName}, 203 | {exchange_vhost, EVHost}, {exchange_name, EName}]; 204 | label({I1, I2}) -> 205 | label(I1) ++ label(I2); 206 | label(P) when is_pid(P) -> 207 | [{channel, P}]; 208 | label(A) when is_atom(A) -> 209 | [{node, A}]. 210 | 211 | metric(counter, Labels, Value) -> 212 | emit_counter_metric_if_defined(Labels, Value); 213 | metric(gauge, Labels, Value) -> 214 | emit_gauge_metric_if_defined(Labels, Value); 215 | metric(untyped, Labels, Value) -> 216 | untyped_metric(Labels, Value); 217 | metric(boolean, Labels, Value0) -> 218 | Value = case Value0 of 219 | true -> 1; 220 | false -> 0; 221 | undefined -> undefined 222 | end, 223 | untyped_metric(Labels, Value). 224 | 225 | 226 | %%==================================================================== 227 | %% Private Parts 228 | %%==================================================================== 229 | catch_boolean(boolean) -> 230 | untyped; 231 | catch_boolean(T) -> 232 | T. 233 | 234 | emit_counter_metric_if_defined(Labels, Value) -> 235 | case Value of 236 | undefined -> undefined; 237 | '' -> 238 | counter_metric(Labels, undefined); 239 | Value -> 240 | counter_metric(Labels, Value) 241 | end. 242 | 243 | emit_gauge_metric_if_defined(Labels, Value) -> 244 | case Value of 245 | undefined -> undefined; 246 | '' -> 247 | gauge_metric(Labels, undefined); 248 | Value -> 249 | gauge_metric(Labels, Value) 250 | end. 251 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_exchanges_collector.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_exchanges_collector). 2 | -export([register/0, 3 | register/1, 4 | deregister_cleanup/1, 5 | collect_mf/2, 6 | collect_metrics/2]). 7 | 8 | -import(prometheus_model_helpers, [create_mf/5, 9 | label_pairs/1, 10 | gauge_metrics/1, 11 | gauge_metric/1, 12 | gauge_metric/2, 13 | counter_metric/1, 14 | counter_metric/2]). 15 | 16 | -include("prometheus_rabbitmq_exporter.hrl"). 17 | 18 | -behaviour(prometheus_collector). 19 | 20 | -define(METRIC_NAME_PREFIX, "rabbitmq_exchange_"). 21 | 22 | -define(EXCHANGE_GAUGES, []). 23 | 24 | -define(EXCHANGE_COUNTERS, []). 25 | 26 | %%==================================================================== 27 | %% Collector API 28 | %%==================================================================== 29 | 30 | register() -> 31 | register(default). 32 | 33 | register(Registry) -> 34 | ok = prometheus_registry:register_collector(Registry, ?MODULE). 35 | 36 | deregister_cleanup(_) -> ok. 37 | 38 | collect_mf(_Registry, Callback) -> 39 | AllQueues = lists:merge([[Exchange || Exchange <- list_exchanges(VHost)] || [{name, VHost}] <- rabbit_vhost:info_all([name])]), 40 | [Callback(create_gauge(?METRIC_NAME(QueueKey), Help, {QueueKey, AllQueues})) || {QueueKey, Help} <- ?EXCHANGE_GAUGES], 41 | [Callback(create_counter(?METRIC_NAME(QueueKey), Help, {QueueKey, AllQueues})) || {QueueKey, Help} <- ?EXCHANGE_COUNTERS], 42 | 43 | case prometheus_rabbitmq_exporter_config:exchange_messages_stat() of 44 | [] -> 45 | ok; 46 | MessagesStat -> 47 | collect_messages_stat(Callback, AllQueues, MessagesStat) 48 | end, 49 | ok. 50 | 51 | %% messages_stat 52 | collect_metrics(_, {messages_stat, MSKey, AllQueues}) -> 53 | [counter_metric(labels(Exchange), prometheus_rabbitmq_message_stats:value(Exchange, MSKey)) 54 | || Exchange <- AllQueues]. 55 | 56 | %%==================================================================== 57 | %% Private Parts 58 | %%==================================================================== 59 | 60 | labels(Exchange) -> 61 | [{vhost, exchange_vhost(Exchange)}, 62 | {exchange, exchange_name(Exchange)}, 63 | {type, exchange_type(Exchange)}]. 64 | 65 | collect_messages_stat(Callback, AllQueues, MessagesStat) -> 66 | [Callback(create_counter(?METRIC_NAME(MetricName), Help, {messages_stat, MSKey, AllQueues})) 67 | || {MSKey, MetricName, Help} <- prometheus_rabbitmq_message_stats:metrics(), lists:member(MetricName, MessagesStat)]. 68 | 69 | %% emit_counter_metric_if_defined(Exchange, Value) -> 70 | %% case Value of 71 | %% undefined -> undefined; 72 | %% Value -> 73 | %% counter_metric(labels(Exchange), Value) 74 | %% end. 75 | 76 | %% emit_gauge_metric_if_defined(Exchange, Value) -> 77 | %% case Value of 78 | %% undefined -> undefined; 79 | %% Value -> 80 | %% gauge_metric(labels(Exchange), Value) 81 | %% end. 82 | 83 | exchange_vhost(Exchange) -> 84 | proplists:get_value(vhost, Exchange). 85 | 86 | exchange_name(Exchange) -> 87 | proplists:get_value(name, Exchange). 88 | 89 | exchange_type(Exchange) -> 90 | proplists:get_value(type, Exchange). 91 | 92 | %% exchange_value(Exchange, Key) -> 93 | %% proplists:get_value(Key, Exchange, undefined). 94 | 95 | list_exchanges(VHost) -> 96 | rabbit_mgmt_db:augment_exchanges( 97 | [rabbit_mgmt_format:exchange(X) || X <- rabbit_exchange:info_all(VHost)], 98 | ?NO_RANGE, basic). 99 | 100 | create_counter(Name, Help, Data) -> 101 | create_mf(Name, Help, counter, ?MODULE, Data). 102 | 103 | create_gauge(Name, Help, Data) -> 104 | create_mf(Name, Help, gauge, ?MODULE, Data). 105 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_message_stats.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_message_stats). 2 | 3 | -export([metrics/0, 4 | value/2]). 5 | 6 | -include("prometheus_rabbitmq_exporter.hrl"). 7 | 8 | %%==================================================================== 9 | %% Public API 10 | %%==================================================================== 11 | 12 | metrics() -> 13 | [{publish, messages_published_total, "Count of messages published."}, 14 | {publish_in, messages_published_in_total, "Count of messages published \"in\" to an exchange, i.e. not taking account of routing."}, 15 | {publish_out, messages_published_out_total, "Count of messages published \"out\" of an exchange, i.e. taking account of routing."}, 16 | {confirm, messages_confirmed_total, "Count of messages confirmed."}, 17 | {deliver, messages_delivered_total, "Count of messages delivered in acknowledgement mode to consumers."}, 18 | {deliver_no_ack, messages_delivered_no_ack_total, "Count of messages delivered in no-acknowledgement mode to consumers."}, 19 | {get, messages_get_total, "Count of messages delivered in acknowledgement mode in response to basic.get."}, 20 | {get_no_ack, messages_get_no_ack_total, "Count of messages delivered in no-acknowledgement mode in response to basic.get."}, 21 | {deliver_get, messages_deliver_get_total, "Sum of *messages_delivered_total, *messages_delivered_no_ack_total, *messages_get_total and *messages_get_no_ack_total."}, 22 | {redeliver, messages_redelivered_total, "Count of subset of delivered messages which had the redelivered flag set."}, 23 | {return_unroutable, messages_returned_total, "Count of messages returned to publisher as unroutable."}]. 24 | 25 | value(Entity, Name) -> 26 | case proplists:get_value(message_stats, Entity) of 27 | undefined -> 0; 28 | MessageStats -> 29 | proplists:get_value(Name, MessageStats, 0) 30 | end. 31 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_mnesia_tables_collector.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_mnesia_tables_collector). 2 | 3 | -export([register/0, 4 | register/1, 5 | deregister_cleanup/1, 6 | collect_mf/2, 7 | collect_metrics/2]). 8 | 9 | -include("prometheus_rabbitmq_exporter.hrl"). 10 | 11 | -import(prometheus_model_helpers, [create_mf/5, 12 | label_pairs/1, 13 | gauge_metrics/1, 14 | gauge_metric/1, 15 | gauge_metric/2, 16 | counter_metric/1, 17 | counter_metric/2, 18 | untyped_metric/1, 19 | untyped_metric/2]). 20 | 21 | -behaviour(prometheus_collector). 22 | 23 | -define(RABBIT_TABLES, [rabbit_durable_exchange, 24 | rabbit_durable_queue, 25 | rabbit_durable_route, 26 | rabbit_exchange, 27 | rabbit_exchange_serial, 28 | rabbit_listener, 29 | rabbit_queue, 30 | rabbit_reverse_route, 31 | rabbit_route, 32 | rabbit_runtime_parameters, 33 | rabbit_semi_durable_route, 34 | rabbit_topic_trie_binding, 35 | rabbit_topic_trie_edge, 36 | rabbit_topic_trie_node, 37 | rabbit_user, 38 | rabbit_user_permission, 39 | rabbit_vhost]). 40 | 41 | -define(METRIC_NAME_PREFIX, "rabbitmq_mnesia_table_"). 42 | 43 | %% metric {Key, Type, Help, &optional Fun} 44 | -define(METRICS, [{read_only, untyped, "Access mode of the table, 1 if table is read_only or 0 otherwise.", 45 | fun(_T, Info) -> 46 | case proplists:get_value(access_mode, Info) of 47 | read_only -> 1; 48 | _ -> 0 49 | end 50 | end}, 51 | {disc_copies, gauge, "Number of the nodes where a disc_copy of the table resides according to the schema."}, 52 | {disc_only_copies, gauge, "Number of the nodes where a disc_only_copy of the table resides according to the schema."}, 53 | {local_content, untyped, "If the table is configured to have locally unique content on each node, value is 1 or 0 otherwise.", 54 | fun(_T, Info) -> 55 | case proplists:get_value(local_content, Info) of 56 | true -> 1; 57 | _ -> 0 58 | end 59 | end}, 60 | {majority_required, untyped, "If 1, a majority of the table replicas must be available for an update to succeed.", 61 | fun(_T, Info) -> 62 | case proplists:get_value(majority, Info) of 63 | true -> 1; 64 | _ -> 0 65 | end 66 | end}, 67 | {master_nodes, gauge, "Number of the master nodes of a table."}, 68 | {memory_bytes, gauge, "The number of bytes allocated to the table on this node.", 69 | fun (_T, Info) -> 70 | proplists:get_value(memory, Info) * erlang:system_info(wordsize) 71 | end}, 72 | {ram_copies, gauge, "Number of the nodes where a ram_copy of the table resides according to the schema."}, 73 | {records_count, gauge, "Number of records inserted in the table.", 74 | fun (_T, Info) -> 75 | proplists:get_value(size, Info) 76 | end}, 77 | {disk_size_bytes, gauge, "Disk space occupied by the table (DCL + DCD).", 78 | fun (T, _) -> 79 | filelib:fold_files(mnesia:system_info(directory), atom_to_list(T), false, 80 | fun (Name, Acc) -> 81 | Acc + filelib:file_size(Name) 82 | end, 0) 83 | end}]). 84 | 85 | %%==================================================================== 86 | %% Collector API 87 | %%==================================================================== 88 | 89 | register() -> 90 | register(default). 91 | 92 | register(Registry) -> 93 | ok = prometheus_registry:register_collector(Registry, ?MODULE). 94 | 95 | deregister_cleanup(_) -> ok. 96 | 97 | collect_mf(_Registry, Callback) -> 98 | Tables = [{Table, mnesia:table_info(Table, all)} || Table <- ?RABBIT_TABLES], 99 | [mf(Callback, Metric, Tables) || Metric <- ?METRICS], 100 | ok. 101 | 102 | mf(Callback, Metric, Tables) -> 103 | {Name, Type, Help, Fun} = case Metric of 104 | {Key, Type1, Help1} -> 105 | {Key, Type1, Help1, fun (_Table, Info) -> 106 | list_to_count(proplists:get_value(Key, Info)) 107 | end}; 108 | {Key, Type1, Help1, Fun1} -> 109 | {Key, Type1, Help1, Fun1} 110 | end, 111 | Callback(create_mf(?METRIC_NAME(Name), Help, Type, ?MODULE, {Type, Fun, Tables})). 112 | 113 | 114 | collect_metrics(_, {Type, Fun, Tables}) -> 115 | [metric(Type, [{table, Table}], Fun(Table, Info)) || {Table, Info} <- Tables]. 116 | 117 | metric(gauge, Labels, Value) -> 118 | gauge_metric(Labels, Value); 119 | metric(untyped, Labels, Value) -> 120 | untyped_metric(Labels, Value). 121 | 122 | %%==================================================================== 123 | %% Private Parts 124 | %%==================================================================== 125 | 126 | list_to_count(Value) when is_list(Value) -> 127 | length(Value); 128 | list_to_count(Value) -> 129 | Value. 130 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_nodes_collector.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_nodes_collector). 2 | -export([register/0, 3 | register/1, 4 | deregister_cleanup/1, 5 | collect_mf/2, 6 | collect_metrics/2]). 7 | 8 | -import(prometheus_model_helpers, [create_mf/5, 9 | label_pairs/1, 10 | gauge_metrics/1, 11 | gauge_metric/1, 12 | gauge_metric/2, 13 | counter_metric/1, 14 | counter_metric/2, 15 | untyped_metric/1, 16 | untyped_metric/2, 17 | boolean_metric/2]). 18 | 19 | -include("prometheus_rabbitmq_exporter.hrl"). 20 | 21 | -define(METRIC_NAME_PREFIX, "rabbitmq_node_"). 22 | 23 | -define(METRICS, [ {partitions, gauge, "Partitions detected in the cluster.", 24 | fun(Node) -> 25 | length(proplists:get_value(partitions, Node, [])) 26 | end}, 27 | {fd_total, gauge, "File descriptors available."}, 28 | {sockets_total, gauge, "Sockets available."}, 29 | {mem_limit, gauge, "Memory usage high watermark."}, 30 | {mem_alarm, boolean, "Set to 1 if a memory alarm is in effect in the node."}, 31 | {disk_free_limit, gauge, "Free disk space low watermark."}, 32 | {disk_free_alarm, boolean, "Set to 1 if a memory alarm is in effect in the node."}, 33 | {proc_total, gauge, "Erlang processes limit."}, 34 | {uptime, counter, "Time in milliseconds since node start."}, 35 | {run_queue, gauge, "Runtime run queue."}, 36 | {processors, gauge, "Logical processors."}, 37 | {net_ticktime, gauge, "Network tick time between pairs of Erlang nodes."}, 38 | {mem_used, gauge, "Memory used in bytes"}, 39 | {fd_used, gauge, "File descriptors used."}, 40 | {sockets_used, gauge, "Sockets used."}, 41 | {proc_used, gauge, "Erlang processes used."}, 42 | {disk_free, gauge, "Disk free in bytes"}, 43 | {gc_num, counter, "GC runs."}, 44 | {gc_bytes_reclaimed, counter, "Bytes reclaimed by GC."}, 45 | {context_switches, counter, "Context switches since node start."}, 46 | {io_read_count, counter, "Read operations since node start."}, 47 | {io_read_bytes, counter, "Bytes read since node start."}, 48 | {io_read_avg_time, gauge, "Average time of read operations."}, 49 | {io_write_count, counter, "Write operations since node start."}, 50 | {io_write_bytes, counter, "Bytes written since node start."}, 51 | {io_write_avg_time, gauge, "Average time of write operations."}, 52 | {io_sync_count, counter, "Sync operations sync node start."}, 53 | {io_sync_avg_time, gauge, "Average time of sync operations."}, 54 | {io_seek_count, counter, "Seek operations since node start."}, 55 | {io_seek_avg_time, gauge, "Average time of seek operations."}, 56 | {io_reopen_count, counter, "Times files have been reopened by the file handle cache."}, 57 | {mnesia_ram_tx_count, counter, "Mnesia transactions in RAM since node start."}, 58 | {mnesia_disk_tx_count, counter, "Mnesia transactions in disk since node start."}, 59 | {msg_store_read_count, counter, "Read operations in the message store since node start."}, 60 | {msg_store_write_count, counter, "Write operations in the message store since node start."}, 61 | {queue_index_journal_write_count, counter, "Write operations in the queue index journal since node start."}, 62 | {queue_index_write_count, counter, "Queue index write operations since node start."}, 63 | {queue_index_read_count, counter, "Queue index read operations since node start."}, 64 | {io_file_handle_open_attempt_count, counter, "File descriptor open attempts."}, 65 | {io_file_handle_open_attempt_avg_time, gauge, "Average time of file descriptor open attempts."}, 66 | {metrics_gc_queue_length_channel_closed, gauge, "Message queue length of GC process for channel metrics", get_metrics_gc_queue_length(channel_closed)}, 67 | {metrics_gc_queue_length_connection_closed, gauge, "Message queue length of GC process for connection metrics", get_metrics_gc_queue_length(connection_closed)}, 68 | {metrics_gc_queue_length_consumer_deleted, gauge, "Message queue length of GC process for consumer metrics", get_metrics_gc_queue_length(consumer_deleted)}, 69 | {metrics_gc_queue_length_exchange_deleted, gauge, "Message queue length of GC process for exchange metrics", get_metrics_gc_queue_length(exchange_deleted)}, 70 | {metrics_gc_queue_length_node_node_deleted, gauge, "Message queue length of GC process for node-node metrics", get_metrics_gc_queue_length(node_deleted)}, 71 | {metrics_gc_queue_length_queue_deleted, gauge, "Message queue length of GC process for queue metrics", get_metrics_gc_queue_length(queue_deleted)}, 72 | {metrics_gc_queue_length_vhost_deleted, gauge, "Message queue length of GC process for vhost metrics", get_metrics_gc_queue_length(vhost_deleted)}, 73 | {metrics_gc_queue_length_channel_consumer_deleted, gauge, "Message queue length of GC process for consumer metrics", get_metrics_gc_queue_length(channel_consumer_deleted)} 74 | ]). 75 | 76 | -behaviour(prometheus_collector). 77 | 78 | %%==================================================================== 79 | %% Collector API 80 | %%==================================================================== 81 | 82 | register() -> 83 | register(default). 84 | 85 | register(Registry) -> 86 | ok = prometheus_registry:register_collector(Registry, ?MODULE). 87 | 88 | deregister_cleanup(_) -> ok. 89 | 90 | collect_mf(_Registry, Callback) -> 91 | Nodes = all_nodes_raw(), 92 | Callback(create_untyped(rabbitmq_node_up, "Node runnning status", Nodes)), 93 | case prometheus_rabbitmq_exporter_config:detailed_node_stat_enabled() of 94 | all -> 95 | collect_detailed_stats(Callback, Nodes); 96 | local -> 97 | [Node] = lists:filter(fun(N) -> 98 | node() == proplists:get_value(name, N) 99 | end, Nodes), 100 | collect_detailed_stats(Callback, [Node]); 101 | _ -> 102 | ok 103 | end. 104 | 105 | collect_metrics(rabbitmq_node_up, Nodes) -> 106 | [untyped_metric(labels(Node), node_running(Node)) || Node <- Nodes]; 107 | collect_metrics(_, {Type, Fun, Nodes}) -> 108 | [metric(Type, labels(Node), Fun(Node)) || Node <- Nodes]. 109 | 110 | metric(_, _, undefined) -> 111 | undefined; 112 | metric(counter, Labels, Value) -> 113 | counter_metric(Labels, Value); 114 | metric(gauge, Labels, Value) -> 115 | gauge_metric(Labels, Value); 116 | metric(untyped, Labels, Value) -> 117 | untyped_metric(Labels, Value); 118 | metric(boolean, Labels, Value) -> 119 | boolean_metric(Labels, Value). 120 | 121 | %%==================================================================== 122 | %% Private Parts 123 | %%==================================================================== 124 | 125 | %% just copied from rabbit_mgmt_wm_nodes 126 | %% [[{name,hare@home},{type,disc},{running,true}], 127 | %% [{name,rabbit@home},{type,disc},{running,false}]]` 128 | all_nodes_raw() -> 129 | S = rabbit_mnesia:status(), 130 | Nodes = proplists:get_value(nodes, S), 131 | Types = proplists:get_keys(Nodes), 132 | Running = proplists:get_value(running_nodes, S), 133 | [[{name, Node}, {type, Type}, {running, lists:member(Node, Running)}] || 134 | Type <- Types, Node <- proplists:get_value(Type, Nodes)]. 135 | 136 | labels(Node) -> 137 | [{name, node_name(Node)}, 138 | {type, node_type(Node)}]. 139 | 140 | node_name(Node) -> 141 | proplists:get_value(name, Node). 142 | 143 | node_type(Node) -> 144 | proplists:get_value(type, Node). 145 | 146 | node_running(Node) -> 147 | case proplists:get_value(running, Node) of 148 | true -> 1; 149 | _ -> 0 150 | end. 151 | 152 | create_untyped(Name, Help, Data) -> 153 | create_mf(Name, Help, untyped, ?MODULE, Data). 154 | 155 | collect_detailed_stats(Callback, Nodes) -> 156 | Augmented = rabbit_mgmt_db:augment_nodes(Nodes, ?NO_RANGE), 157 | [collect_detailed_stats(Callback, Augmented, Metric) || Metric <- ?METRICS], 158 | ok. 159 | 160 | collect_detailed_stats(Callback, Augmented, {Key, Type, Help}) -> 161 | Callback(create_mf(?METRIC_NAME(Key), Help, Type, ?MODULE, 162 | {Type, fun(Node) -> 163 | proplists:get_value(Key, Node, undefined) 164 | end, 165 | Augmented})); 166 | collect_detailed_stats(Callback, Augmented, {Key, Type, Help, Fun}) -> 167 | Callback(create_mf(?METRIC_NAME(Key), Help, Type, ?MODULE, 168 | {Type, Fun, Augmented})). 169 | 170 | get_metrics_gc_queue_length(Tag) -> 171 | fun(Node) -> 172 | proplists:get_value(Tag, 173 | proplists:get_value(metrics_gc_queue_length, Node, []), 174 | undefined) 175 | end. 176 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_overview_collector.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_overview_collector). 2 | -export([register/0, 3 | register/1, 4 | deregister_cleanup/1, 5 | collect_mf/2, 6 | collect_metrics/2]). 7 | 8 | -import(prometheus_model_helpers, [create_mf/4, 9 | create_mf/5, 10 | label_pairs/1, 11 | gauge_metrics/1, 12 | gauge_metric/1, 13 | gauge_metric/2, 14 | counter_metric/1, 15 | counter_metric/2, 16 | untyped_metric/1, 17 | untyped_metric/2]). 18 | 19 | -include("prometheus_rabbitmq_exporter.hrl"). 20 | -behaviour(prometheus_collector). 21 | 22 | -define(METRIC_NAME_PREFIX, "rabbitmq_"). 23 | 24 | -define(MESSAGE_STAT, [{queues_disk_reads, counter, "Total number of times messages have been read from disk by all queues.", 25 | fun (Stat) -> 26 | proplists:get_value(disk_reads, Stat) 27 | end}, 28 | {queues_disk_writes, counter, "Total number of times messages have been written to disk by all queues.", 29 | fun (Stat) -> 30 | proplists:get_value(disk_writes, Stat) 31 | end}]). 32 | -define(OBJECT_TOTALS, [{consumers, gauge, "RabbitMQ Consumers count"}, 33 | {queues, gauge, "RabbitMQ Proplist count"}, 34 | {exchanges, gauge, "RabbitMQ Exchanges count"}, 35 | {connections, gauge, "RabbitMQ Connections count"}, 36 | {channels, gauge, "RabbitMQ Channels count"}]). 37 | -define(QUEUE_TOTALS, [{messages_ready, gauge, "Messages ready for delivery"}, 38 | {messages_unacknowledged, gauge, 39 | "Delivered but unacknowledged messages"}]). 40 | 41 | -define(MEMORY_METRICS, [ 42 | %% Connections 43 | {connection_readers, 44 | "Processes responsible for connection parser " 45 | "and most of connection state. Most of their " 46 | "memory attributes to TCP buffers."}, 47 | {connection_writers, 48 | "Processes responsible for serialization of " 49 | "outgoing protocol frames and writing to " 50 | "client connections sockets."}, 51 | {connection_channels, 52 | "The more channels client connections use, " 53 | "the more memory with be used by this category."}, 54 | {connection_other, 55 | "Other memory related to client connections."}, 56 | 57 | %% Queues 58 | {queue_procs, 59 | "Queue masters, indices and messages kept in memory."}, 60 | {queue_slave_procs, 61 | "Queue mirrors, indices and messages kept in memory."}, 62 | 63 | %% Processes 64 | {plugins, 65 | "Plugins such as Shovel, Federation, or protocol " 66 | "implementations such as STOMP can accumulate " 67 | "messages in memory."}, 68 | {other_proc, 69 | "Queue masters, indices and messages kept in memory."}, 70 | 71 | %% Metrics 72 | {metrics, 73 | "Node-local metrics."}, 74 | {mgmt_db, 75 | "Management DB ETS tables + processes."}, 76 | 77 | %% ETS 78 | {mnesia, 79 | "Virtual hosts, users, permissions, queue metadata " 80 | "and state, exchanges, bindings, runtime parameters " 81 | "and so on."}, 82 | {other_ets, 83 | "Some plugins can use ETS tables to store their state."}, 84 | 85 | %% Messages (mostly, some binaries are not messages) 86 | {binary, 87 | "Runtime binary heap. Most of this section is usually " 88 | "message bodies and properties (metadata)."}, 89 | {msg_index, 90 | "Message index ETS + processes."}, 91 | 92 | %% Totals 93 | {erlang, 94 | "Runtime Used"}, 95 | {allocated, 96 | "Runtime Allocated"}, 97 | {rss, 98 | "Resident Set Size (RSS) reported by the OS"} 99 | ]). 100 | 101 | %%==================================================================== 102 | %% Collector API 103 | %%==================================================================== 104 | 105 | register() -> 106 | register(default). 107 | 108 | register(Registry) -> 109 | ok = prometheus_registry:register_collector(Registry, ?MODULE). 110 | 111 | deregister_cleanup(_) -> ok. 112 | 113 | collect_mf(_Registry, Callback) -> 114 | Overview = rabbit_mgmt_db:get_overview(all, ?NO_RANGE), 115 | MessageStat = proplists:get_value(message_stats, Overview), 116 | ObjectTotals = proplists:get_value(object_totals, Overview), 117 | QueueTotals = proplists:get_value(queue_totals, Overview), 118 | collect_messages_stat(Callback, MessageStat), 119 | [mf(Callback, Metric, MessageStat) || Metric <- ?MESSAGE_STAT], 120 | [mf(Callback, Metric, ObjectTotals) || Metric <- ?OBJECT_TOTALS], 121 | [mf(Callback, Metric, QueueTotals) || Metric <- ?QUEUE_TOTALS], 122 | case prometheus_rabbitmq_exporter_config:memory_stat_enabled() of 123 | true -> 124 | collect_rabbit_memory(Callback); 125 | _ -> 126 | ok 127 | end, 128 | case prometheus_rabbitmq_exporter_config:connections_total_enabled() of 129 | true -> 130 | collect_rabbit_connections(Callback); 131 | _ -> 132 | ok 133 | end, 134 | ok. 135 | 136 | collect_metrics(_, {messages_stat, MSKey, Stats}) -> 137 | counter_metric([], proplists:get_value(MSKey, Stats)); 138 | collect_metrics(_, {Type, Fun, Stats}) -> 139 | metric(Type, [], Fun(Stats)). 140 | 141 | collect_rabbit_memory(Callback) -> 142 | %% We flatten in order to have the totals under the same list. 143 | Memory0 = rabbit_vm:memory(), 144 | Memory = proplists:get_value(total, Memory0, []) ++ Memory0, 145 | [begin 146 | FullName = ?METRIC_NAME(["memory_", Name, "_bytes"]), 147 | Value = proplists:get_value(Name, Memory, undefined), 148 | Callback(create_mf(FullName, Help, gauge, Value)) 149 | end || {Name, Help} <- ?MEMORY_METRICS]. 150 | 151 | collect_rabbit_connections(Callback) -> 152 | Table = ets:new('$$connectinos_stat$$', [set]), 153 | try 154 | Connections = ets:select(connection_stats, [{{'$1', '$2'}, [], ['$2']}], 10), 155 | connections_loop(Connections, Table), 156 | Callback(create_mf(?METRIC_NAME(connections_total), "RabbitMQ connections count grouped by connection state.", 157 | gauge, ets:tab2list(Table))) 158 | after 159 | ets:delete(Table) 160 | end, 161 | ok. 162 | 163 | connections_loop('$end_of_table', _Table) -> 164 | ok; 165 | connections_loop({Connections, Continuation}, Table) -> 166 | [begin 167 | Labels = [{state, proplists:get_value(state, Connection)}], 168 | try 169 | ets:update_counter(Table, Labels, 1) 170 | catch error:badarg -> 171 | ets:insert(Table, {Labels, 1}) 172 | end 173 | end 174 | || Connection <- Connections], 175 | connections_loop(ets:select(Continuation), Table). 176 | 177 | mf(Callback, Metric, Proplist) -> 178 | {Name, Type, Help, Fun} = case Metric of 179 | {Key, Type1, Help1} -> 180 | {Key, Type1, Help1, fun (Proplist1) -> 181 | proplists:get_value(Key, Proplist1) 182 | end}; 183 | {Key, Type1, Help1, Fun1} -> 184 | {Key, Type1, Help1, Fun1} 185 | end, 186 | Callback(create_mf(?METRIC_NAME(Name), Help, catch_boolean(Type), ?MODULE, {Type, Fun, Proplist})). 187 | 188 | %% collect_metrics(rabbitmq_connections, _MFData) -> 189 | %% AllConnections = created_events(connection_stats), 190 | %% AllVHosts = rabbit_vhost:info_all([name]), 191 | %% [gauge_metric([{vhost, VHost}], length(filter_by_vhost(VHost, AllConnections))) || [{name, VHost}] <- AllVHosts]; 192 | %% collect_metrics(rabbitmq_channels, _MFData) -> 193 | %% AllChannels = created_events(channel_stats), 194 | %% AllVHosts = rabbit_vhost:info_all([name]), 195 | %% [gauge_metric([{vhost, VHost}], length(filter_by_vhost(VHost, AllChannels))) || [{name, VHost}] <- AllVHosts]; 196 | %% collect_metrics(rabbitmq_queues, _MFData) -> 197 | %% AllVHosts = rabbit_vhost:info_all([name]), 198 | %% [gauge_metric([{vhost, VHost}], length(rabbit_amqqueue:list(VHost))) || [{name, VHost}] <- AllVHosts]; 199 | %% collect_metrics(rabbitmq_exchanges, _MFData) -> 200 | %% AllVHosts = rabbit_vhost:info_all([name]), 201 | %% [gauge_metric([{vhost, VHost}], length(rabbit_exchange:list(VHost))) || [{name, VHost}] <- AllVHosts]; 202 | %% collect_metrics(rabbitmq_consumers, _MFData) -> 203 | %% gauge_metric([], ets:info(consumers_by_queue, size)). 204 | 205 | %%==================================================================== 206 | %% Private Parts 207 | %%==================================================================== 208 | 209 | collect_messages_stat(Callback, Stats) -> 210 | [Callback(create_counter(?METRIC_NAME(MetricName), Help, {messages_stat, MSKey, Stats})) 211 | || {MSKey, MetricName, Help} <- prometheus_rabbitmq_message_stats:metrics()]. 212 | 213 | 214 | %% filter_by_vhost(VHost, Channels) -> 215 | %% [I || I <- Channels, rabbit_misc:pget(vhost, I) =:= VHost]. 216 | 217 | %% %% created_events(Type) -> 218 | %% %% ets:select(Type, [{{{'_', '$1'}, '$2', '_'}, [{'==', 'create', '$1'}], 219 | %% %% ['$2']}]). 220 | 221 | %% created_events(connection_stats) -> 222 | %% rabbit_mgmt_db:get_all_connections(?NO_RANGE); 223 | %% created_events(channel_stats) -> 224 | %% rabbit_mgmt_db:get_all_channels(?NO_RANGE). 225 | 226 | %% create_gauge(Name, Help, Data) -> 227 | %% create_mf(Name, Help, gauge, ?MODULE, Data). 228 | 229 | create_counter(Name, Help, Data) -> 230 | create_mf(Name, Help, counter, ?MODULE, Data). 231 | 232 | metric(counter, Labels, Value) -> 233 | emit_counter_metric_if_defined(Labels, Value); 234 | metric(gauge, Labels, Value) -> 235 | emit_gauge_metric_if_defined(Labels, Value); 236 | metric(untyped, Labels, Value) -> 237 | untyped_metric(Labels, Value); 238 | metric(boolean, Labels, Value0) -> 239 | Value = case Value0 of 240 | true -> 1; 241 | false -> 0; 242 | undefined -> undefined 243 | end, 244 | untyped_metric(Labels, Value). 245 | 246 | catch_boolean(boolean) -> 247 | untyped; 248 | catch_boolean(T) -> 249 | T. 250 | 251 | emit_counter_metric_if_defined(Labels, Value) -> 252 | case Value of 253 | undefined -> undefined; 254 | '' -> 255 | counter_metric(Labels, undefined); 256 | Value -> 257 | counter_metric(Labels, Value) 258 | end. 259 | 260 | emit_gauge_metric_if_defined(Labels, Value) -> 261 | case Value of 262 | undefined -> undefined; 263 | '' -> 264 | gauge_metric(Labels, undefined); 265 | Value -> 266 | gauge_metric(Labels, Value) 267 | end. 268 | -------------------------------------------------------------------------------- /src/collectors/prometheus_rabbitmq_queues_collector.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_queues_collector). 2 | -export([register/0, 3 | register/1, 4 | deregister_cleanup/1, 5 | collect_mf/2, 6 | collect_metrics/2]). 7 | 8 | -import(prometheus_model_helpers, [create_mf/5, 9 | label_pairs/1, 10 | gauge_metrics/1, 11 | gauge_metric/1, 12 | gauge_metric/2, 13 | counter_metric/1, 14 | counter_metric/2, 15 | untyped_metric/1, 16 | untyped_metric/2]). 17 | 18 | -include("prometheus_rabbitmq_exporter.hrl"). 19 | -behaviour(prometheus_collector). 20 | 21 | 22 | -define(METRIC_NAME_PREFIX, "rabbitmq_queue_"). 23 | 24 | -define(METRICS, [{durable, boolean, "Whether or not the queue survives server restarts."}, 25 | {auto_delete, boolean, "Whether the queue will be deleted automatically when no longer used."}, 26 | {exclusive, boolean, "True if queue is exclusive (i.e. has owner_pid), false otherwise."}, 27 | {messages_ready, gauge, "Number of messages ready to be delivered to clients."}, 28 | {messages_unacknowledged, gauge, "Number of messages delivered to clients but not yet acknowledged."}, 29 | {messages, gauge, "Sum of ready and unacknowledged messages (queue depth)."}, 30 | {messages_ready_ram, gauge, "Number of messages from messages_ready which are resident in ram."}, 31 | {messages_unacknowledged_ram, gauge, "Number of messages from messages_unacknowledged which are resident in ram."}, 32 | {messages_ram, gauge, "Total number of messages which are resident in ram."}, 33 | {messages_persistent, gauge, "Total number of persistent messages in the queue (will always be 0 for transient queues)."}, 34 | {message_bytes, gauge, "Sum of the size of all message bodies in the queue. This does not include the message properties (including headers) or any overhead."}, 35 | {message_bytes_ready, gauge, "Like message_bytes but counting only those messages ready to be delivered to clients."}, 36 | {message_bytes_unacknowledged, gauge, "Like message_bytes but counting only those messages delivered to clients but not yet acknowledged."}, 37 | {message_bytes_ram, gauge, "Like message_bytes but counting only those messages which are in RAM."}, 38 | {message_bytes_persistent, gauge, "Like message_bytes but counting only those messages which are persistent."}, 39 | {head_message_timestamp, gauge, "The timestamp property of the first message in the queue, if present. Timestamps of messages only appear when they are in the paged-in state."}, 40 | {disk_reads, counter, "Total number of times messages have been read from disk by this queue since it started."}, 41 | {disk_writes, counter, "Total number of times messages have been written to disk by this queue since it started."}, 42 | {disk_size_bytes, gauge, "Disk space occupied by the queue.", 43 | fun (Queue) -> 44 | queue_dir_size(Queue) 45 | end}, 46 | {consumers, gauge, "Number of consumers."}, 47 | {consumer_utilisation, gauge, "Fraction of the time (between 0.0 and 1.0) that the queue is able to immediately deliver messages to consumers. This can be less than 1.0 if consumers are limited by network congestion or prefetch count."}, 48 | {memory, gauge, "Bytes of memory consumed by the Erlang process associated with the queue, including stack, heap and internal structures."}, 49 | {state, gauge, "The state of the queue. NaN if queue is located on cluster nodes that are currently down. " 50 | "0 if queue is running normally. MsgCount if queue is synchronizing.", 51 | fun(Queue) -> 52 | case queue_value(Queue, state) of 53 | running -> 0; 54 | undefined -> undefined; 55 | down -> undefined; 56 | {syncing, MsgCount} -> MsgCount 57 | end 58 | end} 59 | ]). 60 | 61 | %%==================================================================== 62 | %% Collector API 63 | %%==================================================================== 64 | 65 | register() -> 66 | register(default). 67 | 68 | register(Registry) -> 69 | ok = prometheus_registry:register_collector(Registry, ?MODULE). 70 | 71 | deregister_cleanup(_) -> ok. 72 | 73 | collect_mf(_Registry, Callback) -> 74 | AllQueues = lists:merge([[Queue || Queue <- list_queues(VHost)] || [{name, VHost}] <- rabbit_vhost:info_all([name])]), 75 | [mf(Callback, Metric, AllQueues) || Metric <- ?METRICS], 76 | 77 | case prometheus_rabbitmq_exporter_config:queue_messages_stat() of 78 | [] -> 79 | ok; 80 | MessagesStat -> 81 | collect_messages_stat(Callback, AllQueues, MessagesStat) 82 | end, 83 | ok. 84 | 85 | mf(Callback, Metric, Queues) -> 86 | {Name, Type, Help, Fun} = case Metric of 87 | {Key, Type1, Help1} -> 88 | {Key, Type1, Help1, fun (Queue) -> 89 | list_to_count(queue_value(Queue, Key)) 90 | end}; 91 | {Key, Type1, Help1, Fun1} -> 92 | {Key, Type1, Help1, Fun1} 93 | end, 94 | Callback(create_mf(?METRIC_NAME(Name), Help, catch_boolean(Type), ?MODULE, {Type, Fun, Queues})). 95 | 96 | 97 | %% messages_stat 98 | collect_metrics(_, {messages_stat, MSKey, AllQueues}) -> 99 | [counter_metric(labels(Queue), prometheus_rabbitmq_message_stats:value(Queue, MSKey)) 100 | || Queue <- AllQueues]; 101 | collect_metrics(_, {Type, Fun, Queues}) -> 102 | [metric(Type, labels(Queue), Fun(Queue)) || Queue <- Queues]. 103 | 104 | 105 | metric(counter, Labels, Value) -> 106 | emit_counter_metric_if_defined(Labels, Value); 107 | metric(gauge, Labels, Value) -> 108 | emit_gauge_metric_if_defined(Labels, Value); 109 | metric(untyped, Labels, Value) -> 110 | untyped_metric(Labels, Value); 111 | metric(boolean, Labels, Value0) -> 112 | Value = case Value0 of 113 | true -> 1; 114 | false -> 0; 115 | undefined -> undefined 116 | end, 117 | untyped_metric(Labels, Value). 118 | 119 | 120 | %%==================================================================== 121 | %% Private Parts 122 | %%==================================================================== 123 | 124 | labels(Queue) -> 125 | %% exclusive_consumer_tag should not be used as a label. Prometheus documentation 126 | %% states that labels should not be used to store dimensions with high cardinality, 127 | %% as every unique combination of key-value label pairs represents a new time 128 | %% series, which can dramatically increase the amount of data stored. 129 | %% As such, from the arguments only x-overflow, x-queue-mode and x-queue-type 130 | %% should be represented as arguments. 131 | add_if_not_empty( 132 | {queue_mode, queue_argument(<<"x-queue-mode">>, Queue)}, 133 | add_if_not_empty( 134 | {type, queue_argument(<<"x-queue-type">>, Queue, <<"classic">>)}, 135 | add_if_not_empty( 136 | {overflow, queue_argument(<<"x-overflow">>, Queue)}, 137 | add_if_not_empty({policy, queue_policy(Queue)}, 138 | [{vhost, queue_vhost(Queue)}, 139 | {queue, queue_name(Queue)}])))). 140 | 141 | add_if_not_empty({_, ''}, Acc) -> 142 | Acc; 143 | add_if_not_empty(Tuple, Acc) -> 144 | [Tuple | Acc]. 145 | 146 | catch_boolean(boolean) -> 147 | untyped; 148 | catch_boolean(T) -> 149 | T. 150 | 151 | collect_messages_stat(Callback, AllQueues, MessagesStat) -> 152 | [Callback(create_counter(?METRIC_NAME(MetricName), Help, {messages_stat, MSKey, AllQueues})) 153 | || {MSKey, MetricName, Help} <- prometheus_rabbitmq_message_stats:metrics(), lists:member(MetricName, MessagesStat)]. 154 | 155 | emit_counter_metric_if_defined(Labels, Value) -> 156 | case Value of 157 | undefined -> undefined; 158 | '' -> 159 | counter_metric(Labels, undefined); 160 | Value -> 161 | counter_metric(Labels, Value) 162 | end. 163 | 164 | emit_gauge_metric_if_defined(Labels, Value) -> 165 | case Value of 166 | undefined -> undefined; 167 | '' -> 168 | gauge_metric(Labels, undefined); 169 | Value -> 170 | gauge_metric(Labels, Value) 171 | end. 172 | 173 | queue_vhost(Queue) -> 174 | proplists:get_value(vhost, Queue). 175 | 176 | queue_name(Queue) -> 177 | proplists:get_value(name, Queue). 178 | 179 | queue_policy(Queue) -> 180 | proplists:get_value(policy, Queue). 181 | 182 | queue_argument(Arg, Queue) -> 183 | queue_argument(Arg, Queue, ''). 184 | 185 | queue_argument(Arg, Queue, Default) -> 186 | maps:get(Arg, proplists:get_value(arguments, Queue), Default). 187 | 188 | queue_dir_size(Queue) -> 189 | QueueDirName = queue_dir_name(Queue), 190 | FullPath = [mnesia:system_info(directory), "/queues/", QueueDirName], 191 | dir_size(FullPath). 192 | 193 | queue_dir_name(Queue) -> 194 | VHost = queue_vhost(Queue), 195 | Name = queue_name(Queue), 196 | %% http://hustoknow.blogspot.ru/2014/03/how-rabbitmq-computes-name-of-its.html 197 | <> = erlang:md5(term_to_binary(rabbit_misc:r(VHost, queue, Name))), 198 | rabbit_misc:format("~.36B", [Num]). 199 | 200 | queue_value(Queue, Key) -> 201 | proplists:get_value(Key, Queue, undefined). 202 | 203 | vhost_queues(VHost) -> 204 | [rabbit_mgmt_format:queue(Q) || Q <- rabbit_amqqueue:list(VHost)]. 205 | 206 | list_queues(VHost) -> 207 | Queues = rabbit_mgmt_db:augment_queues(vhost_queues(VHost), 208 | ?NO_RANGE, basic), 209 | Queues. 210 | 211 | list_to_count(Value) when is_list(Value) -> 212 | length(Value); 213 | list_to_count(Value) -> 214 | Value. 215 | 216 | dir_size(Dir) -> 217 | filelib:fold_files(Dir, "", true, 218 | fun (Name, Acc) -> 219 | Acc + filelib:file_size(Name) 220 | end, 0). 221 | 222 | create_counter(Name, Help, Data) -> 223 | create_mf(Name, Help, counter, ?MODULE, Data). 224 | -------------------------------------------------------------------------------- /src/prometheus_rabbitmq_exporter.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_exporter). 2 | 3 | -behaviour(rabbit_mgmt_extension). 4 | 5 | -export([dispatcher/0, web_ui/0]). 6 | 7 | dispatcher() -> 8 | {ok, _} = application:ensure_all_started(prometheus), 9 | maybe_register_collectors(), 10 | Path = prometheus_rabbitmq_exporter_config:path(), 11 | 12 | prometheus_http_impl:setup(), 13 | 14 | [{Path ++ "/[:registry]", prometheus_rabbitmq_exporter_handler, []}]. 15 | 16 | web_ui() -> []. 17 | 18 | maybe_register_collectors() -> 19 | RabbitCollectors = application:get_env(prometheus, collectors, 20 | [ 21 | prometheus_rabbitmq_exchanges_collector, 22 | prometheus_rabbitmq_mnesia_tables_collector, 23 | prometheus_rabbitmq_nodes_collector, 24 | prometheus_rabbitmq_overview_collector, 25 | prometheus_rabbitmq_queues_collector 26 | ]), 27 | 28 | prometheus_registry:register_collectors(RabbitCollectors). 29 | -------------------------------------------------------------------------------- /src/prometheus_rabbitmq_exporter_config.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_exporter_config). 2 | 3 | -export([path/0, 4 | use_mgmt_auth/0, 5 | queue_messages_stat/0, 6 | exchange_messages_stat/0, 7 | memory_stat_enabled/0, 8 | connections_total_enabled/0, 9 | detailed_node_stat_enabled/0]). 10 | 11 | -define(DEFAULT_PATH, "/metrics"). 12 | -define(DEFAULT_USE_MGMT_AUTH, false). 13 | -define(DEFAULT_QUEUE_MESSAGES_STAT, [messages_published_total, 14 | messages_confirmed_total, 15 | messages_delivered_total, 16 | messages_delivered_no_ack_total, 17 | messages_get_total, 18 | messages_get_no_ack_total, 19 | messages_deliver_get_total, 20 | messages_redelivered_total, 21 | messages_returned_total]). 22 | -define(DEFAULT_EXCHANGE_MESSAGES_STAT, [messages_published_total, 23 | messages_published_in_total, 24 | messages_published_out_total, 25 | messages_confirmed_total, 26 | messages_delivered_total, 27 | messages_delivered_no_ack_total, 28 | messages_get_total, 29 | messages_get_no_ack_total, 30 | messages_deliver_get_total, 31 | messages_redelivered_total, 32 | messages_returned_total]). 33 | -define(DEFAULT_MEMORY_STAT_ENABLED, false). 34 | -define(DEFAULT_CONNECTIONS_TOTAL_ENABLED, false). 35 | -define(DEFAULT_DETAILED_NODE_STAT_ENABLED, none). 36 | 37 | config() -> 38 | application:get_env(prometheus, rabbitmq_exporter, []). 39 | 40 | path() -> 41 | Config = config(), 42 | proplists:get_value(path, Config, ?DEFAULT_PATH). 43 | 44 | use_mgmt_auth() -> 45 | Config = config(), 46 | proplists:get_value(use_mgmt_auth, Config, ?DEFAULT_USE_MGMT_AUTH). 47 | 48 | queue_messages_stat() -> 49 | Config = config(), 50 | proplists:get_value(queue_messages_stat, Config, ?DEFAULT_QUEUE_MESSAGES_STAT). 51 | 52 | exchange_messages_stat() -> 53 | Config = config(), 54 | proplists:get_value(exchange_messages_stat, Config, ?DEFAULT_EXCHANGE_MESSAGES_STAT). 55 | 56 | memory_stat_enabled() -> 57 | Config = config(), 58 | proplists:get_value(memory_stat_enabled, Config, ?DEFAULT_MEMORY_STAT_ENABLED). 59 | 60 | connections_total_enabled() -> 61 | Config = config(), 62 | proplists:get_value(connections_total_enabled, Config, ?DEFAULT_CONNECTIONS_TOTAL_ENABLED). 63 | 64 | detailed_node_stat_enabled() -> 65 | Config = config(), 66 | proplists:get_value(detailed_node_stat_enabled, Config, ?DEFAULT_DETAILED_NODE_STAT_ENABLED). 67 | -------------------------------------------------------------------------------- /src/prometheus_rabbitmq_exporter_handler.erl: -------------------------------------------------------------------------------- 1 | -module(prometheus_rabbitmq_exporter_handler). 2 | 3 | -export([init/2]). 4 | -export([generate_response/2, content_types_provided/2, is_authorized/2]). 5 | 6 | -include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). 7 | 8 | %% =================================================================== 9 | %% Cowboy Handler Callbacks 10 | %% =================================================================== 11 | 12 | init(Req, _State) -> 13 | {cowboy_rest, Req, #context{}}. 14 | 15 | content_types_provided(ReqData, Context) -> 16 | {[ 17 | {<<"*/*">>, generate_response} 18 | ], ReqData, Context}. 19 | 20 | is_authorized(ReqData, Context) -> 21 | case prometheus_rabbitmq_exporter_config:use_mgmt_auth() of 22 | false -> 23 | {true, ReqData, Context}; 24 | true -> 25 | rabbit_mgmt_util:is_authorized(ReqData, Context) 26 | end. 27 | 28 | %% =================================================================== 29 | %% Private functions 30 | %% =================================================================== 31 | 32 | generate_response(ReqData, Context) -> 33 | {ok, Response, undefined} = prometheus_cowboy2_handler:init(ReqData, Context), 34 | {stop, Response, Context}. 35 | --------------------------------------------------------------------------------