├── .env
├── .gitignore
├── README.md
├── assets
├── banner.png
├── frame-install.png
├── lattice-relay.png
└── start-direct.gif
├── connect
├── .direct.env
├── .dockerignore
├── .env
├── .gitignore
├── README.md
├── container
│ ├── Dockerfile
│ ├── dockerBuild.sh
│ └── dockerStart.sh
├── package-lock.json
├── package.json
├── src
│ ├── clients
│ │ ├── createClient.ts
│ │ └── createSigner.ts
│ ├── core
│ │ ├── createApp.ts
│ │ ├── index.ts
│ │ ├── spawnWorker.ts
│ │ ├── startServer.ts
│ │ └── utils.ts
│ ├── direct.ts
│ ├── index.ts
│ └── services
│ │ ├── useProvision.ts
│ │ └── useSigning.ts
└── tsconfig.json
├── mqtt-broker
├── .env
├── README.md
├── config
│ ├── .gitignore
│ ├── enabled_plugins
│ └── rabbitmq.conf
├── container
│ ├── Dockerfile
│ ├── dockerBuild.sh
│ └── dockerStart.sh
└── metrics
│ ├── .gitignore
│ ├── grafana
│ ├── dashboards.yml
│ ├── dashboards
│ │ ├── Erlang-Distribution.json
│ │ ├── Erlang-Distributions-Compare.json
│ │ ├── Erlang-Memory-Allocators.json
│ │ ├── RabbitMQ-Overview.json
│ │ ├── RabbitMQ-PerfTest.json
│ │ ├── RabbitMQ-Quorum-Queues-Raft.json
│ │ ├── RabbitMQ-Stream.json
│ │ ├── inet_tcp_metrics.json
│ │ └── rabbitmq-exporter_vs_rabbitmq-prometheus.json
│ └── datasources.yml
│ └── prometheus
│ ├── prometheus.example.yml
│ └── prometheus.yml
└── pulumi
├── .gitignore
├── Pulumi.dev.yaml
├── Pulumi.prod.yaml
├── Pulumi.yaml
├── README.md
├── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json
/.env:
--------------------------------------------------------------------------------
1 | # DCKR
2 | COMPOSE_PROJECT_NAME=lattice-connect
3 |
4 | # MQTT
5 | ERLANG_COOKIE='erlang-cookie'
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | docker-compose.y*ml
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 👋 Introduction
4 |
5 | By default, [Lattice1](https://gridplus.io/lattice) devices are configured to use GridPlus' cloud services to connect apps and route messages. However, **Lattice Connect V2** allows you to disconnect your Lattice1 from the GridPlus cloud and run the services locally instead. Note that your Lattice1 still needs to be on your WiFi network in order to route local messages, as Lattice Connect V2 runs on your computer and thus must connect to your Lattice1 over LAN.
6 |
7 | This open-source project provides [Lattice1](https://gridplus.io/lattice) owners a HTTP server which they manage themselves, and that will proxy all messages between the device over their own local network, as an alternative to relying on the vendor-provided routing service.
8 |
9 | By default, communication between apps and a Lattice1 route through cloud infrastructure provided by [GridPlus](https://gridplus.io). Any messages sent to, and from, your device will always be encrypted and remain secure; however, we believe Lattice1 owners should be able to manage this service themselves, if they so choose.
10 |
11 | ### 🔗 Related Links
12 | - [📢 Discord](https://twitter.com/gridplus)
13 | - [🐤 Twitter](https://discord.gg/Bt5fVDTJb9)
14 | - [📚 Knowledge Base](https://docs.gridplus.io)
15 |
16 |
17 | ## 🤔 Why use Lattice Connect?
18 |
19 | Running _Lattice Connect_ yourself provides several advantages:
20 |
21 | - Doesn't requires running an external MQTT broker (compared to `v1`);
22 | - Offers the fastest message routing possible for a Lattice1;
23 | - Provides the highest amount of privacy available while using a Lattice1
24 | - Zero configuration changes required (i.e., no SSH'ing necessary);
25 | - Setup takes less than 5 minutes!
26 |
27 | ## 🚨 What about `v1`?
28 | This project replaces the original _[lattice-connect](https://github.com/GridPlus/lattice-connect)_, which is now archived.
29 |
30 | At the time of release, the previous software should continue working as-is; however, GridPlus will no longer offer technical support, or otherwise provide maintenance for the prior version. Thus, breaking changes that may occur as we continue improving our customers' user experience should be expected, and switching to `v2` as soon as possible is highly recommended.
31 |
32 | # ⌛️ Setup Guide
33 |
34 | ##### Estimated Time (TOTAL): 5–10 minutes
35 |
36 | It's possible to run the server:
37 |
38 | - directly on a host system using `node` v14+; or,
39 | - through a `Docker` container.
40 |
41 | > _**NOTE:** The instructions for each are nearly identical. This guide describes `node`;
42 | scripts are provided in `connect/container` that support the `Docker` method._
43 |
44 | ### System Requirements
45 |
46 | Besides the runtime requirements, the system resources for the proxy server are trivial. It will work on any system which can run Node v14+, or Docker.
47 |
48 | The server has been tested on:
49 |
50 | - macOS v10.12;
51 | - Ubuntu 18.04;
52 | - Windows 10
53 |
54 | ## ⚙️ Configuring
55 |
56 | #### 1️⃣ Get the source code
57 | Clone the repo to the server or computer you plan to run it on:
58 |
59 | ```sh
60 | # Clone the repo:
61 | $ git clone https://github.com/GridPlus/lattice-connect-v2.git
62 |
63 | # Change your working director to the 'connect' folder:
64 | $ cd lattice-connect-v2/connect
65 | ```
66 |
67 | #### 2️⃣ Configure the environment
68 | Edit `connect/.direct.env` and set your device's hostname:
69 |
70 | ```sh
71 | # - Open the '.direct.env' file; then,
72 | # - Replace this with your device's hostname
73 | ADMIN_CLIENT_HOST=http://GridPlus-xxxxxxxxxxx.local
74 | ```
75 | ##### 🔍 Checking your device's hostname
76 | On Firmware v16, and above, the device's hostname is shown with the following steps:
77 |
78 | 1. **Unlock** the device; then,
79 | 2. Tap **System Preferences**; then,
80 | 3. Tap **Device Info**; then,
81 | 4. See `SSH Host`.
82 |
83 | ## 🌐 Start Proxy: Using Node
84 | From inside `connect` folder, run:
85 |
86 | ```sh
87 | # Install dependencies
88 | $ npm i
89 |
90 | # Start the proxy
91 | $ npm run start:direct
92 |
93 | # Look for confirmation...
94 | ... [!] MQTT client connected
95 | ```
96 |
97 |
98 |
99 | ## 🐳 Start Proxy: Using Docker
100 | From inside the `connect/container` folder, run:
101 |
102 | ```sh
103 | # Script to build the container
104 | $ ./dockerBuild.sh
105 |
106 | # Script to start the proxy server
107 | $ ./dockerStart.sh
108 | ```
109 |
110 | ## 🔬 Troubleshooting
111 |
112 | If the server fails to connect:
113 |
114 | - Double-check your `ADMIN_CLIENT_HOST` value;
115 | - Ensure `.local` is included as a suffix on the host;
116 | - `ping` your device, being certain your device is reachable before trying to run this software;
117 | - use the Lattice1 IP address as an alternative to hostname (see below);
118 | - be sure your network's firewall isn't blocking port 1883.
119 |
120 | ### Using IP Address
121 | For many of the most common network setups, the server should have no trouble finding, and connecting, to the Lattice1. However, if it's unable to connect—and you're certain you've inputted the `.local` correct—use the device's IP address instead:
122 |
123 | ```sh
124 | # - Open the '.direct.env' file; then,
125 | # - Replace this with your device's IP address.
126 | # - DON'T include '.local'; it's standard IPv4 format.
127 | ADMIN_CLIENT_HOST=http://
128 | ```
129 |
130 | > _**NOTE:** The IP address of the device can be determined from your network's main router or gateway appliance. Details on how to do this vary depending on your specific router or gateway appliance, and is outside the scope of this document._
131 |
132 | # ✌️ Disconnecting Entirely from the GridPlus Cloud
133 |
134 | If you are using Lattice Connect V2 to route messages, your device will not use the GridPlus cloud, but will still be connected to it. If you would like to remove **all** connections to the GridPlus cloud, you will also need to erase some system settings and configure a custom device ID. Note that if you choose to do this, you will need to re-connect with all of your apps using the new device ID.
135 |
136 | 1. SSH into the Lattice (you can find credentials in `System Preferences -> Device Info` -- format the request like so: `ssh root@.local`)
137 | 2. Stop current processes: `service gpd stop && service mosquitto stop`
138 | 3. Update credentials†: `uci set gridplus.provisionLatticeAPIURL="" && uci set gridplus.deviceID="ABCDEF" && uci set gridplus.remote_mqtt_address="foo" && uci commit`
139 | 4. Restart processes: `service gpd restart && service mosquitto restart`
140 |
141 | Give it ~30 seconds and view the `Device ID` on your Lattice menu. You should see the device ID you just configured -- this new device ID indicates that you have disconnected your Lattice from GridPlus cloud services.
142 |
143 | † Note that you can set whatever `deviceID` credential you want, but you should probably use six characters to avoid any edge cases. Also note that `remote_mqtt_address` is not used when Lattice Connect V2 is routing messages, but it can't be empty or else `mosquitto` will fail to start.
144 |
145 | # 🔗 Connecting to Third Party Apps
146 |
147 | Now that Lattice Connect V2 is running on your computer, you will need to update your connections to third party apps, which may involve removing the Permission on your Lattice1 device. This section covers the most common connections: [MetaMask](https://metamask.io) and [Frame](https://frame.sh).
148 |
149 | ## 🖼 MetaMask
150 |
151 | Download the [MetaMask](https://metamask.io) extension if you don't have it already.
152 |
153 | #### Set the Lattice Relay
154 |
155 | 1. Start by removing all **Lattice1** accounts from MetaMask if present.
156 |
157 |
158 | 3. Remove the MetaMask permission from your Lattice1 if present.
159 | 4. Log into the [Lattice Manager](https://lattice.gridplus.io) and remove any MetaMask entries from the **3rd Party Connections** list if present.
160 |
161 |
162 | 5. In the **Settings** tab input the `http://:8080` into the **Connection Endpoint** field.
163 |
164 | Replace `` with the host running _Lattice Connect_.
165 | When running _Lattice Connect_ on the same computer you are using MetaMask, use `localhost`, otherwise use `http://:8080` where `` is the IP of the machine running **Lattice Connect**.
166 |
167 |
168 |
169 | 6. Connect your Lattice to MetaMask as normal. Transaction requests will now be routed to your self-hosted endpoint.
170 |
171 |
172 | ## 🖼 Frame Wallet
173 |
174 |
175 |
176 | Download [Frame](https://frame.sh) wallet desktop app, and run the installer.
177 |
178 | #### Set the Lattice Relay
179 |
180 | From the _Settings_ panel (upper-right; slider icon):
181 |
182 | - Scroll down to the **Lattice Relay** option; then,
183 | - Click _Default_; switch to _Custom_; then,
184 | - Input the `http://:8080`
185 |
186 | Replace `RELAY_HOST` with the host running _Lattice Connect_.
187 | When running _Frame_ and _Lattice Connect_ on the same computer, use `localhost`:
188 |
189 |
190 |
191 | ## FAQ
192 |
193 | ### What do I need to do to migrate from `v1`?
194 | Nothing. If you've made changes from `SSH`, they will be ignored by `v2`.
195 |
196 | If you're adament about having factory settings, you may reset your router in the Lattice1 System Settings. Please be aware doing this will also reset your wireless routing settings, and will require reconnecting to your Wi-Fi network.
197 |
198 | ### How do I connect more than one Lattice1?
199 | Currently, the direct method supports a single Lattice1 at a time.
200 |
--------------------------------------------------------------------------------
/assets/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GridPlus/lattice-connect-v2/646115eb82ddc53f4554748fea37ef8a777162e8/assets/banner.png
--------------------------------------------------------------------------------
/assets/frame-install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GridPlus/lattice-connect-v2/646115eb82ddc53f4554748fea37ef8a777162e8/assets/frame-install.png
--------------------------------------------------------------------------------
/assets/lattice-relay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GridPlus/lattice-connect-v2/646115eb82ddc53f4554748fea37ef8a777162e8/assets/lattice-relay.png
--------------------------------------------------------------------------------
/assets/start-direct.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GridPlus/lattice-connect-v2/646115eb82ddc53f4554748fea37ef8a777162e8/assets/start-direct.gif
--------------------------------------------------------------------------------
/connect/.direct.env:
--------------------------------------------------------------------------------
1 | APP_WORKER_COUNT=1
2 |
3 | # - Replace this with your device's hostname
4 | # - Should be appear as: GridPlus-xxxxxxxxxxx.local
5 | ADMIN_CLIENT_HOST=http://GridPlus-xxxxxxxxxxx.local
6 |
7 | MQTT_HTTP_PORT=1883
8 | MQTT_SKIP_USER_CHECK=1
9 |
--------------------------------------------------------------------------------
/connect/.dockerignore:
--------------------------------------------------------------------------------
1 | .src/node_modules
2 | .dist
3 | .package-lock.json
--------------------------------------------------------------------------------
/connect/.env:
--------------------------------------------------------------------------------
1 | APP_SERVICE_PORT=8080
2 | APP_WORKER_COUNT=2
3 | MQTT_HTTP_PORT=8883
4 |
--------------------------------------------------------------------------------
/connect/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
--------------------------------------------------------------------------------
/connect/README.md:
--------------------------------------------------------------------------------
1 | # Environment Parameters
2 |
3 | > _Note: End-users should follow the instructions provided in the main folder's `README`._
4 |
5 | ### For Internal Use
6 |
7 | - ADMIN_CLIENT_HOST
8 | - ADMIN_CLIENT_PASS
9 | - ADMIN_CLIENT_USER
10 | - APP_SERVICE_PORT
11 | - APP_WORKER_COUNT
12 | - MQTT_HTTP_PORT
13 | - MQTT_SKIP_USER_CHECK
14 |
--------------------------------------------------------------------------------
/connect/container/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04 AS base
2 |
3 | RUN apt update && \
4 | apt install -y curl
5 |
6 | RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
7 | apt-get install -y nodejs
8 |
9 | FROM base AS builder
10 | WORKDIR /build/connect
11 | ADD src /build/connect/src
12 | ADD package.json /build/connect
13 | ADD tsconfig.json /build/connect
14 |
15 | WORKDIR /build/connect
16 | RUN npm i && npx tsc --build tsconfig.json && npm prune --production
17 | RUN rm -rf node_modules/typescript
18 |
19 | FROM node:16-alpine AS app
20 | COPY --from=builder /build/connect/dist /app/dist
21 | COPY --from=builder /build/connect/node_modules /app/node_modules
22 | CMD NODE_ENV=production node /app/dist/index.js
23 |
--------------------------------------------------------------------------------
/connect/container/dockerBuild.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | docker build \
4 | -f Dockerfile \
5 | ../ \
6 | -t lattice-connect:latest
7 |
--------------------------------------------------------------------------------
/connect/container/dockerStart.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | docker run \
4 | --rm -it \
5 | --init \
6 | -h lattice-connect \
7 | --env-file ../.env \
8 | --env-file ../.direct.env \
9 | -p 8080:8080 \
10 | --name "lattice-connect" \
11 | lattice-connect \
12 | node /app/dist/direct.js
--------------------------------------------------------------------------------
/connect/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "private": true,
4 | "version": "0.0.1",
5 | "scripts": {
6 | "start": "NODE_ENV=development nodemon ./src/index.ts",
7 | "start:mqtt": "DEBUG='mqttjs*' NODE_ENV=development nodemon ./src/index.ts",
8 | "start:direct": "nodemon ./src/direct.ts",
9 | "start:direct:mqtt": "DEBUG='mqttjs*' NODE_ENV=development nodemon ./src/direct.ts",
10 | "prod": "tsc --build tsconfig.json; NODE_ENV=production node ./dist/index.js"
11 | },
12 | "dependencies": {
13 | "async-mqtt": "^2.6.2",
14 | "bs58": "^5.0.0",
15 | "cors": "^2.8.5",
16 | "dotenv": "^16.0.1",
17 | "express": "^4.18.1",
18 | "express-pino-logger": "^7.0.0",
19 | "pino-http": "^8.1.1",
20 | "superagent": "^8.0.0"
21 | },
22 | "devDependencies": {
23 | "@types/cors": "^2.8.12",
24 | "@types/express": "^4.17.13",
25 | "@types/express-pino-logger": "^4.0.3",
26 | "@types/node": "^18.0.1",
27 | "@types/superagent": "^4.1.15",
28 | "nodemon": "^2.0.19",
29 | "ts-node": "^10.8.2",
30 | "typescript": "^4.7.4"
31 | },
32 | "nodemonConfig": {
33 | "execMap": {
34 | "ts": "node --require ts-node/register/transpile-only"
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/connect/src/clients/createClient.ts:
--------------------------------------------------------------------------------
1 | import rp from 'superagent';
2 | export interface IAdminConfig {
3 | url: URL,
4 | username: string,
5 | password: string
6 | }
7 |
8 | type APIArgs = {
9 | api: string;
10 | payload?: any;
11 | };
12 |
13 | type APIMethod = (
14 | {
15 | api,
16 | payload
17 | }: APIArgs) => rp.SuperAgentRequest;
18 |
19 | export interface IAdminClient {
20 | get: APIMethod,
21 | put: APIMethod
22 | }
23 |
24 | function _createClient({ url, username, password }: IAdminConfig): {
25 | client: IAdminClient
26 | } {
27 | //--------------------------------------------------
28 | // GET
29 | //--------------------------------------------------
30 | function get({
31 | api, payload
32 | }: {
33 | api: string;
34 | payload?: any;
35 | }) {
36 | console.log(`${url}api/${api}`)
37 | return rp
38 | .get(`${url}api/${api}`)
39 | .auth(username, password)
40 | .set('Content-Type', 'application/json')
41 | .send(payload)
42 | }
43 |
44 | //--------------------------------------------------
45 | // PUT
46 | //--------------------------------------------------
47 | function put({
48 | api, payload
49 | }: {
50 | api: string;
51 | payload?: any;
52 | }) {
53 | return rp
54 | .put(`${url}api/${api}`)
55 | .auth(username, password)
56 | .set('Content-Type', 'application/json')
57 | .send(payload);
58 | }
59 |
60 | return { client: { get, put } }
61 | }
62 |
63 | export function createClient({ url, username, password }: {
64 | url: URL | undefined,
65 | username: string | undefined,
66 | password: string | undefined
67 | }): Promise<{ client: IAdminClient }> {
68 | return new Promise((res, rej) => {
69 | if (!url) {
70 | rej(new Error(`Invalid Admin Config: HOST || ADDRESS (undefined)`))
71 | }
72 | if (!username) {
73 | rej(new Error(`Invalid Admin Config: USERNAME (undefined)`))
74 | }
75 | if (!password) {
76 | rej(new Error(`Invalid Admin Config: PASSWORD (undefined)`))
77 | }
78 |
79 | res(_createClient({
80 | url: url!,
81 | username: username!,
82 | password: password!
83 | }))
84 | })
85 | }
--------------------------------------------------------------------------------
/connect/src/clients/createSigner.ts:
--------------------------------------------------------------------------------
1 | import MQTT, { IClientOptions } from "async-mqtt"
2 | import bs58 from "bs58"
3 | import crypto from 'crypto'
4 | import { EventEmitter } from "stream"
5 |
6 | export interface ISignerClient {
7 | sendForApproval: (payload: Buffer, deviceId: string, requestId: string) => Promise,
8 | }
9 |
10 | export function createSigner(config: IClientOptions, logger?: any): { signer: ISignerClient } {
11 | //--------------------------------------------------------------------------------
12 | // CLIENT: MQTT Connection
13 | //--------------------------------------------------------------------------------
14 | const protocol = process.env["MQTT_HTTP_PORT"] === "8883" ? 'mqtts' : 'mqtt'
15 | const client = MQTT.connect(null, {
16 | clientId: `lattice-${bs58.encode(crypto.randomBytes(8)).slice(6).toUpperCase()}`,
17 | protocol: protocol,
18 | ...config
19 | })
20 |
21 | //--------------------------------------------------------------------------------
22 | // EMITTER: 'Message Received'
23 | //--------------------------------------------------------------------------------
24 | const msgEmitter = new EventEmitter()
25 | const computeEmitterKey = (deviceId: string, requestId: string) => deviceId + requestId
26 |
27 | //--------------------------------------------------------------------------------
28 | // TOPICS: 'TO Agent (Publish)' & 'FROM Agent (Subscribe)'
29 | //--------------------------------------------------------------------------------
30 | const publishTopic = (deviceId, requestId) => `to_agent/${deviceId}/request/${requestId}`
31 | const subscribeTopic = (deviceId, requestId) => `from_agent/${deviceId}/response/${requestId}`
32 |
33 | //--------------------------------------------------------------------------------
34 | // EVENT: 'Connect'
35 | //--------------------------------------------------------------------------------
36 | client.on("connect", (stream) => {
37 | logger?.info(".: [!] MQTT client connected")
38 | })
39 |
40 | //--------------------------------------------------------------------------------
41 | // EVENT: 'Reconnect'
42 | //--------------------------------------------------------------------------------
43 | client.on("reconnect", () => {
44 | logger?.info(".: [!] MQTT client reconnecting...")
45 | })
46 |
47 | //--------------------------------------------------------------------------------
48 | // EVENT: 'Disconnect'
49 | //--------------------------------------------------------------------------------
50 | client.on("disconnect", (stream) => {
51 | logger?.info(".: [!] MQTT client disconnected")
52 | })
53 |
54 | //--------------------------------------------------------------------------------
55 | // EVENT: '(On) Message'
56 | //--------------------------------------------------------------------------------
57 | client.on("message", (topic, payload) => {
58 | const receivedDeviceId = topic.split('/')[1]
59 | const receivedRequestId = topic.split('/')[3]
60 | const receievedPayload = payload.toString('hex')
61 |
62 | // LOG: Confirmation
63 | logger?.info(".: [!] MQTT client receieved:\n", JSON.stringify({
64 | topic: topic,
65 | deviceId: receivedDeviceId,
66 | requestId: receivedRequestId,
67 | payload: `${payload.length} bytes`
68 | }, null, 2))
69 |
70 | const emitterKey = computeEmitterKey(receivedDeviceId, receivedRequestId)
71 | msgEmitter.emit(emitterKey, receievedPayload)
72 | })
73 |
74 | function sendForApproval(payload: Buffer, deviceId: string, requestId: string): Promise {
75 | return new Promise(async (res, rej) => {
76 | // LOG: Initiation
77 | logger?.info(".: [a] Processing request:\n", JSON.stringify({
78 | deviceId: deviceId,
79 | requestId: requestId,
80 | payload: `${payload.length} bytes`
81 | }, null, 2))
82 |
83 | try {
84 | await client.subscribe(subscribeTopic(deviceId, requestId), { qos: 1 })
85 | await client.publish(publishTopic(deviceId, requestId), payload, {
86 | qos: 1,
87 | retain: false,
88 | dup: false
89 | })
90 | }
91 | /**
92 | * Catch 'error'
93 | */
94 | catch (error) {
95 | logger?.info(".: [!] Error:\n", JSON.stringify({
96 | error
97 | }))
98 | return rej(error)
99 | }
100 |
101 | const emitterKey = computeEmitterKey(deviceId, requestId)
102 | const duration = 120000
103 |
104 | setTimeout(() => {
105 | msgEmitter.emit(emitterKey, "TIMED_OUT")
106 | }, duration)
107 |
108 | msgEmitter.once(emitterKey, async (payload) => {
109 | try {
110 | /**
111 | * Unsubscribe & parse 'response'
112 | */
113 | await client
114 | .unsubscribe(subscribeTopic(deviceId, requestId))
115 | .then(() => {
116 | let response = {}
117 | if (payload === "TIMED_OUT") {
118 | response = {
119 | status: 500,
120 | message: "Timed out waiting for response from device"
121 | }
122 |
123 | // LOG: Status Update
124 | logger?.info(`.: [!] Request timed out: ${JSON.stringify({ deviceId, requestId }, null, 2)}`)
125 | }
126 | else {
127 | response = {
128 | status: 200,
129 | message: payload
130 | }
131 | }
132 | // LOG: Confirmation
133 | logger?.info(".: [b] Responding with:\n", JSON.stringify({ payload: `${payload.length} bytes` }, null, 2))
134 | return response
135 | })
136 | .then(res)
137 | }
138 | /**
139 | * Catch 'error'
140 | */
141 | catch (error) {
142 | logger?.info(".: [!] Error:\n", JSON.stringify({
143 | error
144 | }))
145 | /**
146 | * REJECT: 'error'
147 | */
148 | rej(error)
149 | }
150 | })
151 |
152 | // LOG: Send & Wait
153 | logger?.info(`.: [?] Awaiting approval (with timeout: ${duration}ms)...`)
154 | })
155 | }
156 |
157 | return { signer: { sendForApproval } }
158 | }
--------------------------------------------------------------------------------
/connect/src/core/createApp.ts:
--------------------------------------------------------------------------------
1 | import pino, { Options } from "express-pino-logger";
2 | import express from "express";
3 | import bodyParser from "body-parser";
4 | import cors from "cors";
5 |
6 | type App = ReturnType
7 |
8 | export interface IAppConfig {
9 | logging?: Options,
10 | port?: number | string,
11 | workers?: number | string
12 | }
13 |
14 | export interface IApp extends App {
15 | config?: IAppConfig
16 | }
17 |
18 | /**
19 | * Creates an 'Express' instance.
20 | *
21 | * @param config The object that defines specific features of our app instance.
22 | * @returns An 'app' & 'logger' which is associated with the app.
23 | */
24 | export function createApp(config: IAppConfig): Promise<{ app: IApp, logger: any }> {
25 | //----------------------------------------------------------------------------
26 | // APP: Create
27 | //----------------------------------------------------------------------------
28 | const app: IApp = express();
29 | const logger = pino(config.logging)
30 |
31 | //----------------------------------------------------------------------------
32 | // APP: Setup
33 | //----------------------------------------------------------------------------
34 | app.use(cors());
35 | app.use(bodyParser.json());
36 | app.use(logger)
37 |
38 | //----------------------------------------------------------------------------
39 | // GET: "/"
40 | //----------------------------------------------------------------------------
41 | app.get("/", async (_, res) => {
42 | res.sendStatus(200)
43 | })
44 |
45 | //@ts-ignore
46 | app.config = config
47 |
48 | return Promise.resolve({ app, logger: logger.logger })
49 | }
--------------------------------------------------------------------------------
/connect/src/core/index.ts:
--------------------------------------------------------------------------------
1 | import { IApp, IAppConfig } from "./createApp"
2 | import { startServer } from "./startServer"
3 | import { spawn } from "./spawnWorker"
4 | import { Worker } from "cluster";
5 |
6 | export interface IAppService {
7 | app: IApp,
8 | logger: any
9 | }
10 |
11 | export function startService(config: IAppConfig, useService: ((service: IAppService) => void)[]) {
12 | spawn({
13 | upTo: config.workers,
14 | worker: (worker: Worker) => {
15 | startServer({
16 | worker,
17 | config
18 | })
19 | .then(server => useService.forEach(service => service(server)))
20 | .catch((err: any) => {
21 | console.error(err)
22 | process.exit(1)
23 | })
24 | }
25 | })
26 | }
--------------------------------------------------------------------------------
/connect/src/core/spawnWorker.ts:
--------------------------------------------------------------------------------
1 | import cluster, { Worker } from "cluster"
2 |
3 | const log = {
4 | info: console.log
5 | }
6 |
7 | /**
8 | * Spawns as many workers as there are CPUs on the host system,
9 | * unless limited by `limitTo`.
10 | *
11 | * At a minimum, 1 worker is guaranteed to spawn.
12 | */
13 | export function spawn({ upTo, worker }: { upTo?: string | number | undefined, worker: (worker: Worker) => void }) {
14 | if (cluster.isMaster) {
15 | // Spawn Processes
16 | const upperBound = require('os').cpus().length
17 | const lowerBound = upTo ?? upperBound
18 | const numWorkers = Math.max(1, Math.min(lowerBound, upperBound))
19 | for (let i = 0; i < numWorkers; i++) {
20 | cluster.fork()
21 | }
22 |
23 | cluster.on('online', function (worker) {
24 | log.info('Worker ' + worker.id + ' is online')
25 | })
26 |
27 | cluster.on('exit', function (worker, code, signal) {
28 | log.info(`Worker ${worker.id} died with code: ${code}, and signal: ${signal}`)
29 | if (code != 0 && code != 1) {
30 | log.info('Starting a new worker')
31 | cluster.fork()
32 | } else {
33 | log.info(`Worker ${worker.id} is not being replaced. Exiting.`)
34 | }
35 | })
36 | }
37 | else {
38 | worker(cluster.worker!)
39 | }
40 | }
--------------------------------------------------------------------------------
/connect/src/core/startServer.ts:
--------------------------------------------------------------------------------
1 | import http from "http";
2 | import { Worker } from "cluster";
3 | import { createApp, IAppConfig } from "./createApp";
4 |
5 | export async function startServer({ worker, config }: {
6 | worker: Worker,
7 | config: IAppConfig
8 | }): Promise<{ app: any, logger: any }> {
9 | //----------------------------------------------------------------------------------
10 | // APP: Port
11 | //----------------------------------------------------------------------------------
12 | const port = config.port
13 |
14 | /**
15 | * This Promise creates a server from an already instantiated Express 'app', and
16 | * then starts listening on 'port'.
17 | *
18 | * It resolves once it begins listening; it rejects once 'server' receives its
19 | * first (and only) error, at which time the 'server' calls 'close()'.
20 | */
21 | const createServer = ({ app, logger }) => {
22 | return new Promise<{ app: any, logger: any }>((resolve, rejected) => {
23 | //------------------------------------------------------------------------------
24 | // HTTP: Create 'Server'
25 | //------------------------------------------------------------------------------
26 | const server = http.createServer(app).listen(port)
27 |
28 | //------------------------------------------------------------------------------
29 | // EVENT: 'Listening'
30 | //------------------------------------------------------------------------------
31 | server.on('listening', () => {
32 | logger.info(`Worker ${worker.id}: listening on: ${port}`)
33 | resolve({ app, logger })
34 | })
35 |
36 | //------------------------------------------------------------------------------
37 | // EVENT: 'Close'
38 | //------------------------------------------------------------------------------
39 | server.on('close', async () => {
40 | logger.info(`Worker ${worker.id}: closing...`)
41 | })
42 |
43 | //------------------------------------------------------------------------------
44 | // EVENT: 'Error'
45 | //------------------------------------------------------------------------------
46 | server.on('error', (err) => {
47 | server.close()
48 | rejected(err)
49 | })
50 | })
51 | }
52 |
53 | //----------------------------------------------------------------------------------
54 | // SERVER: Create 'App'; Create 'Server'
55 | //----------------------------------------------------------------------------------
56 | return createApp(config).then(createServer)
57 | }
--------------------------------------------------------------------------------
/connect/src/core/utils.ts:
--------------------------------------------------------------------------------
1 |
2 | import bs58 from "bs58"
3 | import crypto from 'crypto'
4 |
5 | export const getRandomUser: () => { id: string, password: string } = () => {
6 | return {
7 | id: bs58.encode(crypto.randomBytes(8)).slice(5),
8 | password: crypto.randomBytes(24).toString('hex')
9 | }
10 | }
--------------------------------------------------------------------------------
/connect/src/direct.ts:
--------------------------------------------------------------------------------
1 | import cluster from "cluster"
2 | import { startService } from "./core"
3 | import { useSigning } from "./services/useSigning"
4 |
5 | if (cluster.isMaster) {
6 | require('dotenv').config({ debug: true, override: true, path: '.direct.env' })
7 | }
8 |
9 | startService({
10 | port: process.env.APP_SERVICE_PORT,
11 | workers: process.env.APP_WORKER_COUNT
12 | }, [useSigning])
13 |
--------------------------------------------------------------------------------
/connect/src/index.ts:
--------------------------------------------------------------------------------
1 | import { startService } from "./core"
2 | import { useProvision } from "./services/useProvision"
3 | import { useSigning } from "./services/useSigning"
4 |
5 | require('dotenv').config()
6 |
7 | startService({
8 | port: process.env.APP_SERVICE_PORT,
9 | workers: process.env.APP_WORKER_COUNT
10 | }, [useProvision, useSigning])
--------------------------------------------------------------------------------
/connect/src/services/useProvision.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import { IAppService } from "../core"
3 | import { IAdminClient, createClient } from "../clients/createClient"
4 | import { getRandomUser } from "../core/utils"
5 |
6 | export async function useProvision(service: IAppService) {
7 | const retry = {
8 | count: 0,
9 | limit: 5
10 | }
11 |
12 | const generateNextValidUser = async (client: IAdminClient, userGenerator: () => {
13 | id: string;
14 | password: string;
15 | }): Promise<{ id: string, password: string }> => {
16 | return new Promise(async (res, rej) => {
17 | const user = userGenerator()
18 | await client
19 | .get({ api: `users/${user.id}` })
20 | .ok((res: any) => res.status == 404)
21 | .catch((error: any) => {
22 | if (error.status == 200) {
23 | // We've hit our "retry.limit". The chances of this
24 | // happening are **infinitesimally** small.
25 | //-------------------------------------------------
26 | if (retry.count >= retry.limit) {
27 | retry.count = 0
28 | return rej({
29 | status: 500,
30 | message: "Unable to provision new user. Retry limit exceeded."
31 | })
32 | }
33 |
34 | // Keep retrying (up to "retry.limit" times)...
35 | //----------------------------------------------
36 | retry.count += 1
37 | return res(
38 | generateNextValidUser(client, userGenerator)
39 | )
40 | }
41 | rej(error)
42 | })
43 | res(user)
44 | })
45 | }
46 |
47 | return await createClient({
48 | url: new URL(`${process.env.ADMIN_CLIENT_HOST}`),
49 | username: process.env.ADMIN_CLIENT_USER,
50 | password: process.env.ADMIN_CLIENT_PASS
51 | })
52 | .then(({ client }) => {
53 | service.app.get("/provision", async (req: Request, res: Response) => {
54 | await generateNextValidUser(client, getRandomUser)
55 | .then(async user => {
56 | await client.put({
57 | api: `users/${user.id}`,
58 | payload: {
59 | password: user.password,
60 | tags: 'lattice'
61 | }
62 | }).then((_res: any) => client.put({
63 | api: `permissions/%2F/${user.id}`,
64 | payload: {
65 | configure: '.*',
66 | write: '.*',
67 | read: '.*'
68 | }
69 | })).then((_res: any) => client.put({
70 | api: `topic-permissions/%2F/${user.id}`,
71 | payload: {
72 | exchange: 'amq.topic',
73 | write: '.*',
74 | read: 'to_agent.{username}.*|lattice.*'
75 | }
76 | }))
77 | res.json({
78 | user: user.id,
79 | password: user.password
80 | })
81 | })
82 | .catch(error => {
83 | console.error(error)
84 | res.status(500).send(error)
85 | })
86 | })
87 | })
88 | }
89 |
--------------------------------------------------------------------------------
/connect/src/services/useSigning.ts:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 |
3 | import { Request, Response } from "express";
4 | import { IAppService } from "../core"
5 | import { createClient } from "../clients/createClient"
6 | import crypto from 'crypto'
7 | import cluster from "cluster";
8 | import { createSigner } from "../clients/createSigner";
9 |
10 | export async function useSigning(service: IAppService) {
11 | const logger = service.logger
12 | const broker = new URL(`${process.env.ADMIN_CLIENT_HOST}`)
13 |
14 | const { signer } = createSigner({
15 | host: broker.hostname,
16 | port: parseInt(`${process.env.MQTT_HTTP_PORT}`),
17 | username: process.env.ADMIN_CLIENT_USER,
18 | password: process.env.ADMIN_CLIENT_PASS,
19 | }, logger)
20 |
21 | const getDeviceId = (req: Request): string | undefined => {
22 | return req.params?.deviceId
23 | }
24 |
25 | const generateRequestId = (): string => {
26 | return crypto.randomBytes(4).toString('hex')
27 | }
28 |
29 | const getRequestData = (req: Request): any | undefined => {
30 | return req.body.data?.data
31 | }
32 |
33 | const preflightCheck = async (deviceId: string | undefined, res: Response) => {
34 | if (process.env.MQTT_SKIP_USER_CHECK) { return }
35 | await createClient({
36 | url: broker,
37 | username: process.env.ADMIN_CLIENT_USER,
38 | password: process.env.ADMIN_CLIENT_PASS
39 | }).then(async ({ client }) => {
40 | await client.get({ api: `users/${deviceId}` }).then(() =>
41 | logger.info("[4] Device ID: VALID")
42 | )
43 | })
44 | }
45 |
46 | service.app.post("/:deviceId", async (req: Request, res: Response) => {
47 | const deviceId = getDeviceId(req)
48 | const requestId = generateRequestId()
49 | const requestData = getRequestData(req)
50 |
51 | logger.info("------------------------")
52 | logger.info("HANDLING MESSAGE [RELAY]")
53 | logger.info("------------------------")
54 | logger.info(`[0] Worker #${cluster.worker?.id} received payload...`)
55 | logger.info(`[1] Request ID created: '${requestId}'`)
56 | logger.info(`[2] Verifying deviceId: '${deviceId}'...`)
57 |
58 | //-------------------------------------------------------
59 | // Pre-flight check ✅
60 | // Validate the received payload
61 | //-------------------------------------------------------
62 | if (!requestData || !deviceId) {
63 | logger.info("[!] Failed to parse request (missing 'requestData' OR 'deviceId')")
64 | logger.info(`[!] 'deviceId': ${deviceId}`)
65 | return res.status(200).send({
66 | status: 400,
67 | message: "Invalid request"
68 | })
69 | }
70 |
71 | //-------------------------------------------------------
72 | // Pre-flight check ✅
73 | // Check to see if the user (deviceId) exists (OPTIONAL)
74 | //-------------------------------------------------------
75 | try {
76 | await preflightCheck(deviceId, res)
77 | } catch (error) {
78 | logger.info(`[!] Database request responded with: '${error}'`)
79 | return res.status(200).send({
80 | status: 401,
81 | message: "Unauthorized"
82 | })
83 | }
84 |
85 | //-------------------------------------------------------
86 | // Relay message; wait for approval 🔄
87 | //-------------------------------------------------------
88 | try {
89 | const payload = Buffer.from(requestData!)
90 | logger.info("[3] Payload: VALID")
91 |
92 | const response = await signer.sendForApproval(payload, deviceId, requestId)
93 |
94 | return res.send(response)
95 | } catch (error: any) {
96 | return res.status(500).send({
97 | status: 500,
98 | message: `Error while attempting to relay message. Reason: '${error.message}'`
99 | })
100 | }
101 | })
102 | }
103 |
--------------------------------------------------------------------------------
/connect/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
9 | // "lib": [], /* Specify library files to be included in the compilation. */
10 | // "allowJs": true, /* Allow javascript files to be compiled. */
11 | // "checkJs": true, /* Report errors in .js files. */
12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
15 | // "sourceMap": true, /* Generates corresponding '.map' file. */
16 | // "outFile": "./", /* Concatenate and emit output to single file. */
17 | "outDir": "./dist" /* Redirect output structure to the directory. */,
18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19 | // "composite": true, /* Enable project compilation */
20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
21 | // "removeComments": true, /* Do not emit comments to output. */
22 | // "noEmit": true, /* Do not emit outputs. */
23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26 |
27 | /* Strict Type-Checking Options */
28 | "strict": true /* Enable all strict type-checking options. */,
29 | "noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */,
30 | // "strictNullChecks": true, /* Enable strict null checks. */
31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
36 |
37 | /* Additional Checks */
38 | // "noUnusedLocals": true, /* Report errors on unused locals. */
39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
43 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
44 |
45 | /* Module Resolution Options */
46 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
47 | "resolveJsonModule": true, /* Allows importing modules with a ‘.json’ extension, which is a common practice in node projects. */
48 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
51 | // "typeRoots": [], /* List of folders to include type definitions from. */
52 | "types": [
53 | "node"
54 | ] /* Type declaration files to be included in compilation. */,
55 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
56 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
57 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
58 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
59 |
60 | /* Source Map Options */
61 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
62 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
63 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
64 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
65 |
66 | /* Experimental Options */
67 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
68 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
69 |
70 | /* Advanced Options */
71 | "skipLibCheck": true /* Skip type checking of declaration files. */,
72 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
73 | },
74 | "include": ["src", "index.*"],
75 | "exclude": ["node_modules", "**/*.spec.ts", "**/*.test.ts"]
76 | }
77 |
--------------------------------------------------------------------------------
/mqtt-broker/.env:
--------------------------------------------------------------------------------
1 | ERLANG_COOKIE='erlang-cookie'
--------------------------------------------------------------------------------
/mqtt-broker/README.md:
--------------------------------------------------------------------------------
1 | # MQTT Broker
2 |
3 | This folder is intended for the GridPlus team, and contains the source files for the RabbitMQ broker used in the _Lattice Connect_ service.
--------------------------------------------------------------------------------
/mqtt-broker/config/.gitignore:
--------------------------------------------------------------------------------
1 | data.json
2 | data-*.json
3 |
--------------------------------------------------------------------------------
/mqtt-broker/config/enabled_plugins:
--------------------------------------------------------------------------------
1 | [rabbitmq_management, rabbitmq_mqtt, rabbitmq_prometheus].
2 |
--------------------------------------------------------------------------------
/mqtt-broker/config/rabbitmq.conf:
--------------------------------------------------------------------------------
1 | # https://github.com/rabbitmq/rabbitmq-server/blob/master/deps/rabbit/docs/rabbitmq.conf.example#
2 |
3 | # log.file.level = error
4 | # loopback_users.guest = false
5 |
6 | # https://www.rabbitmq.com/connections.html#large-number-of-connections
7 | # sets the interval to 60 seconds
8 | collect_statistics_interval = 60000
9 |
10 | # definitions.skip_if_unchanged = true
11 | load_definitions = /etc/rabbitmq/data.json
12 |
13 | mqtt.allow_anonymous = false
14 | # mqtt.proxy_protocol = true
15 |
16 | # mqtt.listeners.tcp.1 = 127.0.0.1:1883
17 | # mqtt.listeners.tcp.2 = ::1:1883
18 |
19 | # mqtt.tcp_listen_options.backlog = 4096
20 | # mqtt.tcp_listen_options.recbuf = 131072
21 | # mqtt.tcp_listen_options.sndbuf = 131072
22 |
23 | # mqtt.tcp_listen_options.keepalive = true
24 | # mqtt.tcp_listen_options.nodelay = true
25 |
26 | # mqtt.tcp_listen_options.exit_on_close = true
27 | # mqtt.tcp_listen_options.send_timeout = 120
28 |
29 | # https://www.rabbitmq.com/networking.html#tuning-for-large-number-of-connections-tcp-buffer-size
30 | mqtt.tcp_listen_options.backlog = 128
31 | mqtt.tcp_listen_options.nodelay = true
32 | mqtt.tcp_listen_options.linger.on = true
33 | mqtt.tcp_listen_options.linger.timeout = 0
34 | mqtt.tcp_listen_options.sndbuf = 32768
35 | mqtt.tcp_listen_options.recbuf = 32768
36 |
37 | # https://www.rabbitmq.com/networking.html#dns-reverse-dns-lookups
38 | reverse_dns_lookups = false
39 |
40 | management.listener.port = 15672
41 | management.listener.ssl = false
42 |
43 | vm_memory_high_watermark.absolute = 8096MiB
44 | vm_memory_high_watermark_paging_ratio = 0.2
45 |
46 | # cluster_name = lattice-mqtt-cluster
47 |
48 | # cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
49 | # cluster_formation.classic_config.nodes.1 = rabbit@mqtt-broker-1
50 | # cluster_formation.classic_config.nodes.2 = rabbit@mqtt-broker-2
51 | # cluster_formation.classic_config.nodes.3 = rabbit@mqtt-broker-3
52 |
--------------------------------------------------------------------------------
/mqtt-broker/container/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM rabbitmq:3.10.6-management-alpine
2 |
3 | COPY config /etc/rabbitmq/
--------------------------------------------------------------------------------
/mqtt-broker/container/dockerBuild.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | docker build -f Dockerfile ../ -t mqtt-broker:latest
4 |
--------------------------------------------------------------------------------
/mqtt-broker/container/dockerStart.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | docker run \
4 | --ulimit nofile=262144:262144 \
5 | -m "8G" --memory-swap "-1" \
6 | --rm -it \
7 | --init \
8 | -h mqtt-broker \
9 | -p 1883:1883 \
10 | -p 15672:15672 \
11 | --env-file ../.env \
12 | --name "mqtt-broker" \
13 | mqtt-broker
14 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/.gitignore:
--------------------------------------------------------------------------------
1 | grafana/data
2 | prometheus/data
3 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/grafana/dashboards.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | providers:
4 | - name: 'rabbitmq'
5 | orgId: 1
6 | folder: ''
7 | type: file
8 | disableDeletion: true
9 | options:
10 | path: /dashboards
11 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/grafana/dashboards/Erlang-Distributions-Compare.json:
--------------------------------------------------------------------------------
1 | {
2 | "__requires": [
3 | {
4 | "type": "grafana",
5 | "id": "grafana",
6 | "name": "Grafana",
7 | "version": "7.0.0"
8 | },
9 | {
10 | "type": "datasource",
11 | "id": "prometheus",
12 | "name": "prometheus",
13 | "version": "2.0.0"
14 | },
15 | {
16 | "type": "table",
17 | "id": "table",
18 | "name": "Table",
19 | "version": ""
20 | },
21 | {
22 | "type": "panel",
23 | "id": "graph",
24 | "name": "Graph",
25 | "version": ""
26 | },
27 | {
28 | "type": "panel",
29 | "id": "heatmap",
30 | "name": "Heatmap",
31 | "version": ""
32 | }
33 | ],
34 | "annotations": {
35 | "list": [
36 | {
37 | "builtIn": 1,
38 | "datasource": "-- Grafana --",
39 | "enable": true,
40 | "hide": true,
41 | "iconColor": "rgba(0, 211, 255, 1)",
42 | "name": "Annotations & Alerts",
43 | "type": "dashboard"
44 | }
45 | ]
46 | },
47 | "editable": true,
48 | "gnetId": null,
49 | "graphTooltip": 1,
50 | "iteration": 1571066778520,
51 | "links": [],
52 | "panels": [
53 | {
54 | "collapsed": false,
55 | "datasource": null,
56 | "gridPos": {
57 | "h": 1,
58 | "w": 24,
59 | "x": 0,
60 | "y": 0
61 | },
62 | "id": 67,
63 | "panels": [],
64 | "title": "rabbitmq-prometheus",
65 | "type": "row"
66 | },
67 | {
68 | "columns": [
69 | {
70 | "text": "Min",
71 | "value": "min"
72 | },
73 | {
74 | "text": "Max",
75 | "value": "max"
76 | },
77 | {
78 | "text": "Avg",
79 | "value": "avg"
80 | },
81 | {
82 | "text": "Current",
83 | "value": "current"
84 | }
85 | ],
86 | "datasource": null,
87 | "fontSize": "100%",
88 | "gridPos": {
89 | "h": 7,
90 | "w": 9,
91 | "x": 0,
92 | "y": 1
93 | },
94 | "id": 56,
95 | "options": {},
96 | "pageSize": null,
97 | "pluginVersion": "6.4.1",
98 | "scroll": true,
99 | "showHeader": true,
100 | "sort": {
101 | "col": 4,
102 | "desc": true
103 | },
104 | "styles": [
105 | {
106 | "alias": "Node -> Peer",
107 | "colorMode": null,
108 | "colors": [
109 | "rgba(245, 54, 54, 0.9)",
110 | "rgba(237, 129, 40, 0.89)",
111 | "rgba(50, 172, 45, 0.97)"
112 | ],
113 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
114 | "decimals": 0,
115 | "mappingType": 1,
116 | "pattern": "Metric",
117 | "thresholds": [],
118 | "type": "string",
119 | "unit": "short"
120 | },
121 | {
122 | "alias": "",
123 | "colorMode": null,
124 | "colors": [
125 | "rgba(245, 54, 54, 0.9)",
126 | "rgba(237, 129, 40, 0.89)",
127 | "rgba(50, 172, 45, 0.97)"
128 | ],
129 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
130 | "decimals": 1,
131 | "mappingType": 1,
132 | "pattern": "/.*/",
133 | "thresholds": [],
134 | "type": "number",
135 | "unit": "Bps"
136 | }
137 | ],
138 | "targets": [
139 | {
140 | "expr": "rate(erlang_vm_dist_send_bytes[60s]) * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=~\"$rabbitmq_cluster\", namespace=\"$namespace\"}",
141 | "legendFormat": "{{rabbitmq_node}} -> {{peer}}",
142 | "refId": "A"
143 | }
144 | ],
145 | "timeFrom": null,
146 | "timeShift": null,
147 | "title": "Erlang Distribution outgoing traffic / s",
148 | "transform": "timeseries_aggregations",
149 | "type": "table"
150 | },
151 | {
152 | "aliasColors": {},
153 | "bars": false,
154 | "dashLength": 10,
155 | "dashes": false,
156 | "datasource": null,
157 | "description": "Erlang Distribution traffic, node network traffic and CPU + PerfTest message throughput and latency",
158 | "fill": 0,
159 | "fillGradient": 0,
160 | "gridPos": {
161 | "h": 7,
162 | "w": 15,
163 | "x": 9,
164 | "y": 1
165 | },
166 | "id": 3,
167 | "legend": {
168 | "alignAsTable": true,
169 | "avg": false,
170 | "current": true,
171 | "max": true,
172 | "min": true,
173 | "rightSide": false,
174 | "show": false,
175 | "sort": "max",
176 | "sortDesc": true,
177 | "total": false,
178 | "values": true
179 | },
180 | "lines": true,
181 | "linewidth": 1,
182 | "links": [],
183 | "nullPointMode": "null",
184 | "options": {
185 | "dataLinks": []
186 | },
187 | "percentage": false,
188 | "pointradius": 2,
189 | "points": false,
190 | "renderer": "flot",
191 | "seriesOverrides": [
192 | {
193 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/",
194 | "color": "#56A64B"
195 | },
196 | {
197 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/",
198 | "color": "#F2CC0C"
199 | },
200 | {
201 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/",
202 | "color": "#3274D9"
203 | },
204 | {
205 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/",
206 | "color": "#A352CC"
207 | },
208 | {
209 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/",
210 | "color": "#FF780A"
211 | },
212 | {
213 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/",
214 | "color": "#96D98D"
215 | },
216 | {
217 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/",
218 | "color": "#FFEE52"
219 | },
220 | {
221 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/",
222 | "color": "#8AB8FF"
223 | },
224 | {
225 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/",
226 | "color": "#CA95E5"
227 | },
228 | {
229 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/",
230 | "color": "#FFB357"
231 | }
232 | ],
233 | "spaceLength": 10,
234 | "stack": false,
235 | "steppedLine": false,
236 | "targets": [
237 | {
238 | "expr": "rate(erlang_vm_dist_send_bytes[60s]) * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=~\"$rabbitmq_cluster\", namespace=\"$namespace\"}",
239 | "format": "time_series",
240 | "intervalFactor": 1,
241 | "legendFormat": "{{rabbitmq_node}} -> {{peer}}",
242 | "refId": "A"
243 | }
244 | ],
245 | "thresholds": [],
246 | "timeFrom": null,
247 | "timeRegions": [],
248 | "timeShift": null,
249 | "title": "Erlang Distribution outgoing traffic / s",
250 | "tooltip": {
251 | "shared": true,
252 | "sort": 2,
253 | "value_type": "individual"
254 | },
255 | "transparent": true,
256 | "type": "graph",
257 | "xaxis": {
258 | "buckets": null,
259 | "mode": "time",
260 | "name": null,
261 | "show": true,
262 | "values": []
263 | },
264 | "yaxes": [
265 | {
266 | "decimals": 0,
267 | "format": "Bps",
268 | "label": null,
269 | "logBase": 1,
270 | "max": null,
271 | "min": "0",
272 | "show": true
273 | },
274 | {
275 | "format": "short",
276 | "label": null,
277 | "logBase": 1,
278 | "max": null,
279 | "min": null,
280 | "show": true
281 | }
282 | ],
283 | "yaxis": {
284 | "align": false,
285 | "alignLevel": null
286 | }
287 | },
288 | {
289 | "collapsed": false,
290 | "datasource": null,
291 | "gridPos": {
292 | "h": 1,
293 | "w": 24,
294 | "x": 0,
295 | "y": 8
296 | },
297 | "id": 65,
298 | "panels": [],
299 | "title": "node-exporter_cadvisor",
300 | "type": "row"
301 | },
302 | {
303 | "columns": [
304 | {
305 | "text": "Min",
306 | "value": "min"
307 | },
308 | {
309 | "text": "Max",
310 | "value": "max"
311 | },
312 | {
313 | "text": "Avg",
314 | "value": "avg"
315 | },
316 | {
317 | "text": "Current",
318 | "value": "current"
319 | }
320 | ],
321 | "datasource": null,
322 | "fontSize": "100%",
323 | "gridPos": {
324 | "h": 7,
325 | "w": 9,
326 | "x": 0,
327 | "y": 9
328 | },
329 | "id": 61,
330 | "options": {},
331 | "pageSize": null,
332 | "pluginVersion": "6.4.1",
333 | "scroll": true,
334 | "showHeader": true,
335 | "sort": {
336 | "col": 4,
337 | "desc": true
338 | },
339 | "styles": [
340 | {
341 | "alias": "Host",
342 | "colorMode": null,
343 | "colors": [
344 | "rgba(245, 54, 54, 0.9)",
345 | "rgba(237, 129, 40, 0.89)",
346 | "rgba(50, 172, 45, 0.97)"
347 | ],
348 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
349 | "decimals": 0,
350 | "mappingType": 1,
351 | "pattern": "Metric",
352 | "thresholds": [],
353 | "type": "string",
354 | "unit": "short"
355 | },
356 | {
357 | "alias": "",
358 | "colorMode": null,
359 | "colors": [
360 | "rgba(245, 54, 54, 0.9)",
361 | "rgba(237, 129, 40, 0.89)",
362 | "rgba(50, 172, 45, 0.97)"
363 | ],
364 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
365 | "decimals": 1,
366 | "mappingType": 1,
367 | "pattern": "/.*/",
368 | "thresholds": [],
369 | "type": "number",
370 | "unit": "Bps"
371 | }
372 | ],
373 | "targets": [
374 | {
375 | "expr": "sum by(instance) (rate(node_network_receive_bytes_total{instance=~\"$host\"}[5m]))",
376 | "legendFormat": "{{instance}}",
377 | "refId": "A"
378 | },
379 | {
380 | "expr": "sum by(name) (rate(container_network_receive_bytes_total{name=~\"$container\"}[1m]))",
381 | "legendFormat": "{{name}}",
382 | "refId": "B"
383 | }
384 | ],
385 | "timeFrom": null,
386 | "timeShift": null,
387 | "title": "Network incoming traffic / s",
388 | "transform": "timeseries_aggregations",
389 | "type": "table"
390 | },
391 | {
392 | "aliasColors": {},
393 | "bars": false,
394 | "dashLength": 10,
395 | "dashes": false,
396 | "datasource": null,
397 | "decimals": null,
398 | "editable": true,
399 | "error": false,
400 | "fill": 0,
401 | "fillGradient": 0,
402 | "grid": {},
403 | "gridPos": {
404 | "h": 7,
405 | "w": 15,
406 | "x": 9,
407 | "y": 9
408 | },
409 | "height": "",
410 | "id": 58,
411 | "legend": {
412 | "alignAsTable": true,
413 | "avg": true,
414 | "current": false,
415 | "hideEmpty": true,
416 | "hideZero": true,
417 | "max": true,
418 | "min": true,
419 | "rightSide": true,
420 | "show": false,
421 | "sort": "max",
422 | "sortDesc": true,
423 | "total": false,
424 | "values": true
425 | },
426 | "lines": true,
427 | "linewidth": 1,
428 | "links": [],
429 | "maxPerRow": 3,
430 | "nullPointMode": "null",
431 | "options": {
432 | "dataLinks": []
433 | },
434 | "percentage": false,
435 | "pointradius": 5,
436 | "points": false,
437 | "renderer": "flot",
438 | "repeatDirection": "h",
439 | "seriesOverrides": [],
440 | "spaceLength": 10,
441 | "stack": false,
442 | "steppedLine": false,
443 | "targets": [
444 | {
445 | "calculatedInterval": "2s",
446 | "datasourceErrors": {},
447 | "errors": {},
448 | "expr": "sum by(instance) (rate(node_network_receive_bytes_total{instance=~\"$host\"}[5m]))",
449 | "format": "time_series",
450 | "interval": "",
451 | "intervalFactor": 1,
452 | "legendFormat": "{{instance}}",
453 | "metric": "",
454 | "refId": "A",
455 | "step": 20
456 | },
457 | {
458 | "expr": "sum by(name) (rate(container_network_receive_bytes_total{name=~\"$container\"}[1m]))",
459 | "format": "time_series",
460 | "intervalFactor": 1,
461 | "legendFormat": "{{name}}",
462 | "refId": "B"
463 | }
464 | ],
465 | "thresholds": [],
466 | "timeFrom": null,
467 | "timeRegions": [],
468 | "timeShift": null,
469 | "title": "Network incoming traffic / s",
470 | "tooltip": {
471 | "msResolution": false,
472 | "shared": true,
473 | "sort": 2,
474 | "value_type": "individual"
475 | },
476 | "transparent": true,
477 | "type": "graph",
478 | "xaxis": {
479 | "buckets": null,
480 | "mode": "time",
481 | "name": null,
482 | "show": true,
483 | "values": []
484 | },
485 | "yaxes": [
486 | {
487 | "decimals": 1,
488 | "format": "Bps",
489 | "label": "",
490 | "logBase": 1,
491 | "max": null,
492 | "min": null,
493 | "show": true
494 | },
495 | {
496 | "format": "short",
497 | "logBase": 1,
498 | "max": null,
499 | "min": 0,
500 | "show": false
501 | }
502 | ],
503 | "yaxis": {
504 | "align": false,
505 | "alignLevel": null
506 | }
507 | },
508 | {
509 | "columns": [
510 | {
511 | "text": "Min",
512 | "value": "min"
513 | },
514 | {
515 | "text": "Max",
516 | "value": "max"
517 | },
518 | {
519 | "text": "Avg",
520 | "value": "avg"
521 | },
522 | {
523 | "text": "Current",
524 | "value": "current"
525 | }
526 | ],
527 | "datasource": null,
528 | "fontSize": "100%",
529 | "gridPos": {
530 | "h": 7,
531 | "w": 9,
532 | "x": 0,
533 | "y": 16
534 | },
535 | "id": 60,
536 | "options": {},
537 | "pageSize": null,
538 | "pluginVersion": "6.4.1",
539 | "scroll": true,
540 | "showHeader": true,
541 | "sort": {
542 | "col": 4,
543 | "desc": true
544 | },
545 | "styles": [
546 | {
547 | "alias": "Host",
548 | "colorMode": null,
549 | "colors": [
550 | "rgba(245, 54, 54, 0.9)",
551 | "rgba(237, 129, 40, 0.89)",
552 | "rgba(50, 172, 45, 0.97)"
553 | ],
554 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
555 | "decimals": 0,
556 | "mappingType": 1,
557 | "pattern": "Metric",
558 | "thresholds": [],
559 | "type": "string",
560 | "unit": "short"
561 | },
562 | {
563 | "alias": "",
564 | "colorMode": null,
565 | "colors": [
566 | "rgba(245, 54, 54, 0.9)",
567 | "rgba(237, 129, 40, 0.89)",
568 | "rgba(50, 172, 45, 0.97)"
569 | ],
570 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
571 | "decimals": 1,
572 | "mappingType": 1,
573 | "pattern": "/.*/",
574 | "thresholds": [],
575 | "type": "number",
576 | "unit": "Bps"
577 | }
578 | ],
579 | "targets": [
580 | {
581 | "expr": "sum by(instance) (rate(node_network_transmit_bytes_total{instance=~\"$host\"}[5m]))",
582 | "legendFormat": "{{instance}}",
583 | "refId": "A"
584 | },
585 | {
586 | "expr": "sum by(name) (rate(container_network_transmit_bytes_total{name=~\"$container\"}[1m]))",
587 | "legendFormat": "{{name}}",
588 | "refId": "B"
589 | }
590 | ],
591 | "timeFrom": null,
592 | "timeShift": null,
593 | "title": "Network outgoing traffic / s",
594 | "transform": "timeseries_aggregations",
595 | "type": "table"
596 | },
597 | {
598 | "aliasColors": {},
599 | "bars": false,
600 | "dashLength": 10,
601 | "dashes": false,
602 | "datasource": null,
603 | "decimals": null,
604 | "editable": true,
605 | "error": false,
606 | "fill": 0,
607 | "fillGradient": 0,
608 | "grid": {},
609 | "gridPos": {
610 | "h": 7,
611 | "w": 15,
612 | "x": 9,
613 | "y": 16
614 | },
615 | "height": "",
616 | "id": 57,
617 | "legend": {
618 | "alignAsTable": true,
619 | "avg": true,
620 | "current": false,
621 | "hideEmpty": true,
622 | "hideZero": true,
623 | "max": true,
624 | "min": true,
625 | "rightSide": true,
626 | "show": false,
627 | "sort": "max",
628 | "sortDesc": true,
629 | "total": false,
630 | "values": true
631 | },
632 | "lines": true,
633 | "linewidth": 1,
634 | "links": [],
635 | "maxPerRow": 3,
636 | "nullPointMode": "null",
637 | "options": {
638 | "dataLinks": []
639 | },
640 | "percentage": false,
641 | "pointradius": 5,
642 | "points": false,
643 | "renderer": "flot",
644 | "repeatDirection": "h",
645 | "seriesOverrides": [],
646 | "spaceLength": 10,
647 | "stack": false,
648 | "steppedLine": false,
649 | "targets": [
650 | {
651 | "calculatedInterval": "2s",
652 | "datasourceErrors": {},
653 | "errors": {},
654 | "expr": "sum by(instance) (rate(node_network_transmit_bytes_total{instance=~\"$host\"}[5m]))",
655 | "format": "time_series",
656 | "interval": "",
657 | "intervalFactor": 1,
658 | "legendFormat": "{{instance}}",
659 | "metric": "",
660 | "refId": "A",
661 | "step": 20
662 | },
663 | {
664 | "expr": "sum by(name) (rate(container_network_transmit_bytes_total{name=~\"$container\"}[1m]))",
665 | "format": "time_series",
666 | "intervalFactor": 1,
667 | "legendFormat": "{{name}}",
668 | "refId": "B"
669 | }
670 | ],
671 | "thresholds": [],
672 | "timeFrom": null,
673 | "timeRegions": [],
674 | "timeShift": null,
675 | "title": "Network outgoing traffic / s",
676 | "tooltip": {
677 | "msResolution": false,
678 | "shared": true,
679 | "sort": 2,
680 | "value_type": "individual"
681 | },
682 | "transparent": true,
683 | "type": "graph",
684 | "xaxis": {
685 | "buckets": null,
686 | "mode": "time",
687 | "name": null,
688 | "show": true,
689 | "values": []
690 | },
691 | "yaxes": [
692 | {
693 | "decimals": 1,
694 | "format": "Bps",
695 | "label": "",
696 | "logBase": 1,
697 | "max": null,
698 | "min": null,
699 | "show": true
700 | },
701 | {
702 | "format": "short",
703 | "logBase": 1,
704 | "max": null,
705 | "min": 0,
706 | "show": false
707 | }
708 | ],
709 | "yaxis": {
710 | "align": false,
711 | "alignLevel": null
712 | }
713 | },
714 | {
715 | "columns": [
716 | {
717 | "text": "Min",
718 | "value": "min"
719 | },
720 | {
721 | "text": "Max",
722 | "value": "max"
723 | },
724 | {
725 | "text": "Avg",
726 | "value": "avg"
727 | },
728 | {
729 | "text": "Current",
730 | "value": "current"
731 | }
732 | ],
733 | "datasource": null,
734 | "fontSize": "100%",
735 | "gridPos": {
736 | "h": 7,
737 | "w": 9,
738 | "x": 0,
739 | "y": 23
740 | },
741 | "id": 59,
742 | "options": {},
743 | "pageSize": null,
744 | "pluginVersion": "6.4.1",
745 | "scroll": true,
746 | "showHeader": true,
747 | "sort": {
748 | "col": 4,
749 | "desc": true
750 | },
751 | "styles": [
752 | {
753 | "alias": "Host",
754 | "colorMode": null,
755 | "colors": [
756 | "rgba(245, 54, 54, 0.9)",
757 | "rgba(237, 129, 40, 0.89)",
758 | "rgba(50, 172, 45, 0.97)"
759 | ],
760 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
761 | "decimals": 0,
762 | "mappingType": 1,
763 | "pattern": "Metric",
764 | "thresholds": [],
765 | "type": "string",
766 | "unit": "short"
767 | },
768 | {
769 | "alias": "",
770 | "colorMode": null,
771 | "colors": [
772 | "rgba(245, 54, 54, 0.9)",
773 | "rgba(237, 129, 40, 0.89)",
774 | "rgba(50, 172, 45, 0.97)"
775 | ],
776 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
777 | "decimals": 0,
778 | "mappingType": 1,
779 | "pattern": "/.*/",
780 | "thresholds": [],
781 | "type": "number",
782 | "unit": "percent"
783 | }
784 | ],
785 | "targets": [
786 | {
787 | "expr": "(max by (instance) (irate(node_cpu_seconds_total{job=\"node\", mode=~\"user|system|iowait|softirq\", instance=~\"$host\"}[5m])) * 100)",
788 | "legendFormat": "{{instance}}",
789 | "refId": "A"
790 | },
791 | {
792 | "expr": "sum by(name) (irate(container_cpu_usage_seconds_total{name=~\"$container\"}[1m])) * 100",
793 | "legendFormat": "{{name}}",
794 | "refId": "B"
795 | }
796 | ],
797 | "timeFrom": null,
798 | "timeShift": null,
799 | "title": "CPU",
800 | "transform": "timeseries_aggregations",
801 | "type": "table"
802 | },
803 | {
804 | "aliasColors": {},
805 | "bars": false,
806 | "dashLength": 10,
807 | "dashes": false,
808 | "datasource": null,
809 | "decimals": null,
810 | "editable": true,
811 | "error": false,
812 | "fill": 0,
813 | "fillGradient": 0,
814 | "grid": {},
815 | "gridPos": {
816 | "h": 7,
817 | "w": 15,
818 | "x": 9,
819 | "y": 23
820 | },
821 | "height": "",
822 | "id": 28,
823 | "legend": {
824 | "alignAsTable": true,
825 | "avg": true,
826 | "current": false,
827 | "hideEmpty": true,
828 | "hideZero": true,
829 | "max": true,
830 | "min": true,
831 | "rightSide": true,
832 | "show": false,
833 | "sort": "max",
834 | "sortDesc": true,
835 | "total": false,
836 | "values": true
837 | },
838 | "lines": true,
839 | "linewidth": 1,
840 | "links": [],
841 | "maxPerRow": 3,
842 | "nullPointMode": "null",
843 | "options": {
844 | "dataLinks": []
845 | },
846 | "percentage": false,
847 | "pointradius": 5,
848 | "points": false,
849 | "renderer": "flot",
850 | "repeat": null,
851 | "repeatDirection": "h",
852 | "seriesOverrides": [],
853 | "spaceLength": 10,
854 | "stack": false,
855 | "steppedLine": false,
856 | "targets": [
857 | {
858 | "calculatedInterval": "2s",
859 | "datasourceErrors": {},
860 | "errors": {},
861 | "expr": "(max by (instance) (irate(node_cpu_seconds_total{job=\"node\", mode=~\"user|system|iowait|softirq\", instance=~\"$host\"}[5m])) * 100)",
862 | "format": "time_series",
863 | "interval": "",
864 | "intervalFactor": 1,
865 | "legendFormat": "{{instance}}",
866 | "metric": "",
867 | "refId": "A",
868 | "step": 20
869 | },
870 | {
871 | "expr": "sum by(name) (irate(container_cpu_usage_seconds_total{name=~\"$container\"}[1m])) * 100",
872 | "format": "time_series",
873 | "hide": false,
874 | "intervalFactor": 1,
875 | "legendFormat": "{{name}}",
876 | "refId": "B"
877 | }
878 | ],
879 | "thresholds": [],
880 | "timeFrom": null,
881 | "timeRegions": [],
882 | "timeShift": null,
883 | "title": "CPU",
884 | "tooltip": {
885 | "msResolution": false,
886 | "shared": true,
887 | "sort": 2,
888 | "value_type": "individual"
889 | },
890 | "transparent": true,
891 | "type": "graph",
892 | "xaxis": {
893 | "buckets": null,
894 | "mode": "time",
895 | "name": null,
896 | "show": true,
897 | "values": []
898 | },
899 | "yaxes": [
900 | {
901 | "format": "percent",
902 | "label": "",
903 | "logBase": 1,
904 | "max": null,
905 | "min": 0,
906 | "show": true
907 | },
908 | {
909 | "format": "short",
910 | "logBase": 1,
911 | "max": null,
912 | "min": 0,
913 | "show": true
914 | }
915 | ],
916 | "yaxis": {
917 | "align": false,
918 | "alignLevel": null
919 | }
920 | },
921 | {
922 | "collapsed": false,
923 | "datasource": null,
924 | "gridPos": {
925 | "h": 1,
926 | "w": 24,
927 | "x": 0,
928 | "y": 30
929 | },
930 | "id": 63,
931 | "panels": [],
932 | "title": "rabbitmq-perf-test",
933 | "type": "row"
934 | },
935 | {
936 | "columns": [
937 | {
938 | "text": "Min",
939 | "value": "min"
940 | },
941 | {
942 | "text": "Max",
943 | "value": "max"
944 | },
945 | {
946 | "text": "Avg",
947 | "value": "avg"
948 | },
949 | {
950 | "text": "Current",
951 | "value": "current"
952 | }
953 | ],
954 | "datasource": null,
955 | "fontSize": "100%",
956 | "gridPos": {
957 | "h": 7,
958 | "w": 9,
959 | "x": 0,
960 | "y": 31
961 | },
962 | "id": 49,
963 | "options": {},
964 | "pageSize": null,
965 | "pluginVersion": "6.4.1",
966 | "scroll": true,
967 | "showHeader": true,
968 | "sort": {
969 | "col": 4,
970 | "desc": true
971 | },
972 | "styles": [
973 | {
974 | "alias": "Instance",
975 | "colorMode": null,
976 | "colors": [
977 | "rgba(245, 54, 54, 0.9)",
978 | "rgba(237, 129, 40, 0.89)",
979 | "rgba(50, 172, 45, 0.97)"
980 | ],
981 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
982 | "decimals": 0,
983 | "mappingType": 1,
984 | "pattern": "Metric",
985 | "thresholds": [],
986 | "type": "string",
987 | "unit": "short"
988 | },
989 | {
990 | "alias": "",
991 | "colorMode": null,
992 | "colors": [
993 | "rgba(245, 54, 54, 0.9)",
994 | "rgba(237, 129, 40, 0.89)",
995 | "rgba(50, 172, 45, 0.97)"
996 | ],
997 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
998 | "decimals": 1,
999 | "mappingType": 1,
1000 | "pattern": "/.*/",
1001 | "thresholds": [],
1002 | "type": "number",
1003 | "unit": "short"
1004 | }
1005 | ],
1006 | "targets": [
1007 | {
1008 | "expr": "perftest_published{instance=~\"$instance\"}",
1009 | "legendFormat": "{{instance}}",
1010 | "refId": "A"
1011 | }
1012 | ],
1013 | "timeFrom": null,
1014 | "timeShift": null,
1015 | "title": "Messages published / s",
1016 | "transform": "timeseries_aggregations",
1017 | "type": "table"
1018 | },
1019 | {
1020 | "aliasColors": {},
1021 | "bars": false,
1022 | "dashLength": 10,
1023 | "dashes": false,
1024 | "datasource": null,
1025 | "fill": 1,
1026 | "fillGradient": 0,
1027 | "gridPos": {
1028 | "h": 7,
1029 | "w": 15,
1030 | "x": 9,
1031 | "y": 31
1032 | },
1033 | "id": 51,
1034 | "legend": {
1035 | "alignAsTable": true,
1036 | "avg": true,
1037 | "current": true,
1038 | "max": true,
1039 | "min": true,
1040 | "rightSide": false,
1041 | "show": false,
1042 | "sort": "avg",
1043 | "sortDesc": true,
1044 | "total": false,
1045 | "values": true
1046 | },
1047 | "lines": true,
1048 | "linewidth": 1,
1049 | "links": [],
1050 | "nullPointMode": "null",
1051 | "options": {
1052 | "dataLinks": []
1053 | },
1054 | "percentage": false,
1055 | "pointradius": 5,
1056 | "points": false,
1057 | "renderer": "flot",
1058 | "seriesOverrides": [],
1059 | "spaceLength": 10,
1060 | "stack": false,
1061 | "steppedLine": false,
1062 | "targets": [
1063 | {
1064 | "expr": "perftest_published{instance=~\"$instance\"}",
1065 | "format": "time_series",
1066 | "intervalFactor": 1,
1067 | "legendFormat": "{{instance}}",
1068 | "refId": "A"
1069 | }
1070 | ],
1071 | "thresholds": [],
1072 | "timeFrom": null,
1073 | "timeRegions": [],
1074 | "timeShift": null,
1075 | "title": "Messages published / s",
1076 | "tooltip": {
1077 | "shared": true,
1078 | "sort": 2,
1079 | "value_type": "individual"
1080 | },
1081 | "transparent": true,
1082 | "type": "graph",
1083 | "xaxis": {
1084 | "buckets": null,
1085 | "mode": "time",
1086 | "name": null,
1087 | "show": true,
1088 | "values": []
1089 | },
1090 | "yaxes": [
1091 | {
1092 | "decimals": null,
1093 | "format": "short",
1094 | "label": "",
1095 | "logBase": 1,
1096 | "max": null,
1097 | "min": "0",
1098 | "show": true
1099 | },
1100 | {
1101 | "format": "short",
1102 | "label": null,
1103 | "logBase": 1,
1104 | "max": null,
1105 | "min": null,
1106 | "show": true
1107 | }
1108 | ],
1109 | "yaxis": {
1110 | "align": false,
1111 | "alignLevel": null
1112 | }
1113 | },
1114 | {
1115 | "columns": [
1116 | {
1117 | "text": "Min",
1118 | "value": "min"
1119 | },
1120 | {
1121 | "text": "Max",
1122 | "value": "max"
1123 | },
1124 | {
1125 | "text": "Avg",
1126 | "value": "avg"
1127 | },
1128 | {
1129 | "text": "Current",
1130 | "value": "current"
1131 | }
1132 | ],
1133 | "datasource": null,
1134 | "fontSize": "100%",
1135 | "gridPos": {
1136 | "h": 7,
1137 | "w": 9,
1138 | "x": 0,
1139 | "y": 38
1140 | },
1141 | "id": 55,
1142 | "options": {},
1143 | "pageSize": null,
1144 | "pluginVersion": "6.4.1",
1145 | "scroll": true,
1146 | "showHeader": true,
1147 | "sort": {
1148 | "col": 4,
1149 | "desc": true
1150 | },
1151 | "styles": [
1152 | {
1153 | "alias": "Instance",
1154 | "colorMode": null,
1155 | "colors": [
1156 | "rgba(245, 54, 54, 0.9)",
1157 | "rgba(237, 129, 40, 0.89)",
1158 | "rgba(50, 172, 45, 0.97)"
1159 | ],
1160 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1161 | "decimals": 0,
1162 | "mappingType": 1,
1163 | "pattern": "Metric",
1164 | "thresholds": [],
1165 | "type": "string",
1166 | "unit": "short"
1167 | },
1168 | {
1169 | "alias": "",
1170 | "colorMode": null,
1171 | "colors": [
1172 | "rgba(245, 54, 54, 0.9)",
1173 | "rgba(237, 129, 40, 0.89)",
1174 | "rgba(50, 172, 45, 0.97)"
1175 | ],
1176 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1177 | "decimals": 0,
1178 | "mappingType": 1,
1179 | "pattern": "/.*/",
1180 | "thresholds": [],
1181 | "type": "number",
1182 | "unit": "short"
1183 | }
1184 | ],
1185 | "targets": [
1186 | {
1187 | "expr": "perftest_consumed{instance=~\"$instance\"}",
1188 | "legendFormat": "{{instance}}",
1189 | "refId": "A"
1190 | }
1191 | ],
1192 | "timeFrom": null,
1193 | "timeShift": null,
1194 | "title": "Messages consumed / s",
1195 | "transform": "timeseries_aggregations",
1196 | "type": "table"
1197 | },
1198 | {
1199 | "aliasColors": {},
1200 | "bars": false,
1201 | "dashLength": 10,
1202 | "dashes": false,
1203 | "datasource": null,
1204 | "fill": 1,
1205 | "fillGradient": 0,
1206 | "gridPos": {
1207 | "h": 7,
1208 | "w": 15,
1209 | "x": 9,
1210 | "y": 38
1211 | },
1212 | "id": 53,
1213 | "legend": {
1214 | "alignAsTable": true,
1215 | "avg": true,
1216 | "current": true,
1217 | "max": true,
1218 | "min": true,
1219 | "rightSide": false,
1220 | "show": false,
1221 | "sort": "avg",
1222 | "sortDesc": true,
1223 | "total": false,
1224 | "values": true
1225 | },
1226 | "lines": true,
1227 | "linewidth": 1,
1228 | "links": [],
1229 | "nullPointMode": "null",
1230 | "options": {
1231 | "dataLinks": []
1232 | },
1233 | "percentage": false,
1234 | "pointradius": 5,
1235 | "points": false,
1236 | "renderer": "flot",
1237 | "seriesOverrides": [],
1238 | "spaceLength": 10,
1239 | "stack": false,
1240 | "steppedLine": false,
1241 | "targets": [
1242 | {
1243 | "expr": "perftest_consumed{instance=~\"$instance\"}",
1244 | "format": "time_series",
1245 | "intervalFactor": 1,
1246 | "legendFormat": "{{instance}}",
1247 | "refId": "A"
1248 | }
1249 | ],
1250 | "thresholds": [],
1251 | "timeFrom": null,
1252 | "timeRegions": [],
1253 | "timeShift": null,
1254 | "title": "Messages consumed / s",
1255 | "tooltip": {
1256 | "shared": true,
1257 | "sort": 2,
1258 | "value_type": "individual"
1259 | },
1260 | "transparent": true,
1261 | "type": "graph",
1262 | "xaxis": {
1263 | "buckets": null,
1264 | "mode": "time",
1265 | "name": null,
1266 | "show": true,
1267 | "values": []
1268 | },
1269 | "yaxes": [
1270 | {
1271 | "decimals": null,
1272 | "format": "short",
1273 | "label": "",
1274 | "logBase": 1,
1275 | "max": null,
1276 | "min": "0",
1277 | "show": true
1278 | },
1279 | {
1280 | "format": "short",
1281 | "label": null,
1282 | "logBase": 1,
1283 | "max": null,
1284 | "min": null,
1285 | "show": true
1286 | }
1287 | ],
1288 | "yaxis": {
1289 | "align": false,
1290 | "alignLevel": null
1291 | }
1292 | },
1293 | {
1294 | "columns": [
1295 | {
1296 | "text": "Min",
1297 | "value": "min"
1298 | },
1299 | {
1300 | "text": "Max",
1301 | "value": "max"
1302 | },
1303 | {
1304 | "text": "Avg",
1305 | "value": "avg"
1306 | },
1307 | {
1308 | "text": "Current",
1309 | "value": "current"
1310 | }
1311 | ],
1312 | "datasource": null,
1313 | "fontSize": "100%",
1314 | "gridPos": {
1315 | "h": 7,
1316 | "w": 9,
1317 | "x": 0,
1318 | "y": 45
1319 | },
1320 | "id": 47,
1321 | "options": {},
1322 | "pageSize": null,
1323 | "pluginVersion": "6.4.1",
1324 | "scroll": true,
1325 | "showHeader": true,
1326 | "sort": {
1327 | "col": 4,
1328 | "desc": true
1329 | },
1330 | "styles": [
1331 | {
1332 | "alias": "Instance",
1333 | "colorMode": null,
1334 | "colors": [
1335 | "rgba(245, 54, 54, 0.9)",
1336 | "rgba(237, 129, 40, 0.89)",
1337 | "rgba(50, 172, 45, 0.97)"
1338 | ],
1339 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1340 | "decimals": 0,
1341 | "mappingType": 1,
1342 | "pattern": "Metric",
1343 | "thresholds": [],
1344 | "type": "string",
1345 | "unit": "short"
1346 | },
1347 | {
1348 | "alias": "",
1349 | "colorMode": null,
1350 | "colors": [
1351 | "rgba(245, 54, 54, 0.9)",
1352 | "rgba(237, 129, 40, 0.89)",
1353 | "rgba(50, 172, 45, 0.97)"
1354 | ],
1355 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1356 | "decimals": 1,
1357 | "mappingType": 1,
1358 | "pattern": "/.*/",
1359 | "thresholds": [],
1360 | "type": "number",
1361 | "unit": "s"
1362 | }
1363 | ],
1364 | "targets": [
1365 | {
1366 | "expr": "perftest_latency_seconds{quantile=\"$percentile\", instance=~\"$instance\"}",
1367 | "legendFormat": "{{instance}}",
1368 | "refId": "A"
1369 | }
1370 | ],
1371 | "timeFrom": null,
1372 | "timeShift": null,
1373 | "title": "End-to-end message latency",
1374 | "transform": "timeseries_aggregations",
1375 | "type": "table"
1376 | },
1377 | {
1378 | "aliasColors": {},
1379 | "bars": false,
1380 | "dashLength": 10,
1381 | "dashes": false,
1382 | "datasource": null,
1383 | "fill": 1,
1384 | "fillGradient": 0,
1385 | "gridPos": {
1386 | "h": 7,
1387 | "w": 15,
1388 | "x": 9,
1389 | "y": 45
1390 | },
1391 | "id": 45,
1392 | "legend": {
1393 | "alignAsTable": true,
1394 | "avg": true,
1395 | "current": true,
1396 | "max": true,
1397 | "min": true,
1398 | "rightSide": false,
1399 | "show": false,
1400 | "sort": "avg",
1401 | "sortDesc": true,
1402 | "total": false,
1403 | "values": true
1404 | },
1405 | "lines": true,
1406 | "linewidth": 1,
1407 | "links": [],
1408 | "nullPointMode": "null",
1409 | "options": {
1410 | "dataLinks": []
1411 | },
1412 | "percentage": false,
1413 | "pointradius": 5,
1414 | "points": false,
1415 | "renderer": "flot",
1416 | "seriesOverrides": [],
1417 | "spaceLength": 10,
1418 | "stack": false,
1419 | "steppedLine": false,
1420 | "targets": [
1421 | {
1422 | "expr": "perftest_latency_seconds{quantile=\"$percentile\", instance=~\"$instance\"}",
1423 | "format": "time_series",
1424 | "instant": false,
1425 | "interval": "1s",
1426 | "intervalFactor": 1,
1427 | "legendFormat": "{{instance}}",
1428 | "refId": "A"
1429 | }
1430 | ],
1431 | "thresholds": [],
1432 | "timeFrom": null,
1433 | "timeRegions": [],
1434 | "timeShift": null,
1435 | "title": "End-to-end message latency",
1436 | "tooltip": {
1437 | "shared": true,
1438 | "sort": 2,
1439 | "value_type": "individual"
1440 | },
1441 | "transparent": true,
1442 | "type": "graph",
1443 | "xaxis": {
1444 | "buckets": null,
1445 | "mode": "time",
1446 | "name": null,
1447 | "show": true,
1448 | "values": []
1449 | },
1450 | "yaxes": [
1451 | {
1452 | "format": "s",
1453 | "label": null,
1454 | "logBase": 1,
1455 | "max": null,
1456 | "min": "0",
1457 | "show": true
1458 | },
1459 | {
1460 | "format": "short",
1461 | "label": null,
1462 | "logBase": 1,
1463 | "max": null,
1464 | "min": null,
1465 | "show": true
1466 | }
1467 | ],
1468 | "yaxis": {
1469 | "align": false,
1470 | "alignLevel": null
1471 | }
1472 | },
1473 | {
1474 | "aliasColors": {},
1475 | "bars": true,
1476 | "dashLength": 10,
1477 | "dashes": false,
1478 | "datasource": null,
1479 | "fill": 1,
1480 | "fillGradient": 0,
1481 | "gridPos": {
1482 | "h": 8,
1483 | "w": 9,
1484 | "x": 0,
1485 | "y": 52
1486 | },
1487 | "id": 43,
1488 | "legend": {
1489 | "alignAsTable": true,
1490 | "avg": true,
1491 | "current": true,
1492 | "max": true,
1493 | "min": true,
1494 | "rightSide": false,
1495 | "show": false,
1496 | "sort": "max",
1497 | "sortDesc": true,
1498 | "total": false,
1499 | "values": true
1500 | },
1501 | "lines": false,
1502 | "linewidth": 1,
1503 | "links": [],
1504 | "nullPointMode": "null",
1505 | "options": {
1506 | "dataLinks": []
1507 | },
1508 | "percentage": false,
1509 | "pointradius": 5,
1510 | "points": false,
1511 | "renderer": "flot",
1512 | "seriesOverrides": [],
1513 | "spaceLength": 10,
1514 | "stack": false,
1515 | "steppedLine": false,
1516 | "targets": [
1517 | {
1518 | "expr": "perftest_latency_seconds{quantile=\"$percentile\", instance=~\"$instance\"}",
1519 | "format": "time_series",
1520 | "intervalFactor": 1,
1521 | "legendFormat": "{{instance}}",
1522 | "refId": "A"
1523 | }
1524 | ],
1525 | "thresholds": [],
1526 | "timeFrom": null,
1527 | "timeRegions": [],
1528 | "timeShift": null,
1529 | "title": "End-to-end message latency distribution",
1530 | "tooltip": {
1531 | "shared": false,
1532 | "sort": 0,
1533 | "value_type": "individual"
1534 | },
1535 | "transparent": true,
1536 | "type": "graph",
1537 | "xaxis": {
1538 | "buckets": 20,
1539 | "mode": "histogram",
1540 | "name": null,
1541 | "show": true,
1542 | "values": []
1543 | },
1544 | "yaxes": [
1545 | {
1546 | "format": "none",
1547 | "label": "",
1548 | "logBase": 1,
1549 | "max": null,
1550 | "min": "0",
1551 | "show": true
1552 | },
1553 | {
1554 | "format": "short",
1555 | "label": null,
1556 | "logBase": 1,
1557 | "max": null,
1558 | "min": null,
1559 | "show": false
1560 | }
1561 | ],
1562 | "yaxis": {
1563 | "align": false,
1564 | "alignLevel": null
1565 | }
1566 | },
1567 | {
1568 | "cards": {
1569 | "cardPadding": null,
1570 | "cardRound": null
1571 | },
1572 | "color": {
1573 | "cardColor": "rgb(255, 255, 255)",
1574 | "colorScale": "sqrt",
1575 | "colorScheme": "interpolateBlues",
1576 | "exponent": 0.4,
1577 | "max": null,
1578 | "min": null,
1579 | "mode": "opacity"
1580 | },
1581 | "dataFormat": "timeseries",
1582 | "datasource": null,
1583 | "gridPos": {
1584 | "h": 8,
1585 | "w": 15,
1586 | "x": 9,
1587 | "y": 52
1588 | },
1589 | "heatmap": {},
1590 | "hideZeroBuckets": true,
1591 | "highlightCards": true,
1592 | "id": 41,
1593 | "legend": {
1594 | "show": true
1595 | },
1596 | "links": [],
1597 | "options": {},
1598 | "reverseYBuckets": false,
1599 | "targets": [
1600 | {
1601 | "expr": "perftest_latency_seconds{quantile=\"$percentile\", instance=~\"$instance\"}",
1602 | "format": "heatmap",
1603 | "intervalFactor": 1,
1604 | "refId": "A"
1605 | }
1606 | ],
1607 | "title": "End-to-end message latency distribution",
1608 | "tooltip": {
1609 | "show": true,
1610 | "showHistogram": true
1611 | },
1612 | "transparent": true,
1613 | "type": "heatmap",
1614 | "xAxis": {
1615 | "show": true
1616 | },
1617 | "xBucketNumber": null,
1618 | "xBucketSize": null,
1619 | "yAxis": {
1620 | "decimals": null,
1621 | "format": "s",
1622 | "logBase": 1,
1623 | "max": null,
1624 | "min": "0",
1625 | "show": true,
1626 | "splitFactor": null
1627 | },
1628 | "yBucketBound": "auto",
1629 | "yBucketNumber": null,
1630 | "yBucketSize": null
1631 | }
1632 | ],
1633 | "refresh": "15s",
1634 | "schemaVersion": 20,
1635 | "style": "dark",
1636 | "tags": [
1637 | "cadvisor",
1638 | "node-exporter",
1639 | "rabbitmq-perf-test",
1640 | "rabbitmq-prometheus"
1641 | ],
1642 | "templating": {
1643 | "list": [
1644 | {
1645 | "current": {
1646 | "selected": false,
1647 | "text": "default",
1648 | "value": "default"
1649 | },
1650 | "hide": 2,
1651 | "includeAll": false,
1652 | "label": "datasource",
1653 | "multi": false,
1654 | "name": "DS_PROMETHEUS",
1655 | "options": [],
1656 | "query": "prometheus",
1657 | "refresh": 1,
1658 | "regex": "",
1659 | "skipUrlSync": false,
1660 | "type": "datasource"
1661 | },
1662 | {
1663 | "allValue": null,
1664 | "current": {},
1665 | "datasource": null,
1666 | "definition": "label_values(rabbitmq_identity_info, namespace)",
1667 | "hide": 0,
1668 | "includeAll": false,
1669 | "label": "Namespace",
1670 | "multi": false,
1671 | "name": "namespace",
1672 | "options": [],
1673 | "query": "label_values(rabbitmq_identity_info, namespace)",
1674 | "refresh": 2,
1675 | "regex": "",
1676 | "skipUrlSync": false,
1677 | "sort": 1,
1678 | "tagValuesQuery": "",
1679 | "tags": [],
1680 | "tagsQuery": "",
1681 | "type": "query",
1682 | "useTags": false
1683 | },
1684 | {
1685 | "allValue": null,
1686 | "current": {
1687 | "text": "All",
1688 | "value": [
1689 | "$__all"
1690 | ]
1691 | },
1692 | "datasource": null,
1693 | "definition": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)",
1694 | "hide": 0,
1695 | "includeAll": true,
1696 | "label": "RabbitMQ Cluster",
1697 | "multi": true,
1698 | "name": "rabbitmq_cluster",
1699 | "options": [],
1700 | "query": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)",
1701 | "refresh": 2,
1702 | "regex": "",
1703 | "skipUrlSync": false,
1704 | "sort": 1,
1705 | "tagValuesQuery": "",
1706 | "tags": [],
1707 | "tagsQuery": "",
1708 | "type": "query",
1709 | "useTags": false
1710 | },
1711 | {
1712 | "allValue": null,
1713 | "current": {
1714 | "text": "All",
1715 | "value": [
1716 | "$__all"
1717 | ]
1718 | },
1719 | "datasource": null,
1720 | "definition": "label_values(perftest_published, instance)",
1721 | "hide": 0,
1722 | "includeAll": true,
1723 | "label": "PerfTest Instance",
1724 | "multi": true,
1725 | "name": "instance",
1726 | "options": [],
1727 | "query": "label_values(perftest_published, instance)",
1728 | "refresh": 2,
1729 | "regex": "",
1730 | "skipUrlSync": false,
1731 | "sort": 1,
1732 | "tagValuesQuery": "",
1733 | "tags": [],
1734 | "tagsQuery": "",
1735 | "type": "query",
1736 | "useTags": false
1737 | },
1738 | {
1739 | "allValue": null,
1740 | "current": {
1741 | "text": "0.99",
1742 | "value": "0.99"
1743 | },
1744 | "datasource": null,
1745 | "definition": "label_values(perftest_latency_seconds, quantile)",
1746 | "hide": 0,
1747 | "includeAll": false,
1748 | "label": "Percentile",
1749 | "multi": false,
1750 | "name": "percentile",
1751 | "options": [],
1752 | "query": "label_values(perftest_latency_seconds, quantile)",
1753 | "refresh": 2,
1754 | "regex": "",
1755 | "skipUrlSync": false,
1756 | "sort": 4,
1757 | "tagValuesQuery": "",
1758 | "tags": [],
1759 | "tagsQuery": "",
1760 | "type": "query",
1761 | "useTags": false
1762 | },
1763 | {
1764 | "allValue": null,
1765 | "current": {
1766 | "text": "All",
1767 | "value": [
1768 | "$__all"
1769 | ]
1770 | },
1771 | "datasource": null,
1772 | "definition": "label_values(node_network_info, instance)",
1773 | "hide": 0,
1774 | "includeAll": true,
1775 | "label": "Host",
1776 | "multi": true,
1777 | "name": "host",
1778 | "options": [],
1779 | "query": "label_values(node_network_info, instance)",
1780 | "refresh": 2,
1781 | "regex": "",
1782 | "skipUrlSync": false,
1783 | "sort": 1,
1784 | "tagValuesQuery": "",
1785 | "tags": [],
1786 | "tagsQuery": "",
1787 | "type": "query",
1788 | "useTags": false
1789 | },
1790 | {
1791 | "allValue": null,
1792 | "current": {
1793 | "text": "All",
1794 | "value": [
1795 | "$__all"
1796 | ]
1797 | },
1798 | "datasource": null,
1799 | "definition": "label_values(container_network_receive_bytes_total, name)",
1800 | "hide": 0,
1801 | "includeAll": true,
1802 | "label": "or Container",
1803 | "multi": true,
1804 | "name": "container",
1805 | "options": [],
1806 | "query": "label_values(container_network_receive_bytes_total, name)",
1807 | "refresh": 2,
1808 | "regex": "",
1809 | "skipUrlSync": false,
1810 | "sort": 1,
1811 | "tagValuesQuery": "",
1812 | "tags": [],
1813 | "tagsQuery": "",
1814 | "type": "query",
1815 | "useTags": false
1816 | }
1817 | ]
1818 | },
1819 | "time": {
1820 | "from": "now-15m",
1821 | "to": "now"
1822 | },
1823 | "timepicker": {
1824 | "refresh_intervals": [
1825 | "15s",
1826 | "30s",
1827 | "1m",
1828 | "5m",
1829 | "10m"
1830 | ],
1831 | "time_options": [
1832 | "5m",
1833 | "15m",
1834 | "1h",
1835 | "6h",
1836 | "12h",
1837 | "24h",
1838 | "2d",
1839 | "7d",
1840 | "30d"
1841 | ]
1842 | },
1843 | "timezone": "",
1844 | "title": "Erlang-Distributions-Compare",
1845 | "uid": "C0jeDstZk",
1846 | "version": 20210322
1847 | }
1848 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/grafana/dashboards/RabbitMQ-PerfTest.json:
--------------------------------------------------------------------------------
1 | {
2 | "__requires": [
3 | {
4 | "type": "grafana",
5 | "id": "grafana",
6 | "name": "Grafana",
7 | "version": "7.0.0"
8 | },
9 | {
10 | "type": "datasource",
11 | "id": "prometheus",
12 | "name": "prometheus",
13 | "version": "2.0.0"
14 | },
15 | {
16 | "type": "table",
17 | "id": "table",
18 | "name": "Table",
19 | "version": ""
20 | },
21 | {
22 | "type": "panel",
23 | "id": "graph",
24 | "name": "Graph",
25 | "version": ""
26 | },
27 | {
28 | "type": "panel",
29 | "id": "heatmap",
30 | "name": "Heatmap",
31 | "version": ""
32 | }
33 | ],
34 | "annotations": {
35 | "list": [
36 | {
37 | "builtIn": 1,
38 | "datasource": "-- Grafana --",
39 | "enable": true,
40 | "hide": true,
41 | "iconColor": "rgba(0, 211, 255, 1)",
42 | "name": "Annotations & Alerts",
43 | "type": "dashboard"
44 | }
45 | ]
46 | },
47 | "editable": true,
48 | "gnetId": null,
49 | "graphTooltip": 1,
50 | "iteration": 1570184644782,
51 | "links": [],
52 | "panels": [
53 | {
54 | "collapsed": false,
55 | "datasource": null,
56 | "description": "RabbitMQ message latency & throughput across all PerfTest instances",
57 | "gridPos": {
58 | "h": 1,
59 | "w": 24,
60 | "x": 0,
61 | "y": 0
62 | },
63 | "id": 22,
64 | "panels": [],
65 | "title": "LATENCY",
66 | "type": "row"
67 | },
68 | {
69 | "columns": [
70 | {
71 | "text": "Min",
72 | "value": "min"
73 | },
74 | {
75 | "text": "Max",
76 | "value": "max"
77 | },
78 | {
79 | "text": "Avg",
80 | "value": "avg"
81 | },
82 | {
83 | "text": "Current",
84 | "value": "current"
85 | }
86 | ],
87 | "datasource": null,
88 | "fontSize": "100%",
89 | "gridPos": {
90 | "h": 7,
91 | "w": 6,
92 | "x": 0,
93 | "y": 1
94 | },
95 | "id": 33,
96 | "options": {},
97 | "pageSize": 5,
98 | "pluginVersion": "6.4.1",
99 | "showHeader": true,
100 | "sort": {
101 | "col": 4,
102 | "desc": true
103 | },
104 | "styles": [
105 | {
106 | "alias": "Instance",
107 | "colorMode": null,
108 | "colors": [
109 | "rgba(245, 54, 54, 0.9)",
110 | "rgba(237, 129, 40, 0.89)",
111 | "rgba(50, 172, 45, 0.97)"
112 | ],
113 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
114 | "decimals": 0,
115 | "mappingType": 1,
116 | "pattern": "Metric",
117 | "thresholds": [],
118 | "type": "string",
119 | "unit": "short"
120 | },
121 | {
122 | "alias": "",
123 | "colorMode": null,
124 | "colors": [
125 | "rgba(245, 54, 54, 0.9)",
126 | "rgba(237, 129, 40, 0.89)",
127 | "rgba(50, 172, 45, 0.97)"
128 | ],
129 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
130 | "decimals": 1,
131 | "mappingType": 1,
132 | "pattern": "/.*/",
133 | "thresholds": [],
134 | "type": "number",
135 | "unit": "s"
136 | }
137 | ],
138 | "targets": [
139 | {
140 | "expr": "perftest_latency_seconds{quantile=\"$percentile\"}",
141 | "legendFormat": "{{instance}}",
142 | "refId": "A"
143 | }
144 | ],
145 | "timeFrom": null,
146 | "timeShift": null,
147 | "title": "End-to-end message latency",
148 | "transform": "timeseries_aggregations",
149 | "type": "table"
150 | },
151 | {
152 | "aliasColors": {},
153 | "bars": false,
154 | "dashLength": 10,
155 | "dashes": false,
156 | "datasource": null,
157 | "fill": 1,
158 | "fillGradient": 0,
159 | "gridPos": {
160 | "h": 7,
161 | "w": 6,
162 | "x": 6,
163 | "y": 1
164 | },
165 | "id": 2,
166 | "legend": {
167 | "alignAsTable": true,
168 | "avg": true,
169 | "current": true,
170 | "max": true,
171 | "min": true,
172 | "rightSide": false,
173 | "show": false,
174 | "sort": "avg",
175 | "sortDesc": true,
176 | "total": false,
177 | "values": true
178 | },
179 | "lines": true,
180 | "linewidth": 1,
181 | "links": [],
182 | "nullPointMode": "null",
183 | "options": {
184 | "dataLinks": []
185 | },
186 | "percentage": false,
187 | "pointradius": 5,
188 | "points": false,
189 | "renderer": "flot",
190 | "seriesOverrides": [],
191 | "spaceLength": 10,
192 | "stack": false,
193 | "steppedLine": false,
194 | "targets": [
195 | {
196 | "expr": "perftest_latency_seconds{quantile=\"$percentile\",instance=~\"$instance\"}",
197 | "format": "time_series",
198 | "instant": false,
199 | "interval": "1s",
200 | "intervalFactor": 1,
201 | "legendFormat": "{{instance}}",
202 | "refId": "A"
203 | }
204 | ],
205 | "thresholds": [],
206 | "timeFrom": null,
207 | "timeRegions": [],
208 | "timeShift": null,
209 | "title": "End-to-end message latency",
210 | "tooltip": {
211 | "shared": true,
212 | "sort": 2,
213 | "value_type": "individual"
214 | },
215 | "transparent": true,
216 | "type": "graph",
217 | "xaxis": {
218 | "buckets": null,
219 | "mode": "time",
220 | "name": null,
221 | "show": true,
222 | "values": []
223 | },
224 | "yaxes": [
225 | {
226 | "format": "s",
227 | "label": null,
228 | "logBase": 1,
229 | "max": null,
230 | "min": "0",
231 | "show": true
232 | },
233 | {
234 | "format": "short",
235 | "label": null,
236 | "logBase": 1,
237 | "max": null,
238 | "min": null,
239 | "show": true
240 | }
241 | ],
242 | "yaxis": {
243 | "align": false,
244 | "alignLevel": null
245 | }
246 | },
247 | {
248 | "cards": {
249 | "cardPadding": null,
250 | "cardRound": null
251 | },
252 | "color": {
253 | "cardColor": "rgb(255, 255, 255)",
254 | "colorScale": "sqrt",
255 | "colorScheme": "interpolateSpectral",
256 | "exponent": 0.4,
257 | "max": null,
258 | "min": null,
259 | "mode": "opacity"
260 | },
261 | "dataFormat": "timeseries",
262 | "datasource": null,
263 | "gridPos": {
264 | "h": 7,
265 | "w": 6,
266 | "x": 12,
267 | "y": 1
268 | },
269 | "heatmap": {},
270 | "hideZeroBuckets": false,
271 | "highlightCards": true,
272 | "id": 16,
273 | "legend": {
274 | "show": true
275 | },
276 | "links": [],
277 | "options": {},
278 | "reverseYBuckets": false,
279 | "targets": [
280 | {
281 | "expr": "perftest_latency_seconds{quantile=\"$percentile\",instance=~\"$instance\"} > 0",
282 | "format": "heatmap",
283 | "intervalFactor": 1,
284 | "refId": "A"
285 | }
286 | ],
287 | "title": "End-to-end message latency distribution",
288 | "tooltip": {
289 | "show": true,
290 | "showHistogram": true
291 | },
292 | "transparent": true,
293 | "type": "heatmap",
294 | "xAxis": {
295 | "show": true
296 | },
297 | "xBucketNumber": null,
298 | "xBucketSize": null,
299 | "yAxis": {
300 | "decimals": null,
301 | "format": "s",
302 | "logBase": 1,
303 | "max": null,
304 | "min": "0",
305 | "show": true,
306 | "splitFactor": null
307 | },
308 | "yBucketBound": "auto",
309 | "yBucketNumber": null,
310 | "yBucketSize": null
311 | },
312 | {
313 | "aliasColors": {},
314 | "bars": true,
315 | "dashLength": 10,
316 | "dashes": false,
317 | "datasource": null,
318 | "fill": 1,
319 | "fillGradient": 0,
320 | "gridPos": {
321 | "h": 7,
322 | "w": 6,
323 | "x": 18,
324 | "y": 1
325 | },
326 | "id": 17,
327 | "legend": {
328 | "alignAsTable": true,
329 | "avg": true,
330 | "current": true,
331 | "max": true,
332 | "min": true,
333 | "rightSide": false,
334 | "show": false,
335 | "sort": "max",
336 | "sortDesc": true,
337 | "total": false,
338 | "values": true
339 | },
340 | "lines": false,
341 | "linewidth": 1,
342 | "links": [],
343 | "nullPointMode": "null",
344 | "options": {
345 | "dataLinks": []
346 | },
347 | "percentage": false,
348 | "pointradius": 5,
349 | "points": false,
350 | "renderer": "flot",
351 | "seriesOverrides": [],
352 | "spaceLength": 10,
353 | "stack": false,
354 | "steppedLine": false,
355 | "targets": [
356 | {
357 | "expr": "perftest_latency_seconds{quantile=\"$percentile\",instance=~\"$instance\"} > 0",
358 | "format": "time_series",
359 | "intervalFactor": 1,
360 | "legendFormat": "{{instance}}",
361 | "refId": "A"
362 | }
363 | ],
364 | "thresholds": [],
365 | "timeFrom": null,
366 | "timeRegions": [],
367 | "timeShift": null,
368 | "title": "End-to-end message latency distribution",
369 | "tooltip": {
370 | "shared": false,
371 | "sort": 0,
372 | "value_type": "individual"
373 | },
374 | "transparent": true,
375 | "type": "graph",
376 | "xaxis": {
377 | "buckets": 20,
378 | "mode": "histogram",
379 | "name": null,
380 | "show": true,
381 | "values": []
382 | },
383 | "yaxes": [
384 | {
385 | "format": "none",
386 | "label": "",
387 | "logBase": 1,
388 | "max": null,
389 | "min": "0",
390 | "show": true
391 | },
392 | {
393 | "format": "short",
394 | "label": null,
395 | "logBase": 1,
396 | "max": null,
397 | "min": null,
398 | "show": false
399 | }
400 | ],
401 | "yaxis": {
402 | "align": false,
403 | "alignLevel": null
404 | }
405 | },
406 | {
407 | "columns": [
408 | {
409 | "text": "Min",
410 | "value": "min"
411 | },
412 | {
413 | "text": "Max",
414 | "value": "max"
415 | },
416 | {
417 | "text": "Avg",
418 | "value": "avg"
419 | },
420 | {
421 | "text": "Current",
422 | "value": "current"
423 | }
424 | ],
425 | "datasource": null,
426 | "fontSize": "100%",
427 | "gridPos": {
428 | "h": 7,
429 | "w": 6,
430 | "x": 0,
431 | "y": 8
432 | },
433 | "id": 34,
434 | "options": {},
435 | "pageSize": 5,
436 | "pluginVersion": "6.4.1",
437 | "showHeader": true,
438 | "sort": {
439 | "col": 4,
440 | "desc": true
441 | },
442 | "styles": [
443 | {
444 | "alias": "Instance",
445 | "colorMode": null,
446 | "colors": [
447 | "rgba(245, 54, 54, 0.9)",
448 | "rgba(237, 129, 40, 0.89)",
449 | "rgba(50, 172, 45, 0.97)"
450 | ],
451 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
452 | "decimals": 0,
453 | "mappingType": 1,
454 | "pattern": "Metric",
455 | "thresholds": [],
456 | "type": "string",
457 | "unit": "short"
458 | },
459 | {
460 | "alias": "",
461 | "colorMode": null,
462 | "colors": [
463 | "rgba(245, 54, 54, 0.9)",
464 | "rgba(237, 129, 40, 0.89)",
465 | "rgba(50, 172, 45, 0.97)"
466 | ],
467 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
468 | "decimals": 1,
469 | "mappingType": 1,
470 | "pattern": "/.*/",
471 | "thresholds": [],
472 | "type": "number",
473 | "unit": "s"
474 | }
475 | ],
476 | "targets": [
477 | {
478 | "expr": "perftest_confirm_latency_seconds{quantile=\"$percentile\"}",
479 | "legendFormat": "{{instance}}",
480 | "refId": "A"
481 | }
482 | ],
483 | "timeFrom": null,
484 | "timeShift": null,
485 | "title": "Publish confirm latency",
486 | "transform": "timeseries_aggregations",
487 | "type": "table"
488 | },
489 | {
490 | "aliasColors": {},
491 | "bars": false,
492 | "dashLength": 10,
493 | "dashes": false,
494 | "datasource": null,
495 | "fill": 1,
496 | "fillGradient": 0,
497 | "gridPos": {
498 | "h": 7,
499 | "w": 6,
500 | "x": 6,
501 | "y": 8
502 | },
503 | "id": 37,
504 | "legend": {
505 | "alignAsTable": true,
506 | "avg": true,
507 | "current": true,
508 | "max": true,
509 | "min": true,
510 | "rightSide": false,
511 | "show": false,
512 | "sort": "avg",
513 | "sortDesc": true,
514 | "total": false,
515 | "values": true
516 | },
517 | "lines": true,
518 | "linewidth": 1,
519 | "links": [],
520 | "nullPointMode": "null",
521 | "options": {
522 | "dataLinks": []
523 | },
524 | "percentage": false,
525 | "pointradius": 5,
526 | "points": false,
527 | "renderer": "flot",
528 | "seriesOverrides": [],
529 | "spaceLength": 10,
530 | "stack": false,
531 | "steppedLine": false,
532 | "targets": [
533 | {
534 | "expr": "perftest_confirm_latency_seconds{quantile=\"$percentile\",instance=~\"$instance\"}",
535 | "format": "time_series",
536 | "instant": false,
537 | "interval": "1s",
538 | "intervalFactor": 1,
539 | "legendFormat": "{{instance}}",
540 | "refId": "A"
541 | }
542 | ],
543 | "thresholds": [],
544 | "timeFrom": null,
545 | "timeRegions": [],
546 | "timeShift": null,
547 | "title": "Publish confirm latency",
548 | "tooltip": {
549 | "shared": true,
550 | "sort": 2,
551 | "value_type": "individual"
552 | },
553 | "transparent": true,
554 | "type": "graph",
555 | "xaxis": {
556 | "buckets": null,
557 | "mode": "time",
558 | "name": null,
559 | "show": true,
560 | "values": []
561 | },
562 | "yaxes": [
563 | {
564 | "format": "s",
565 | "label": null,
566 | "logBase": 1,
567 | "max": null,
568 | "min": "0",
569 | "show": true
570 | },
571 | {
572 | "format": "short",
573 | "label": null,
574 | "logBase": 1,
575 | "max": null,
576 | "min": null,
577 | "show": true
578 | }
579 | ],
580 | "yaxis": {
581 | "align": false,
582 | "alignLevel": null
583 | }
584 | },
585 | {
586 | "cards": {
587 | "cardPadding": null,
588 | "cardRound": null
589 | },
590 | "color": {
591 | "cardColor": "rgb(255, 255, 255)",
592 | "colorScale": "sqrt",
593 | "colorScheme": "interpolateSpectral",
594 | "exponent": 0.4,
595 | "max": null,
596 | "min": null,
597 | "mode": "opacity"
598 | },
599 | "dataFormat": "timeseries",
600 | "datasource": null,
601 | "gridPos": {
602 | "h": 7,
603 | "w": 6,
604 | "x": 12,
605 | "y": 8
606 | },
607 | "heatmap": {},
608 | "hideZeroBuckets": false,
609 | "highlightCards": true,
610 | "id": 38,
611 | "legend": {
612 | "show": true
613 | },
614 | "links": [],
615 | "options": {},
616 | "reverseYBuckets": false,
617 | "targets": [
618 | {
619 | "expr": "perftest_confirm_latency_seconds{quantile=\"$percentile\",instance=~\"$instance\"} > 0",
620 | "format": "heatmap",
621 | "intervalFactor": 1,
622 | "refId": "A"
623 | }
624 | ],
625 | "title": "Publish confirm latency distribution",
626 | "tooltip": {
627 | "show": true,
628 | "showHistogram": true
629 | },
630 | "transparent": true,
631 | "type": "heatmap",
632 | "xAxis": {
633 | "show": true
634 | },
635 | "xBucketNumber": null,
636 | "xBucketSize": null,
637 | "yAxis": {
638 | "decimals": null,
639 | "format": "s",
640 | "logBase": 1,
641 | "max": null,
642 | "min": "0",
643 | "show": true,
644 | "splitFactor": null
645 | },
646 | "yBucketBound": "auto",
647 | "yBucketNumber": null,
648 | "yBucketSize": null
649 | },
650 | {
651 | "aliasColors": {},
652 | "bars": true,
653 | "dashLength": 10,
654 | "dashes": false,
655 | "datasource": null,
656 | "fill": 1,
657 | "fillGradient": 0,
658 | "gridPos": {
659 | "h": 7,
660 | "w": 6,
661 | "x": 18,
662 | "y": 8
663 | },
664 | "id": 39,
665 | "legend": {
666 | "alignAsTable": true,
667 | "avg": true,
668 | "current": true,
669 | "max": true,
670 | "min": true,
671 | "rightSide": false,
672 | "show": false,
673 | "sort": "max",
674 | "sortDesc": true,
675 | "total": false,
676 | "values": true
677 | },
678 | "lines": false,
679 | "linewidth": 1,
680 | "links": [],
681 | "nullPointMode": "null",
682 | "options": {
683 | "dataLinks": []
684 | },
685 | "percentage": false,
686 | "pointradius": 5,
687 | "points": false,
688 | "renderer": "flot",
689 | "seriesOverrides": [],
690 | "spaceLength": 10,
691 | "stack": false,
692 | "steppedLine": false,
693 | "targets": [
694 | {
695 | "expr": "perftest_confirm_latency_seconds{quantile=\"$percentile\",instance=~\"$instance\"} > 0",
696 | "format": "time_series",
697 | "intervalFactor": 1,
698 | "legendFormat": "{{instance}}",
699 | "refId": "A"
700 | }
701 | ],
702 | "thresholds": [],
703 | "timeFrom": null,
704 | "timeRegions": [],
705 | "timeShift": null,
706 | "title": "Publish confirm latency distribution",
707 | "tooltip": {
708 | "shared": false,
709 | "sort": 2,
710 | "value_type": "individual"
711 | },
712 | "transparent": true,
713 | "type": "graph",
714 | "xaxis": {
715 | "buckets": 20,
716 | "mode": "histogram",
717 | "name": null,
718 | "show": true,
719 | "values": []
720 | },
721 | "yaxes": [
722 | {
723 | "format": "none",
724 | "label": "",
725 | "logBase": 1,
726 | "max": null,
727 | "min": null,
728 | "show": true
729 | },
730 | {
731 | "format": "short",
732 | "label": null,
733 | "logBase": 1,
734 | "max": null,
735 | "min": null,
736 | "show": false
737 | }
738 | ],
739 | "yaxis": {
740 | "align": false,
741 | "alignLevel": null
742 | }
743 | },
744 | {
745 | "collapsed": false,
746 | "datasource": null,
747 | "gridPos": {
748 | "h": 1,
749 | "w": 24,
750 | "x": 0,
751 | "y": 15
752 | },
753 | "id": 24,
754 | "panels": [],
755 | "title": "THROUGHPUT",
756 | "type": "row"
757 | },
758 | {
759 | "columns": [
760 | {
761 | "text": "Min",
762 | "value": "min"
763 | },
764 | {
765 | "text": "Max",
766 | "value": "max"
767 | },
768 | {
769 | "text": "Avg",
770 | "value": "avg"
771 | },
772 | {
773 | "text": "Current",
774 | "value": "current"
775 | }
776 | ],
777 | "datasource": null,
778 | "fontSize": "100%",
779 | "gridPos": {
780 | "h": 7,
781 | "w": 6,
782 | "x": 0,
783 | "y": 16
784 | },
785 | "id": 27,
786 | "options": {},
787 | "pageSize": 5,
788 | "pluginVersion": "6.4.1",
789 | "showHeader": true,
790 | "sort": {
791 | "col": 4,
792 | "desc": true
793 | },
794 | "styles": [
795 | {
796 | "alias": "Instance",
797 | "colorMode": null,
798 | "colors": [
799 | "rgba(245, 54, 54, 0.9)",
800 | "rgba(237, 129, 40, 0.89)",
801 | "rgba(50, 172, 45, 0.97)"
802 | ],
803 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
804 | "decimals": 0,
805 | "mappingType": 1,
806 | "pattern": "Metric",
807 | "thresholds": [],
808 | "type": "string",
809 | "unit": "short"
810 | },
811 | {
812 | "alias": "",
813 | "colorMode": null,
814 | "colors": [
815 | "rgba(245, 54, 54, 0.9)",
816 | "rgba(237, 129, 40, 0.89)",
817 | "rgba(50, 172, 45, 0.97)"
818 | ],
819 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
820 | "decimals": 0,
821 | "mappingType": 1,
822 | "pattern": "/.*/",
823 | "thresholds": [],
824 | "type": "number",
825 | "unit": "short"
826 | }
827 | ],
828 | "targets": [
829 | {
830 | "expr": "perftest_published",
831 | "legendFormat": "{{instance}}",
832 | "refId": "A"
833 | }
834 | ],
835 | "timeFrom": null,
836 | "timeShift": null,
837 | "title": "Messages published / s",
838 | "transform": "timeseries_aggregations",
839 | "type": "table"
840 | },
841 | {
842 | "aliasColors": {},
843 | "bars": false,
844 | "dashLength": 10,
845 | "dashes": false,
846 | "datasource": null,
847 | "fill": 1,
848 | "fillGradient": 0,
849 | "gridPos": {
850 | "h": 7,
851 | "w": 6,
852 | "x": 6,
853 | "y": 16
854 | },
855 | "id": 19,
856 | "legend": {
857 | "alignAsTable": true,
858 | "avg": true,
859 | "current": true,
860 | "max": true,
861 | "min": true,
862 | "rightSide": false,
863 | "show": false,
864 | "sort": "avg",
865 | "sortDesc": true,
866 | "total": false,
867 | "values": true
868 | },
869 | "lines": true,
870 | "linewidth": 1,
871 | "links": [],
872 | "nullPointMode": "null",
873 | "options": {
874 | "dataLinks": []
875 | },
876 | "percentage": false,
877 | "pointradius": 5,
878 | "points": false,
879 | "renderer": "flot",
880 | "seriesOverrides": [],
881 | "spaceLength": 10,
882 | "stack": false,
883 | "steppedLine": false,
884 | "targets": [
885 | {
886 | "expr": "perftest_published{instance=~\"$instance\"}",
887 | "format": "time_series",
888 | "intervalFactor": 1,
889 | "legendFormat": "{{instance}}",
890 | "refId": "A"
891 | }
892 | ],
893 | "thresholds": [],
894 | "timeFrom": null,
895 | "timeRegions": [],
896 | "timeShift": null,
897 | "title": "Messages published / s",
898 | "tooltip": {
899 | "shared": true,
900 | "sort": 2,
901 | "value_type": "individual"
902 | },
903 | "transparent": true,
904 | "type": "graph",
905 | "xaxis": {
906 | "buckets": null,
907 | "mode": "time",
908 | "name": null,
909 | "show": true,
910 | "values": []
911 | },
912 | "yaxes": [
913 | {
914 | "decimals": null,
915 | "format": "short",
916 | "label": "",
917 | "logBase": 1,
918 | "max": null,
919 | "min": "0",
920 | "show": true
921 | },
922 | {
923 | "format": "short",
924 | "label": null,
925 | "logBase": 1,
926 | "max": null,
927 | "min": null,
928 | "show": true
929 | }
930 | ],
931 | "yaxis": {
932 | "align": false,
933 | "alignLevel": null
934 | }
935 | },
936 | {
937 | "aliasColors": {},
938 | "bars": false,
939 | "dashLength": 10,
940 | "dashes": false,
941 | "datasource": null,
942 | "fill": 1,
943 | "fillGradient": 0,
944 | "gridPos": {
945 | "h": 7,
946 | "w": 6,
947 | "x": 12,
948 | "y": 16
949 | },
950 | "id": 20,
951 | "legend": {
952 | "alignAsTable": true,
953 | "avg": true,
954 | "current": true,
955 | "max": true,
956 | "min": true,
957 | "rightSide": false,
958 | "show": false,
959 | "sort": "avg",
960 | "sortDesc": true,
961 | "total": false,
962 | "values": true
963 | },
964 | "lines": true,
965 | "linewidth": 1,
966 | "links": [],
967 | "nullPointMode": "null",
968 | "options": {
969 | "dataLinks": []
970 | },
971 | "percentage": false,
972 | "pointradius": 5,
973 | "points": false,
974 | "renderer": "flot",
975 | "seriesOverrides": [],
976 | "spaceLength": 10,
977 | "stack": false,
978 | "steppedLine": false,
979 | "targets": [
980 | {
981 | "expr": "perftest_consumed{instance=~\"$instance\"}",
982 | "format": "time_series",
983 | "intervalFactor": 1,
984 | "legendFormat": "{{instance}}",
985 | "refId": "A"
986 | }
987 | ],
988 | "thresholds": [],
989 | "timeFrom": null,
990 | "timeRegions": [],
991 | "timeShift": null,
992 | "title": "Messages consumed / s",
993 | "tooltip": {
994 | "shared": true,
995 | "sort": 2,
996 | "value_type": "individual"
997 | },
998 | "transparent": true,
999 | "type": "graph",
1000 | "xaxis": {
1001 | "buckets": null,
1002 | "mode": "time",
1003 | "name": null,
1004 | "show": true,
1005 | "values": []
1006 | },
1007 | "yaxes": [
1008 | {
1009 | "decimals": null,
1010 | "format": "short",
1011 | "label": "",
1012 | "logBase": 1,
1013 | "max": null,
1014 | "min": "0",
1015 | "show": true
1016 | },
1017 | {
1018 | "format": "short",
1019 | "label": null,
1020 | "logBase": 1,
1021 | "max": null,
1022 | "min": null,
1023 | "show": true
1024 | }
1025 | ],
1026 | "yaxis": {
1027 | "align": false,
1028 | "alignLevel": null
1029 | }
1030 | },
1031 | {
1032 | "columns": [
1033 | {
1034 | "text": "Min",
1035 | "value": "min"
1036 | },
1037 | {
1038 | "text": "Max",
1039 | "value": "max"
1040 | },
1041 | {
1042 | "text": "Avg",
1043 | "value": "avg"
1044 | },
1045 | {
1046 | "text": "Current",
1047 | "value": "current"
1048 | }
1049 | ],
1050 | "datasource": null,
1051 | "fontSize": "100%",
1052 | "gridPos": {
1053 | "h": 7,
1054 | "w": 6,
1055 | "x": 18,
1056 | "y": 16
1057 | },
1058 | "id": 28,
1059 | "options": {},
1060 | "pageSize": 5,
1061 | "pluginVersion": "6.4.1",
1062 | "showHeader": true,
1063 | "sort": {
1064 | "col": 4,
1065 | "desc": true
1066 | },
1067 | "styles": [
1068 | {
1069 | "alias": "Instance",
1070 | "colorMode": null,
1071 | "colors": [
1072 | "rgba(245, 54, 54, 0.9)",
1073 | "rgba(237, 129, 40, 0.89)",
1074 | "rgba(50, 172, 45, 0.97)"
1075 | ],
1076 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1077 | "decimals": 0,
1078 | "mappingType": 1,
1079 | "pattern": "Metric",
1080 | "thresholds": [],
1081 | "type": "string",
1082 | "unit": "short"
1083 | },
1084 | {
1085 | "alias": "",
1086 | "colorMode": null,
1087 | "colors": [
1088 | "rgba(245, 54, 54, 0.9)",
1089 | "rgba(237, 129, 40, 0.89)",
1090 | "rgba(50, 172, 45, 0.97)"
1091 | ],
1092 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1093 | "decimals": 0,
1094 | "mappingType": 1,
1095 | "pattern": "/.*/",
1096 | "thresholds": [],
1097 | "type": "number",
1098 | "unit": "short"
1099 | }
1100 | ],
1101 | "targets": [
1102 | {
1103 | "expr": "perftest_consumed",
1104 | "legendFormat": "{{instance}}",
1105 | "refId": "A"
1106 | }
1107 | ],
1108 | "timeFrom": null,
1109 | "timeShift": null,
1110 | "title": "Messages consumed / s",
1111 | "transform": "timeseries_aggregations",
1112 | "type": "table"
1113 | },
1114 | {
1115 | "columns": [
1116 | {
1117 | "text": "Min",
1118 | "value": "min"
1119 | },
1120 | {
1121 | "text": "Max",
1122 | "value": "max"
1123 | },
1124 | {
1125 | "text": "Avg",
1126 | "value": "avg"
1127 | },
1128 | {
1129 | "text": "Current",
1130 | "value": "current"
1131 | }
1132 | ],
1133 | "datasource": null,
1134 | "fontSize": "100%",
1135 | "gridPos": {
1136 | "h": 7,
1137 | "w": 6,
1138 | "x": 0,
1139 | "y": 23
1140 | },
1141 | "id": 30,
1142 | "options": {},
1143 | "pageSize": 5,
1144 | "pluginVersion": "6.4.1",
1145 | "showHeader": true,
1146 | "sort": {
1147 | "col": 4,
1148 | "desc": true
1149 | },
1150 | "styles": [
1151 | {
1152 | "alias": "Instance",
1153 | "colorMode": null,
1154 | "colors": [
1155 | "rgba(245, 54, 54, 0.9)",
1156 | "rgba(237, 129, 40, 0.89)",
1157 | "rgba(50, 172, 45, 0.97)"
1158 | ],
1159 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1160 | "decimals": 0,
1161 | "mappingType": 1,
1162 | "pattern": "Metric",
1163 | "thresholds": [],
1164 | "type": "string",
1165 | "unit": "short"
1166 | },
1167 | {
1168 | "alias": "",
1169 | "colorMode": null,
1170 | "colors": [
1171 | "rgba(245, 54, 54, 0.9)",
1172 | "rgba(237, 129, 40, 0.89)",
1173 | "rgba(50, 172, 45, 0.97)"
1174 | ],
1175 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1176 | "decimals": 0,
1177 | "mappingType": 1,
1178 | "pattern": "/.*/",
1179 | "thresholds": [],
1180 | "type": "number",
1181 | "unit": "short"
1182 | }
1183 | ],
1184 | "targets": [
1185 | {
1186 | "expr": "perftest_confirmed",
1187 | "legendFormat": "{{instance}}",
1188 | "refId": "A"
1189 | }
1190 | ],
1191 | "timeFrom": null,
1192 | "timeShift": null,
1193 | "title": "Messages confirmed / s",
1194 | "transform": "timeseries_aggregations",
1195 | "type": "table"
1196 | },
1197 | {
1198 | "aliasColors": {},
1199 | "bars": false,
1200 | "dashLength": 10,
1201 | "dashes": false,
1202 | "datasource": null,
1203 | "fill": 1,
1204 | "fillGradient": 0,
1205 | "gridPos": {
1206 | "h": 7,
1207 | "w": 6,
1208 | "x": 6,
1209 | "y": 23
1210 | },
1211 | "id": 29,
1212 | "legend": {
1213 | "alignAsTable": true,
1214 | "avg": true,
1215 | "current": true,
1216 | "max": true,
1217 | "min": true,
1218 | "rightSide": false,
1219 | "show": false,
1220 | "sort": "avg",
1221 | "sortDesc": true,
1222 | "total": false,
1223 | "values": true
1224 | },
1225 | "lines": true,
1226 | "linewidth": 1,
1227 | "links": [],
1228 | "nullPointMode": "null",
1229 | "options": {
1230 | "dataLinks": []
1231 | },
1232 | "percentage": false,
1233 | "pointradius": 5,
1234 | "points": false,
1235 | "renderer": "flot",
1236 | "seriesOverrides": [],
1237 | "spaceLength": 10,
1238 | "stack": false,
1239 | "steppedLine": false,
1240 | "targets": [
1241 | {
1242 | "expr": "perftest_confirmed{instance=~\"$instance\"}",
1243 | "format": "time_series",
1244 | "intervalFactor": 1,
1245 | "legendFormat": "{{instance}}",
1246 | "refId": "A"
1247 | }
1248 | ],
1249 | "thresholds": [],
1250 | "timeFrom": null,
1251 | "timeRegions": [],
1252 | "timeShift": null,
1253 | "title": "Messages confirmed / s",
1254 | "tooltip": {
1255 | "shared": true,
1256 | "sort": 2,
1257 | "value_type": "individual"
1258 | },
1259 | "transparent": true,
1260 | "type": "graph",
1261 | "xaxis": {
1262 | "buckets": null,
1263 | "mode": "time",
1264 | "name": null,
1265 | "show": true,
1266 | "values": []
1267 | },
1268 | "yaxes": [
1269 | {
1270 | "decimals": null,
1271 | "format": "short",
1272 | "label": "",
1273 | "logBase": 1,
1274 | "max": null,
1275 | "min": "0",
1276 | "show": true
1277 | },
1278 | {
1279 | "format": "short",
1280 | "label": null,
1281 | "logBase": 1,
1282 | "max": null,
1283 | "min": null,
1284 | "show": true
1285 | }
1286 | ],
1287 | "yaxis": {
1288 | "align": false,
1289 | "alignLevel": null
1290 | }
1291 | },
1292 | {
1293 | "aliasColors": {},
1294 | "bars": false,
1295 | "dashLength": 10,
1296 | "dashes": false,
1297 | "datasource": null,
1298 | "fill": 1,
1299 | "fillGradient": 0,
1300 | "gridPos": {
1301 | "h": 7,
1302 | "w": 6,
1303 | "x": 12,
1304 | "y": 23
1305 | },
1306 | "id": 40,
1307 | "legend": {
1308 | "alignAsTable": true,
1309 | "avg": true,
1310 | "current": true,
1311 | "max": true,
1312 | "min": true,
1313 | "rightSide": false,
1314 | "show": false,
1315 | "sort": "avg",
1316 | "sortDesc": true,
1317 | "total": false,
1318 | "values": true
1319 | },
1320 | "lines": true,
1321 | "linewidth": 1,
1322 | "links": [],
1323 | "nullPointMode": "null",
1324 | "options": {
1325 | "dataLinks": []
1326 | },
1327 | "percentage": false,
1328 | "pointradius": 5,
1329 | "points": false,
1330 | "renderer": "flot",
1331 | "seriesOverrides": [],
1332 | "spaceLength": 10,
1333 | "stack": false,
1334 | "steppedLine": false,
1335 | "targets": [
1336 | {
1337 | "expr": "perftest_nacked{instance=~\"$instance\"}",
1338 | "format": "time_series",
1339 | "intervalFactor": 1,
1340 | "legendFormat": "{{instance}}",
1341 | "refId": "A"
1342 | }
1343 | ],
1344 | "thresholds": [],
1345 | "timeFrom": null,
1346 | "timeRegions": [],
1347 | "timeShift": null,
1348 | "title": "Messages rejected / s",
1349 | "tooltip": {
1350 | "shared": true,
1351 | "sort": 2,
1352 | "value_type": "individual"
1353 | },
1354 | "transparent": true,
1355 | "type": "graph",
1356 | "xaxis": {
1357 | "buckets": null,
1358 | "mode": "time",
1359 | "name": null,
1360 | "show": true,
1361 | "values": []
1362 | },
1363 | "yaxes": [
1364 | {
1365 | "decimals": null,
1366 | "format": "short",
1367 | "label": "",
1368 | "logBase": 1,
1369 | "max": null,
1370 | "min": "0",
1371 | "show": true
1372 | },
1373 | {
1374 | "format": "short",
1375 | "label": null,
1376 | "logBase": 1,
1377 | "max": null,
1378 | "min": null,
1379 | "show": true
1380 | }
1381 | ],
1382 | "yaxis": {
1383 | "align": false,
1384 | "alignLevel": null
1385 | }
1386 | },
1387 | {
1388 | "columns": [
1389 | {
1390 | "text": "Min",
1391 | "value": "min"
1392 | },
1393 | {
1394 | "text": "Max",
1395 | "value": "max"
1396 | },
1397 | {
1398 | "text": "Avg",
1399 | "value": "avg"
1400 | },
1401 | {
1402 | "text": "Current",
1403 | "value": "current"
1404 | }
1405 | ],
1406 | "datasource": null,
1407 | "fontSize": "100%",
1408 | "gridPos": {
1409 | "h": 7,
1410 | "w": 6,
1411 | "x": 18,
1412 | "y": 23
1413 | },
1414 | "id": 41,
1415 | "options": {},
1416 | "pageSize": 5,
1417 | "pluginVersion": "6.4.1",
1418 | "showHeader": true,
1419 | "sort": {
1420 | "col": 4,
1421 | "desc": true
1422 | },
1423 | "styles": [
1424 | {
1425 | "alias": "Instance",
1426 | "colorMode": null,
1427 | "colors": [
1428 | "rgba(245, 54, 54, 0.9)",
1429 | "rgba(237, 129, 40, 0.89)",
1430 | "rgba(50, 172, 45, 0.97)"
1431 | ],
1432 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1433 | "decimals": 0,
1434 | "mappingType": 1,
1435 | "pattern": "Metric",
1436 | "thresholds": [],
1437 | "type": "string",
1438 | "unit": "short"
1439 | },
1440 | {
1441 | "alias": "",
1442 | "colorMode": null,
1443 | "colors": [
1444 | "rgba(245, 54, 54, 0.9)",
1445 | "rgba(237, 129, 40, 0.89)",
1446 | "rgba(50, 172, 45, 0.97)"
1447 | ],
1448 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1449 | "decimals": 0,
1450 | "mappingType": 1,
1451 | "pattern": "/.*/",
1452 | "thresholds": [],
1453 | "type": "number",
1454 | "unit": "short"
1455 | }
1456 | ],
1457 | "targets": [
1458 | {
1459 | "expr": "perftest_nacked",
1460 | "legendFormat": "{{instance}}",
1461 | "refId": "A"
1462 | }
1463 | ],
1464 | "timeFrom": null,
1465 | "timeShift": null,
1466 | "title": "Messages rejected / s",
1467 | "transform": "timeseries_aggregations",
1468 | "type": "table"
1469 | },
1470 | {
1471 | "columns": [
1472 | {
1473 | "text": "Min",
1474 | "value": "min"
1475 | },
1476 | {
1477 | "text": "Max",
1478 | "value": "max"
1479 | },
1480 | {
1481 | "text": "Avg",
1482 | "value": "avg"
1483 | },
1484 | {
1485 | "text": "Current",
1486 | "value": "current"
1487 | }
1488 | ],
1489 | "datasource": null,
1490 | "fontSize": "100%",
1491 | "gridPos": {
1492 | "h": 7,
1493 | "w": 6,
1494 | "x": 0,
1495 | "y": 30
1496 | },
1497 | "id": 32,
1498 | "options": {},
1499 | "pageSize": 5,
1500 | "pluginVersion": "6.4.1",
1501 | "showHeader": true,
1502 | "sort": {
1503 | "col": 4,
1504 | "desc": true
1505 | },
1506 | "styles": [
1507 | {
1508 | "alias": "Instance",
1509 | "colorMode": null,
1510 | "colors": [
1511 | "rgba(245, 54, 54, 0.9)",
1512 | "rgba(237, 129, 40, 0.89)",
1513 | "rgba(50, 172, 45, 0.97)"
1514 | ],
1515 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1516 | "decimals": 0,
1517 | "mappingType": 1,
1518 | "pattern": "Metric",
1519 | "thresholds": [],
1520 | "type": "string",
1521 | "unit": "short"
1522 | },
1523 | {
1524 | "alias": "",
1525 | "colorMode": null,
1526 | "colors": [
1527 | "rgba(245, 54, 54, 0.9)",
1528 | "rgba(237, 129, 40, 0.89)",
1529 | "rgba(50, 172, 45, 0.97)"
1530 | ],
1531 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
1532 | "decimals": 0,
1533 | "mappingType": 1,
1534 | "pattern": "/.*/",
1535 | "thresholds": [],
1536 | "type": "number",
1537 | "unit": "short"
1538 | }
1539 | ],
1540 | "targets": [
1541 | {
1542 | "expr": "perftest_returned",
1543 | "legendFormat": "{{instance}}",
1544 | "refId": "A"
1545 | }
1546 | ],
1547 | "timeFrom": null,
1548 | "timeShift": null,
1549 | "title": "Messages returned / s",
1550 | "transform": "timeseries_aggregations",
1551 | "type": "table"
1552 | },
1553 | {
1554 | "aliasColors": {},
1555 | "bars": false,
1556 | "dashLength": 10,
1557 | "dashes": false,
1558 | "datasource": null,
1559 | "fill": 1,
1560 | "fillGradient": 0,
1561 | "gridPos": {
1562 | "h": 7,
1563 | "w": 6,
1564 | "x": 6,
1565 | "y": 30
1566 | },
1567 | "id": 31,
1568 | "legend": {
1569 | "alignAsTable": true,
1570 | "avg": true,
1571 | "current": true,
1572 | "max": true,
1573 | "min": true,
1574 | "rightSide": false,
1575 | "show": false,
1576 | "sort": "avg",
1577 | "sortDesc": true,
1578 | "total": false,
1579 | "values": true
1580 | },
1581 | "lines": true,
1582 | "linewidth": 1,
1583 | "links": [],
1584 | "nullPointMode": "null",
1585 | "options": {
1586 | "dataLinks": []
1587 | },
1588 | "percentage": false,
1589 | "pointradius": 5,
1590 | "points": false,
1591 | "renderer": "flot",
1592 | "seriesOverrides": [],
1593 | "spaceLength": 10,
1594 | "stack": false,
1595 | "steppedLine": false,
1596 | "targets": [
1597 | {
1598 | "expr": "perftest_returned{instance=~\"$instance\"}",
1599 | "format": "time_series",
1600 | "intervalFactor": 1,
1601 | "legendFormat": "{{instance}}",
1602 | "refId": "A"
1603 | }
1604 | ],
1605 | "thresholds": [],
1606 | "timeFrom": null,
1607 | "timeRegions": [],
1608 | "timeShift": null,
1609 | "title": "Messages returned / s",
1610 | "tooltip": {
1611 | "shared": true,
1612 | "sort": 2,
1613 | "value_type": "individual"
1614 | },
1615 | "transparent": true,
1616 | "type": "graph",
1617 | "xaxis": {
1618 | "buckets": null,
1619 | "mode": "time",
1620 | "name": null,
1621 | "show": true,
1622 | "values": []
1623 | },
1624 | "yaxes": [
1625 | {
1626 | "decimals": null,
1627 | "format": "short",
1628 | "label": "",
1629 | "logBase": 1,
1630 | "max": null,
1631 | "min": "0",
1632 | "show": true
1633 | },
1634 | {
1635 | "format": "short",
1636 | "label": null,
1637 | "logBase": 1,
1638 | "max": null,
1639 | "min": null,
1640 | "show": true
1641 | }
1642 | ],
1643 | "yaxis": {
1644 | "align": false,
1645 | "alignLevel": null
1646 | }
1647 | }
1648 | ],
1649 | "refresh": "15s",
1650 | "schemaVersion": 20,
1651 | "style": "dark",
1652 | "tags": [
1653 | "rabbitmq-perf-test"
1654 | ],
1655 | "templating": {
1656 | "list": [
1657 | {
1658 | "current": {
1659 | "selected": false,
1660 | "text": "default",
1661 | "value": "default"
1662 | },
1663 | "hide": 2,
1664 | "includeAll": false,
1665 | "label": "datasource",
1666 | "multi": false,
1667 | "name": "DS_PROMETHEUS",
1668 | "options": [],
1669 | "query": "prometheus",
1670 | "refresh": 1,
1671 | "regex": "",
1672 | "skipUrlSync": false,
1673 | "type": "datasource"
1674 | },
1675 | {
1676 | "allValue": null,
1677 | "current": {
1678 | "text": "All",
1679 | "value": [
1680 | "$__all"
1681 | ]
1682 | },
1683 | "datasource": null,
1684 | "definition": "label_values(perftest_published, instance)",
1685 | "hide": 0,
1686 | "includeAll": true,
1687 | "label": "PerfTest Instance",
1688 | "multi": true,
1689 | "name": "instance",
1690 | "options": [],
1691 | "query": "label_values(perftest_published, instance)",
1692 | "refresh": 2,
1693 | "regex": "",
1694 | "skipUrlSync": false,
1695 | "sort": 1,
1696 | "tagValuesQuery": "",
1697 | "tags": [],
1698 | "tagsQuery": "",
1699 | "type": "query",
1700 | "useTags": false
1701 | },
1702 | {
1703 | "allValue": null,
1704 | "current": {
1705 | "text": "0.99",
1706 | "value": "0.99"
1707 | },
1708 | "datasource": null,
1709 | "definition": "label_values(perftest_latency_seconds, quantile)",
1710 | "hide": 0,
1711 | "includeAll": false,
1712 | "label": "Percentile",
1713 | "multi": false,
1714 | "name": "percentile",
1715 | "options": [],
1716 | "query": "label_values(perftest_latency_seconds, quantile)",
1717 | "refresh": 2,
1718 | "regex": "",
1719 | "skipUrlSync": false,
1720 | "sort": 4,
1721 | "tagValuesQuery": "",
1722 | "tags": [],
1723 | "tagsQuery": "",
1724 | "type": "query",
1725 | "useTags": false
1726 | }
1727 | ]
1728 | },
1729 | "time": {
1730 | "from": "now-15m",
1731 | "to": "now"
1732 | },
1733 | "timepicker": {
1734 | "refresh_intervals": [
1735 | "15s",
1736 | "30s",
1737 | "1m",
1738 | "5m",
1739 | "10m"
1740 | ],
1741 | "time_options": [
1742 | "5m",
1743 | "15m",
1744 | "1h",
1745 | "6h",
1746 | "12h",
1747 | "24h",
1748 | "2d",
1749 | "7d",
1750 | "30d"
1751 | ]
1752 | },
1753 | "timezone": "",
1754 | "title": "RabbitMQ-PerfTest",
1755 | "uid": "pK9UatSiz",
1756 | "version": 20210322
1757 | }
1758 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/grafana/dashboards/RabbitMQ-Quorum-Queues-Raft.json:
--------------------------------------------------------------------------------
1 | {
2 | "__requires": [
3 | {
4 | "type": "grafana",
5 | "id": "grafana",
6 | "name": "Grafana",
7 | "version": "7.0.0"
8 | },
9 | {
10 | "type": "datasource",
11 | "id": "prometheus",
12 | "name": "Prometheus",
13 | "version": "2.0.0"
14 | },
15 | {
16 | "type": "panel",
17 | "id": "graph",
18 | "name": "Graph",
19 | "version": ""
20 | },
21 | {
22 | "type": "panel",
23 | "id": "heatmap",
24 | "name": "Heatmap",
25 | "version": ""
26 | }
27 | ],
28 | "annotations": {
29 | "list": [
30 | {
31 | "builtIn": 1,
32 | "datasource": "-- Grafana --",
33 | "enable": true,
34 | "hide": true,
35 | "iconColor": "rgba(0, 211, 255, 1)",
36 | "name": "Annotations & Alerts",
37 | "type": "dashboard"
38 | }
39 | ]
40 | },
41 | "description": "Raft state for all Quorum Queues running in a RabbitMQ cluster",
42 | "editable": true,
43 | "gnetId": null,
44 | "graphTooltip": 1,
45 | "id": null,
46 | "iteration": 1581011566961,
47 | "links": [
48 | {
49 | "icon": "doc",
50 | "tags": [],
51 | "targetBlank": true,
52 | "title": "Quorum Queues Documentation",
53 | "tooltip": "",
54 | "type": "link",
55 | "url": "https://www.rabbitmq.com/quorum-queues.html"
56 | }
57 | ],
58 | "panels": [
59 | {
60 | "aliasColors": {},
61 | "bars": false,
62 | "cacheTimeout": null,
63 | "dashLength": 10,
64 | "dashes": false,
65 | "datasource": null,
66 | "description": "##### Rate of Raft log operations committed\n\nThis includes all queue operations, including publishes & consumer acknowledgements.\n\nThis tracks the progress of the Raft commit index on all members, including followers.\n\nIf a RabbitMQ node does not run a Raft member, it will not report any entries committed.",
67 | "fill": 0,
68 | "fillGradient": 0,
69 | "gridPos": {
70 | "h": 9,
71 | "w": 12,
72 | "x": 0,
73 | "y": 0
74 | },
75 | "hiddenSeries": false,
76 | "id": 64,
77 | "legend": {
78 | "alignAsTable": true,
79 | "avg": false,
80 | "current": true,
81 | "max": true,
82 | "min": false,
83 | "show": true,
84 | "sort": "current",
85 | "sortDesc": true,
86 | "total": true,
87 | "values": true
88 | },
89 | "lines": true,
90 | "linewidth": 1,
91 | "links": [],
92 | "nullPointMode": "null",
93 | "options": {
94 | "dataLinks": []
95 | },
96 | "percentage": false,
97 | "pointradius": 2,
98 | "points": false,
99 | "renderer": "flot",
100 | "seriesOverrides": [
101 | {
102 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/",
103 | "color": "#56A64B"
104 | },
105 | {
106 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/",
107 | "color": "#F2CC0C"
108 | },
109 | {
110 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/",
111 | "color": "#3274D9"
112 | },
113 | {
114 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/",
115 | "color": "#A352CC"
116 | },
117 | {
118 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/",
119 | "color": "#FF780A"
120 | },
121 | {
122 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/",
123 | "color": "#96D98D"
124 | },
125 | {
126 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/",
127 | "color": "#FFEE52"
128 | },
129 | {
130 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/",
131 | "color": "#8AB8FF"
132 | },
133 | {
134 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/",
135 | "color": "#CA95E5"
136 | },
137 | {
138 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/",
139 | "color": "#FFB357"
140 | }
141 | ],
142 | "spaceLength": 10,
143 | "stack": false,
144 | "steppedLine": false,
145 | "targets": [
146 | {
147 | "expr": "sum(rate(rabbitmq_raft_log_commit_index[60s]) * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)",
148 | "format": "time_series",
149 | "instant": false,
150 | "intervalFactor": 1,
151 | "legendFormat": "{{rabbitmq_node}}",
152 | "refId": "A"
153 | }
154 | ],
155 | "thresholds": [],
156 | "timeFrom": null,
157 | "timeRegions": [],
158 | "timeShift": null,
159 | "title": "Log entries committed / s",
160 | "tooltip": {
161 | "shared": true,
162 | "sort": 2,
163 | "value_type": "individual"
164 | },
165 | "type": "graph",
166 | "xaxis": {
167 | "buckets": null,
168 | "mode": "time",
169 | "name": null,
170 | "show": true,
171 | "values": []
172 | },
173 | "yaxes": [
174 | {
175 | "decimals": null,
176 | "format": "short",
177 | "label": null,
178 | "logBase": 1,
179 | "max": null,
180 | "min": "0",
181 | "show": true
182 | },
183 | {
184 | "format": "short",
185 | "label": null,
186 | "logBase": 1,
187 | "max": null,
188 | "min": null,
189 | "show": true
190 | }
191 | ],
192 | "yaxis": {
193 | "align": false,
194 | "alignLevel": null
195 | }
196 | },
197 | {
198 | "cacheTimeout": null,
199 | "cards": {
200 | "cardPadding": null,
201 | "cardRound": null
202 | },
203 | "color": {
204 | "cardColor": "rgb(255, 255, 255)",
205 | "colorScale": "sqrt",
206 | "colorScheme": "interpolateCool",
207 | "exponent": 0.4,
208 | "mode": "opacity"
209 | },
210 | "dataFormat": "timeseries",
211 | "datasource": null,
212 | "description": "##### Time for a log entry to be committed\n\nThis is an indicator of Raft operational overhead. Values will increase with increased load as the system trades latency for throughput.\n\nThis metric samples the time it takes for a log entry to be written to a Raft log and that entry being committed.\n\nBecause quorum queues fsync all operations to disk before committing them, they are not suitable for low-latency workloads.",
213 | "gridPos": {
214 | "h": 9,
215 | "w": 12,
216 | "x": 12,
217 | "y": 0
218 | },
219 | "heatmap": {},
220 | "hideZeroBuckets": false,
221 | "highlightCards": true,
222 | "id": 65,
223 | "legend": {
224 | "show": true
225 | },
226 | "links": [],
227 | "options": {},
228 | "reverseYBuckets": false,
229 | "targets": [
230 | {
231 | "expr": "rabbitmq_raft_entry_commit_latency_seconds * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}",
232 | "format": "time_series",
233 | "instant": false,
234 | "intervalFactor": 1,
235 | "legendFormat": "",
236 | "refId": "A"
237 | }
238 | ],
239 | "timeFrom": null,
240 | "timeShift": null,
241 | "title": "Log entry commit latency",
242 | "tooltip": {
243 | "show": true,
244 | "showHistogram": true
245 | },
246 | "type": "heatmap",
247 | "xAxis": {
248 | "show": true
249 | },
250 | "xBucketNumber": null,
251 | "xBucketSize": null,
252 | "yAxis": {
253 | "decimals": null,
254 | "format": "s",
255 | "logBase": 1,
256 | "max": null,
257 | "min": "0",
258 | "show": true,
259 | "splitFactor": null
260 | },
261 | "yBucketBound": "lower",
262 | "yBucketNumber": null,
263 | "yBucketSize": null
264 | },
265 | {
266 | "aliasColors": {},
267 | "bars": false,
268 | "cacheTimeout": null,
269 | "dashLength": 10,
270 | "dashes": false,
271 | "datasource": null,
272 | "description": "##### Pending Raft log entries\n\nTracks the number of Raft log entries that have been written but not yet committed.\n\nHigh & growing values may be indicative of a quorum of members not being available so that a queue can make progress.",
273 | "fill": 0,
274 | "fillGradient": 0,
275 | "gridPos": {
276 | "h": 9,
277 | "w": 12,
278 | "x": 0,
279 | "y": 9
280 | },
281 | "hiddenSeries": false,
282 | "id": 62,
283 | "legend": {
284 | "alignAsTable": true,
285 | "avg": false,
286 | "current": true,
287 | "hideEmpty": false,
288 | "hideZero": true,
289 | "max": true,
290 | "min": false,
291 | "rightSide": false,
292 | "show": true,
293 | "sort": "total",
294 | "sortDesc": true,
295 | "total": true,
296 | "values": true
297 | },
298 | "lines": true,
299 | "linewidth": 1,
300 | "links": [],
301 | "nullPointMode": "null",
302 | "options": {
303 | "dataLinks": []
304 | },
305 | "percentage": false,
306 | "pointradius": 2,
307 | "points": false,
308 | "renderer": "flot",
309 | "seriesOverrides": [
310 | {
311 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/",
312 | "color": "#56A64B"
313 | },
314 | {
315 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/",
316 | "color": "#F2CC0C"
317 | },
318 | {
319 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/",
320 | "color": "#3274D9"
321 | },
322 | {
323 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/",
324 | "color": "#A352CC"
325 | },
326 | {
327 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/",
328 | "color": "#FF780A"
329 | },
330 | {
331 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/",
332 | "color": "#96D98D"
333 | },
334 | {
335 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/",
336 | "color": "#FFEE52"
337 | },
338 | {
339 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/",
340 | "color": "#8AB8FF"
341 | },
342 | {
343 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/",
344 | "color": "#CA95E5"
345 | },
346 | {
347 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/",
348 | "color": "#FFB357"
349 | }
350 | ],
351 | "spaceLength": 10,
352 | "stack": false,
353 | "steppedLine": false,
354 | "targets": [
355 | {
356 | "expr": "sum(\n (rabbitmq_raft_log_last_written_index * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n (rabbitmq_raft_log_commit_index * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})\n) by(rabbitmq_node)",
357 | "format": "time_series",
358 | "instant": false,
359 | "intervalFactor": 1,
360 | "legendFormat": "{{rabbitmq_node}}",
361 | "refId": "A"
362 | }
363 | ],
364 | "thresholds": [],
365 | "timeFrom": null,
366 | "timeRegions": [],
367 | "timeShift": null,
368 | "title": "Uncommitted log entries",
369 | "tooltip": {
370 | "shared": true,
371 | "sort": 2,
372 | "value_type": "individual"
373 | },
374 | "type": "graph",
375 | "xaxis": {
376 | "buckets": null,
377 | "mode": "time",
378 | "name": null,
379 | "show": true,
380 | "values": []
381 | },
382 | "yaxes": [
383 | {
384 | "decimals": null,
385 | "format": "short",
386 | "label": "",
387 | "logBase": 1,
388 | "max": null,
389 | "min": null,
390 | "show": true
391 | },
392 | {
393 | "format": "short",
394 | "label": null,
395 | "logBase": 1,
396 | "max": null,
397 | "min": null,
398 | "show": true
399 | }
400 | ],
401 | "yaxis": {
402 | "align": false,
403 | "alignLevel": null
404 | }
405 | },
406 | {
407 | "aliasColors": {},
408 | "bars": false,
409 | "cacheTimeout": null,
410 | "dashLength": 10,
411 | "dashes": false,
412 | "datasource": null,
413 | "description": "##### Rate of Raft leader elections\n\nTracks the increments of the Raft term.\n\nSustained non-zero rates are indicative of network and/or availability issues, or queue churn. The other reason may be quorum queue declarations.\n\nValues above 0 are normal, some leader elections are expected. Sustained high values may be of concern.",
414 | "fill": 0,
415 | "fillGradient": 0,
416 | "gridPos": {
417 | "h": 9,
418 | "w": 12,
419 | "x": 12,
420 | "y": 9
421 | },
422 | "hiddenSeries": false,
423 | "id": 63,
424 | "legend": {
425 | "alignAsTable": true,
426 | "avg": false,
427 | "current": true,
428 | "max": true,
429 | "min": false,
430 | "rightSide": false,
431 | "show": true,
432 | "sort": "total",
433 | "sortDesc": true,
434 | "total": true,
435 | "values": true
436 | },
437 | "lines": true,
438 | "linewidth": 1,
439 | "links": [],
440 | "nullPointMode": "null",
441 | "options": {
442 | "dataLinks": []
443 | },
444 | "percentage": false,
445 | "pointradius": 2,
446 | "points": false,
447 | "renderer": "flot",
448 | "seriesOverrides": [
449 | {
450 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/",
451 | "color": "#56A64B"
452 | },
453 | {
454 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/",
455 | "color": "#F2CC0C"
456 | },
457 | {
458 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/",
459 | "color": "#3274D9"
460 | },
461 | {
462 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/",
463 | "color": "#A352CC"
464 | },
465 | {
466 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/",
467 | "color": "#FF780A"
468 | },
469 | {
470 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/",
471 | "color": "#96D98D"
472 | },
473 | {
474 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/",
475 | "color": "#FFEE52"
476 | },
477 | {
478 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/",
479 | "color": "#8AB8FF"
480 | },
481 | {
482 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/",
483 | "color": "#CA95E5"
484 | },
485 | {
486 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/",
487 | "color": "#FFB357"
488 | }
489 | ],
490 | "spaceLength": 10,
491 | "stack": false,
492 | "steppedLine": false,
493 | "targets": [
494 | {
495 | "expr": "sum(rate(rabbitmq_raft_term_total[60s]) * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)",
496 | "format": "time_series",
497 | "instant": false,
498 | "intervalFactor": 1,
499 | "legendFormat": "{{rabbitmq_node}}",
500 | "refId": "A"
501 | }
502 | ],
503 | "thresholds": [
504 | {
505 | "colorMode": "warning",
506 | "fill": true,
507 | "line": true,
508 | "op": "gt",
509 | "value": 3,
510 | "yaxis": "left"
511 | }
512 | ],
513 | "timeFrom": null,
514 | "timeRegions": [],
515 | "timeShift": null,
516 | "title": "Leader elections / s",
517 | "tooltip": {
518 | "shared": true,
519 | "sort": 2,
520 | "value_type": "individual"
521 | },
522 | "type": "graph",
523 | "xaxis": {
524 | "buckets": null,
525 | "mode": "time",
526 | "name": null,
527 | "show": true,
528 | "values": []
529 | },
530 | "yaxes": [
531 | {
532 | "decimals": null,
533 | "format": "short",
534 | "label": "",
535 | "logBase": 1,
536 | "max": null,
537 | "min": "0",
538 | "show": true
539 | },
540 | {
541 | "format": "short",
542 | "label": null,
543 | "logBase": 1,
544 | "max": null,
545 | "min": null,
546 | "show": true
547 | }
548 | ],
549 | "yaxis": {
550 | "align": false,
551 | "alignLevel": null
552 | }
553 | },
554 | {
555 | "aliasColors": {},
556 | "bars": false,
557 | "cacheTimeout": null,
558 | "dashLength": 10,
559 | "dashes": false,
560 | "datasource": null,
561 | "description": "##### Number of entries in the Raft log\n\nTracks the number of Raft log entries since the last snapshot.\n\nLarge values can either be indicative of large quorum queue backlogs or availability problems. If the uncommitted entries metric is large as well, there is a genuine availability problem in the system.",
562 | "fill": 0,
563 | "fillGradient": 0,
564 | "gridPos": {
565 | "h": 13,
566 | "w": 24,
567 | "x": 0,
568 | "y": 18
569 | },
570 | "hiddenSeries": false,
571 | "id": 18,
572 | "legend": {
573 | "alignAsTable": true,
574 | "avg": false,
575 | "current": true,
576 | "max": true,
577 | "min": false,
578 | "rightSide": false,
579 | "show": true,
580 | "sort": "current",
581 | "sortDesc": true,
582 | "total": true,
583 | "values": true
584 | },
585 | "lines": true,
586 | "linewidth": 1,
587 | "links": [],
588 | "nullPointMode": "null as zero",
589 | "options": {
590 | "dataLinks": []
591 | },
592 | "percentage": false,
593 | "pointradius": 2,
594 | "points": false,
595 | "renderer": "flot",
596 | "seriesOverrides": [
597 | {
598 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/",
599 | "color": "#56A64B"
600 | },
601 | {
602 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/",
603 | "color": "#F2CC0C"
604 | },
605 | {
606 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/",
607 | "color": "#3274D9"
608 | },
609 | {
610 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/",
611 | "color": "#A352CC"
612 | },
613 | {
614 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/",
615 | "color": "#FF780A"
616 | },
617 | {
618 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/",
619 | "color": "#96D98D"
620 | },
621 | {
622 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/",
623 | "color": "#FFEE52"
624 | },
625 | {
626 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/",
627 | "color": "#8AB8FF"
628 | },
629 | {
630 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/",
631 | "color": "#CA95E5"
632 | },
633 | {
634 | "alias": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/",
635 | "color": "#FFB357"
636 | }
637 | ],
638 | "spaceLength": 10,
639 | "stack": false,
640 | "steppedLine": false,
641 | "targets": [
642 | {
643 | "expr": "sum(\n (rabbitmq_raft_log_last_written_index * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) - \n (rabbitmq_raft_log_snapshot_index * on(instance) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})\n) by(queue, rabbitmq_node) > 5000",
644 | "hide": false,
645 | "legendFormat": "{{rabbitmq_node}} {{queue}}",
646 | "refId": "A"
647 | }
648 | ],
649 | "thresholds": [],
650 | "timeFrom": null,
651 | "timeRegions": [],
652 | "timeShift": null,
653 | "title": "Raft members with >5k entries in the log",
654 | "tooltip": {
655 | "shared": true,
656 | "sort": 2,
657 | "value_type": "individual"
658 | },
659 | "type": "graph",
660 | "xaxis": {
661 | "buckets": null,
662 | "mode": "time",
663 | "name": null,
664 | "show": true,
665 | "values": []
666 | },
667 | "yaxes": [
668 | {
669 | "decimals": null,
670 | "format": "short",
671 | "label": "",
672 | "logBase": 1,
673 | "max": null,
674 | "min": "0",
675 | "show": true
676 | },
677 | {
678 | "format": "short",
679 | "label": null,
680 | "logBase": 1,
681 | "max": null,
682 | "min": null,
683 | "show": true
684 | }
685 | ],
686 | "yaxis": {
687 | "align": false,
688 | "alignLevel": null
689 | }
690 | }
691 | ],
692 | "refresh": "15s",
693 | "schemaVersion": 21,
694 | "style": "dark",
695 | "tags": [
696 | "rabbitmq-prometheus"
697 | ],
698 | "templating": {
699 | "list": [
700 | {
701 | "current": {
702 | "selected": false,
703 | "text": "default",
704 | "value": "default"
705 | },
706 | "hide": 2,
707 | "includeAll": false,
708 | "label": "datasource",
709 | "multi": false,
710 | "name": "DS_PROMETHEUS",
711 | "options": [],
712 | "query": "prometheus",
713 | "refresh": 1,
714 | "regex": "",
715 | "skipUrlSync": false,
716 | "type": "datasource"
717 | },
718 | {
719 | "allValue": null,
720 | "current": {},
721 | "datasource": null,
722 | "definition": "label_values(rabbitmq_identity_info, namespace)",
723 | "hide": 0,
724 | "includeAll": false,
725 | "label": "Namespace",
726 | "multi": false,
727 | "name": "namespace",
728 | "options": [],
729 | "query": "label_values(rabbitmq_identity_info, namespace)",
730 | "refresh": 2,
731 | "regex": "",
732 | "skipUrlSync": false,
733 | "sort": 1,
734 | "tagValuesQuery": "",
735 | "tags": [],
736 | "tagsQuery": "",
737 | "type": "query",
738 | "useTags": false
739 | },
740 | {
741 | "allValue": null,
742 | "current": {
743 | "text": "",
744 | "value": ""
745 | },
746 | "datasource": null,
747 | "definition": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)",
748 | "hide": 0,
749 | "includeAll": false,
750 | "label": "RabbitMQ Cluster",
751 | "multi": false,
752 | "name": "rabbitmq_cluster",
753 | "options": [],
754 | "query": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)",
755 | "refresh": 2,
756 | "regex": "",
757 | "skipUrlSync": false,
758 | "sort": 0,
759 | "tagValuesQuery": "",
760 | "tags": [],
761 | "tagsQuery": "",
762 | "type": "query",
763 | "useTags": false
764 | }
765 | ]
766 | },
767 | "time": {
768 | "from": "now-15m",
769 | "to": "now"
770 | },
771 | "timepicker": {
772 | "refresh_intervals": [
773 | "15s",
774 | "30s",
775 | "1m",
776 | "5m",
777 | "10m"
778 | ],
779 | "time_options": [
780 | "5m",
781 | "15m",
782 | "1h",
783 | "6h",
784 | "12h",
785 | "24h",
786 | "2d",
787 | "7d",
788 | "30d"
789 | ]
790 | },
791 | "timezone": "",
792 | "title": "RabbitMQ-Quorum-Queues-Raft",
793 | "uid": "f1Mee9nZz",
794 | "version": 20210322
795 | }
796 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/grafana/dashboards/rabbitmq-exporter_vs_rabbitmq-prometheus.json:
--------------------------------------------------------------------------------
1 | {
2 | "__requires": [
3 | {
4 | "type": "grafana",
5 | "id": "grafana",
6 | "name": "Grafana",
7 | "version": "7.0.0"
8 | },
9 | {
10 | "type": "datasource",
11 | "id": "prometheus",
12 | "name": "prometheus",
13 | "version": "2.0.0"
14 | },
15 | {
16 | "type": "panel",
17 | "id": "graph",
18 | "name": "Graph",
19 | "version": ""
20 | }
21 | ],
22 | "annotations": {
23 | "list": [
24 | {
25 | "builtIn": 1,
26 | "datasource": "-- Grafana --",
27 | "enable": true,
28 | "hide": true,
29 | "iconColor": "rgba(0, 211, 255, 1)",
30 | "name": "Annotations & Alerts",
31 | "type": "dashboard"
32 | }
33 | ]
34 | },
35 | "description": "rabbitmq-exporter vs rabbitmq-prometheus",
36 | "editable": true,
37 | "gnetId": null,
38 | "graphTooltip": 1,
39 | "links": [],
40 | "panels": [
41 | {
42 | "columns": [
43 | {
44 | "text": "Min",
45 | "value": "min"
46 | },
47 | {
48 | "text": "Max",
49 | "value": "max"
50 | },
51 | {
52 | "text": "Avg",
53 | "value": "avg"
54 | },
55 | {
56 | "text": "Current",
57 | "value": "current"
58 | }
59 | ],
60 | "datasource": null,
61 | "fontSize": "100%",
62 | "gridPos": {
63 | "h": 10,
64 | "w": 8,
65 | "x": 0,
66 | "y": 0
67 | },
68 | "id": 5,
69 | "options": {},
70 | "pageSize": null,
71 | "pluginVersion": "6.4.1",
72 | "scroll": true,
73 | "showHeader": true,
74 | "sort": {
75 | "col": 3,
76 | "desc": true
77 | },
78 | "styles": [
79 | {
80 | "alias": "",
81 | "colorMode": null,
82 | "colors": [
83 | "rgba(245, 54, 54, 0.9)",
84 | "rgba(237, 129, 40, 0.89)",
85 | "rgba(50, 172, 45, 0.97)"
86 | ],
87 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
88 | "decimals": 0,
89 | "mappingType": 1,
90 | "pattern": "Metric",
91 | "thresholds": [],
92 | "type": "string",
93 | "unit": "short"
94 | },
95 | {
96 | "alias": "",
97 | "colorMode": null,
98 | "colors": [
99 | "rgba(245, 54, 54, 0.9)",
100 | "rgba(237, 129, 40, 0.89)",
101 | "rgba(50, 172, 45, 0.97)"
102 | ],
103 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
104 | "decimals": 1,
105 | "mappingType": 1,
106 | "pattern": "/.*/",
107 | "thresholds": [],
108 | "type": "number",
109 | "unit": "s"
110 | }
111 | ],
112 | "targets": [
113 | {
114 | "expr": "scrape_duration_seconds{job=\"rabbitmq-exporter\"}",
115 | "legendFormat": "{{job}}",
116 | "refId": "A"
117 | },
118 | {
119 | "expr": "scrape_duration_seconds{job=\"rabbitmq-server\", instance=~\".*dist-tls.*\"}",
120 | "legendFormat": "{{instance}}",
121 | "refId": "B"
122 | },
123 | {
124 | "expr": "scrape_duration_seconds{job=\"rabbitmq-prometheus\"}",
125 | "legendFormat": "{{deployment}} {{instance}}",
126 | "refId": "C"
127 | }
128 | ],
129 | "timeFrom": null,
130 | "timeShift": null,
131 | "title": "Prometheus target scrape duration",
132 | "transform": "timeseries_aggregations",
133 | "type": "table"
134 | },
135 | {
136 | "aliasColors": {},
137 | "bars": false,
138 | "dashLength": 10,
139 | "dashes": false,
140 | "datasource": null,
141 | "description": "",
142 | "fill": 1,
143 | "fillGradient": 0,
144 | "gridPos": {
145 | "h": 10,
146 | "w": 16,
147 | "x": 8,
148 | "y": 0
149 | },
150 | "id": 3,
151 | "legend": {
152 | "avg": false,
153 | "current": false,
154 | "max": false,
155 | "min": false,
156 | "show": true,
157 | "total": false,
158 | "values": false
159 | },
160 | "lines": true,
161 | "linewidth": 1,
162 | "nullPointMode": "null",
163 | "options": {
164 | "dataLinks": []
165 | },
166 | "percentage": false,
167 | "pointradius": 2,
168 | "points": false,
169 | "renderer": "flot",
170 | "seriesOverrides": [],
171 | "spaceLength": 10,
172 | "stack": false,
173 | "steppedLine": false,
174 | "targets": [
175 | {
176 | "expr": "scrape_duration_seconds{job=\"rabbitmq-exporter\"}",
177 | "legendFormat": "{{job}}",
178 | "refId": "A"
179 | },
180 | {
181 | "expr": "scrape_duration_seconds{job=\"rabbitmq-server\", instance=~\".*dist-tls.*\"}",
182 | "legendFormat": "{{instance}}",
183 | "refId": "B"
184 | },
185 | {
186 | "expr": "scrape_duration_seconds{job=\"rabbitmq-prometheus\"}",
187 | "legendFormat": "{{deployment}} {{instance}}",
188 | "refId": "C"
189 | }
190 | ],
191 | "thresholds": [
192 | {
193 | "colorMode": "warning",
194 | "fill": true,
195 | "line": true,
196 | "op": "gt",
197 | "value": 10,
198 | "yaxis": "left"
199 | },
200 | {
201 | "colorMode": "critical",
202 | "fill": true,
203 | "line": true,
204 | "op": "gt",
205 | "value": 59,
206 | "yaxis": "left"
207 | }
208 | ],
209 | "timeFrom": null,
210 | "timeRegions": [],
211 | "timeShift": null,
212 | "title": "Prometheus target scrape duration",
213 | "tooltip": {
214 | "shared": true,
215 | "sort": 2,
216 | "value_type": "individual"
217 | },
218 | "type": "graph",
219 | "xaxis": {
220 | "buckets": null,
221 | "mode": "time",
222 | "name": null,
223 | "show": true,
224 | "values": []
225 | },
226 | "yaxes": [
227 | {
228 | "format": "s",
229 | "label": null,
230 | "logBase": 1,
231 | "max": null,
232 | "min": "0",
233 | "show": true
234 | },
235 | {
236 | "format": "short",
237 | "label": null,
238 | "logBase": 1,
239 | "max": null,
240 | "min": null,
241 | "show": true
242 | }
243 | ],
244 | "yaxis": {
245 | "align": false,
246 | "alignLevel": null
247 | }
248 | },
249 | {
250 | "aliasColors": {},
251 | "bars": false,
252 | "dashLength": 10,
253 | "dashes": false,
254 | "datasource": null,
255 | "fill": 1,
256 | "fillGradient": 0,
257 | "gridPos": {
258 | "h": 10,
259 | "w": 24,
260 | "x": 0,
261 | "y": 10
262 | },
263 | "id": 2,
264 | "legend": {
265 | "avg": false,
266 | "current": false,
267 | "max": false,
268 | "min": false,
269 | "show": true,
270 | "total": false,
271 | "values": false
272 | },
273 | "lines": true,
274 | "linewidth": 1,
275 | "nullPointMode": "null",
276 | "options": {
277 | "dataLinks": []
278 | },
279 | "percentage": false,
280 | "pointradius": 2,
281 | "points": false,
282 | "renderer": "flot",
283 | "seriesOverrides": [],
284 | "spaceLength": 10,
285 | "stack": false,
286 | "steppedLine": false,
287 | "targets": [
288 | {
289 | "expr": "http_request_duration_microseconds{quantile=\"0.99\", instance=\"rabbitmq-exporter:9090\"}",
290 | "format": "heatmap",
291 | "legendFormat": "{{quantile}}th",
292 | "refId": "A"
293 | }
294 | ],
295 | "thresholds": [],
296 | "timeFrom": null,
297 | "timeRegions": [],
298 | "timeShift": null,
299 | "title": "rabbitmq-exporter - RabbitMQ HTTP API request duration",
300 | "tooltip": {
301 | "shared": true,
302 | "sort": 0,
303 | "value_type": "individual"
304 | },
305 | "type": "graph",
306 | "xaxis": {
307 | "buckets": null,
308 | "mode": "time",
309 | "name": null,
310 | "show": true,
311 | "values": []
312 | },
313 | "yaxes": [
314 | {
315 | "format": "µs",
316 | "label": null,
317 | "logBase": 1,
318 | "max": null,
319 | "min": "0",
320 | "show": true
321 | },
322 | {
323 | "format": "short",
324 | "label": null,
325 | "logBase": 1,
326 | "max": null,
327 | "min": null,
328 | "show": true
329 | }
330 | ],
331 | "yaxis": {
332 | "align": false,
333 | "alignLevel": null
334 | }
335 | }
336 | ],
337 | "refresh": "15s",
338 | "schemaVersion": 20,
339 | "style": "dark",
340 | "tags": [
341 | "rabbitmq-exporter",
342 | "rabbitmq-prometheus"
343 | ],
344 | "templating": {
345 | "list": []
346 | },
347 | "time": {
348 | "from": "now-15m",
349 | "to": "now"
350 | },
351 | "timepicker": {
352 | "refresh_intervals": [
353 | "15s",
354 | "30s",
355 | "1m",
356 | "5m",
357 | "10m"
358 | ],
359 | "time_options": [
360 | "5m",
361 | "15m",
362 | "1h",
363 | "6h",
364 | "12h",
365 | "24h",
366 | "2d",
367 | "7d",
368 | "30d"
369 | ]
370 | },
371 | "timezone": "",
372 | "title": "rabbitmq-exporter_vs_rabbitmq-prometheus",
373 | "uid": "hNmaJ2AZk",
374 | "version": 1
375 | }
376 |
--------------------------------------------------------------------------------
/mqtt-broker/metrics/grafana/datasources.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | datasources:
4 | # name of the datasource. Required
5 | - name: prometheus
6 | # datasource type. Required
7 | type: prometheus
8 | # access mode. direct or proxy. Required
9 | access: proxy
10 | # org id. will default to orgId 1 if not specified
11 | orgId: 1
12 | # url
13 | url: http://prometheus:9090
14 | # database password, if used
15 | # password:
16 | # database user, if used
17 | # user:
18 | # database name, if used
19 | # database:
20 | # enable/disable basic auth
21 | # basicAuth:
22 | # basic auth username
23 | # basicAuthUser:
24 | # basic auth password
25 | # basicAuthPassword:
26 | # enable/disable with credentials headers
27 | # withCredentials:
28 | # mark as default datasource. Max one per org
29 | isDefault: true
30 | #