Giter VIP home page Giter VIP logo

rq-exporter's Introduction

Python RQ Prometheus Exporter

PyPI PyPI - Python Version Libraries.io dependency status for latest release Docker Image Size (latest semver)

Prometheus metrics exporter for Python RQ (Redis Queue) job queue library.

Grafana dashboard

Installation

Install the Python package:

$ # Install the latest version
$ pip install rq-exporter
$ # Or install a specific version
$ pip install rq-exporter==2.1.0

Or download the Docker image:

$ # Pull the latest image
$ docker pull mdawar/rq-exporter
$ # Or pull a specific version
$ docker pull mdawar/rq-exporter:v2.1.0

The releases are available as Docker image tags.

Usage

Python package:

$ # Start the exporter on port 9726
$ rq-exporter
$ # Start the exporter on a specific port and host (Default: 0.0.0.0:9726)
$ rq-exporter --host localhost --port 8080
$ # By default the exporter will connect to Redis on `localhost` port `6379`
$ # You can specify a Redis URL
$ rq-exporter --redis-url redis://:123456@redis_host:6379/0
$ # Or specific Redis options (host, port, db, password)
$ rq-exporter --redis-host 192.168.1.10 --redis-port 6380 --redis-pass 123456 --redis-db 1
$ # You can also specify a password file path (eg: mounted Docker secret)
$ rq-exporter --redis-pass-file /run/secrets/redis_pass

Docker image:

$ # Run the exporter and publish the port 9726 on the host
$ docker run -it -p 9726:9726 rq-exporter
$ # Use the -d option to run the container in the background (detached)
$ docker run -d -p 9726:9726 rq-exporter
$ # All the command line arguments will be passed to rq-exporter
$ docker run -it -p 9726:9726 rq-exporter --redis-host redis --redis-pass 123456
$ # You can also configure the exporter using environment variables
$ docker run -it -p 9726:9726 -e RQ_REDIS_HOST=redis -e RQ_REDIS_PASS=123456 rq-exporter

Grafana Dashboard

An example Grafana dashboard is available with the ID 12196 for showcasing this exporter's metrics.

You can also find the JSON file of the dashboard in this repository.

Note:

  • This is just an example dashboard, feel free to use it as a base for your custom dashboard
  • You need to adjust the color thresholds to suit your needs for the job status percentage singlestat panels
  • Some panels might seem duplicated providing percentages and current values, these are just for showcasing the PromQL queries

Exported Metrics

RQ metrics:

Metric Name Type Labels Description
rq_workers Gauge name, queues, state RQ workers
rq_jobs Gauge queue, status RQ jobs by queue and status
rq_workers_success_total Counter name, queues Successful job count by worker
rq_workers_failed_total Counter name, queues Failed job count by worker
rq_workers_working_time_total Counter name, queues Total working time in seconds by worker

Request processing metrics:

Metric Name Type Description
rq_request_processing_seconds_count Summary Number of times the RQ data were collected
rq_request_processing_seconds_sum Summary Total sum of time spent collecting RQ data
rq_request_processing_seconds_created Gauge Time created at (time.time() return value)

Example:

# HELP rq_request_processing_seconds Time spent collecting RQ data
# TYPE rq_request_processing_seconds summary
rq_request_processing_seconds_count 1.0
rq_request_processing_seconds_sum 0.029244607000009637
# TYPE rq_request_processing_seconds_created gauge
rq_request_processing_seconds_created 1.5878023726039658e+09
# HELP rq_workers RQ workers
# TYPE rq_workers gauge
rq_workers{name="40d33ed9541644d79373765e661b7f38", queues="default", state="idle"} 1.0
rq_workers{name="fe9a433575e04685a53e4794b2eaeea9", queues="high,default,low", state="busy"} 1.0
# HELP rq_jobs RQ jobs by state
# TYPE rq_jobs gauge
rq_jobs{queue="default", status="queued"} 2.0
rq_jobs{queue="default", status="started"} 1.0
rq_jobs{queue="default", status="finished"} 5.0
rq_jobs{queue="default", status="failed"} 1.0
rq_jobs{queue="default", status="deferred"} 1.0
rq_jobs{queue="default", status="scheduled"} 2.0

Configuration

You can configure the exporter using command line arguments or environment variables:

CLI Argument Env Variable Default Value Description
--host RQ_EXPORTER_HOST 0.0.0.0 Serve the exporter on this host
-p, --port RQ_EXPORTER_PORT 9726 Serve the exporter on this port
--redis-url RQ_REDIS_URL None Redis URL in the form redis://:[password]@[host]:[port]/[db]
--redis-host RQ_REDIS_HOST localhost Redis host name
--redis-port RQ_REDIS_PORT 6379 Redis port number
--redis-db RQ_REDIS_DB 0 Redis database number
--sentinel-host RQ_SENTINEL_HOST None Redis Sentinel hosts separated by commas e.g sentinel1,sentinel2:26380
--sentinel-port RQ_SENTINEL_PORT 26379 Redis Sentinel port, default port used when not set with the host
--sentinel-master RQ_SENTINEL_MASTER master Redis Sentinel master name
--redis-pass RQ_REDIS_PASS None Redis password
--redis-pass-file RQ_REDIS_PASS_FILE None Redis password file path (e.g. Path of a mounted Docker secret)
--worker-class RQ_WORKER_CLASS rq.Worker RQ worker class
--queue-class RQ_QUEUE_CLASS rq.Queue RQ queue class
--log-level RQ_EXPORTER_LOG_LEVEL INFO Logging level
--log-format RQ_EXPORTER_LOG_FORMAT [%(asctime)s] [%(name)s] [%(levelname)s]: %(message)s Logging handler format string
--log-datefmt RQ_EXPORTER_LOG_DATEFMT %Y-%m-%d %H:%M:%S Logging date/time format string

Notes:

  • When Redis URL is set using --redis-url or RQ_REDIS_URL the other Redis options will be ignored
  • When the Redis password is set using --redis-pass-file or RQ_REDIS_PASS_FILE, then --redis-pass and RQ_REDIS_PASS will be ignored
  • The Sentinel port will default to the value of --sentinel-port if not set for each host with --sentinel-host or RQ_SENTINEL_HOST

Serving with Gunicorn

The WSGI application can be created using the rq_exporter.create_app() function:

$ gunicorn "rq_exporter:create_app()" -b 0.0.0.0:9726 --log-level info

Example Dockerfile to create a Docker image to serve the application with Gunicorn

FROM mdawar/rq-exporter:latest

USER root

RUN pip install --no-cache-dir gunicorn

USER exporter

ENTRYPOINT ["gunicorn", "rq_exporter:create_app()"]

CMD ["-b", "0.0.0.0:9726", "--threads", "2", "--log-level", "info", "--keep-alive", "3"]

Note about concurrency:

The exporter is going to work without any problems with multiple workers but you will get different values for these metrics:

  • rq_request_processing_seconds_count
  • rq_request_processing_seconds_sum
  • rq_request_processing_seconds_created

This is fine if you don't care about these metrics, these are only for measuring the count and time processing the RQ data, so the other RQ metrics are not going to be affected.

But you can still use multiple threads with 1 worker process to handle multiple concurrent requests:

$ gunicorn "rq_exporter:create_app()" -b 0.0.0.0:9726 --threads 2

Building the Docker Image

$ # Build the docker image and tag it rq-exporter:latest
$ docker build -t rq-exporter .
$ # Or
$ make build

$ # M1 MacOS Build the docker image and tag it rq-exporter:latest
$ docker buildx build --platform linux/amd64 -t rq-exporter .

The image can also be built using docker compose:

$ docker compose build

Check the docker-compose.yml file for usage example.

Development

To start a full development environment with RQ workers, Prometheus and Grafana:

$ docker compose up
$ # If you want to start multiple workers use the --compatibility flag
$ # which will make docker compose read the `deploy` section and start multiple replicas
$ docker compose --compatibility up

You can access the services on these ports on your local machine:

  • RQ exporter: 9726
  • Redis: 6379
  • RQ Dashboard: 9181
  • Prometheus: 9090
  • Grafana: 3000 (Login using admin:admin)

You can specify the services that you want to start by their name in the docker-compose.yml file:

$ # Example starting only the `rq_exporter` and `redis` services
$ docker compose up rq_exporter redis

To run more workers and enqueue more jobs you can scale the worker and enqueue services:

$ # Run 5 workers
$ docker compose up -d --scale worker=5
$ # Enqueue more jobs
$ # Scale the enqueue service and the workers
$ docker compose up -d --scale worker=5 --scale enqueue=2

To cleanup after development:

$ # Use -v to remove volumes
$ docker compose down -v

You can also start another rq-exporter instance that collects stats from a project using custom RQ Worker and Queue classes:

$ # Using -f to pass multiple docker-compose files
$ # docker-compose.custom.yml defines services using custom RQ classes
$ docker compose -f docker-compose.yml -f docker-compose.custom.yml up
$ # To cleanup you need to also pass the same files
$ docker compose -f docker-compose.yml -f docker-compose.custom.yml down

A new RQ exporter instance will be exposed on port 9727 on your local machine.

Note: If you don't have docker compose installed follow the installation instructions on the official website.

If you want to use the package manually:

$ # Clone the repository
$ git clone <REPO_URL>
$ # Change to the project directory
$ cd rq-exporter
$ # Create a new virtualenv
$ python -m venv /path/to/env
$ # Activate the environment
$ source /path/to/env/bin/activate
$ # Install the requirements
$ pip install -r requirements.txt
$ # Start the exporter on port 9726
$ python -m rq_exporter
$ # You can configure the exporter using command line arguments
$ python -m rq_exporter --port 8080

Running the Tests

$ make test
$ # Or
$ python -m unittest

Contributing

  1. Fork the repository
  2. Clone the forked repository git clone <URL>
  3. Create a new feature branch git checkout -b <BRANCH_NAME>
  4. Make changes and add tests if needed and commit your changes git commit -am "Your commit message"
  5. Push the new branch to Github git push origin <BRANCH_NAME>
  6. Create a pull request

rq-exporter's People

Contributors

aleksandr-vin avatar bzd111 avatar mdawar avatar mkotsalainen avatar opetrenko-grid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rq-exporter's Issues

Latest docker image (4 months old now) has vulnerabilities with known fixes

Running trivy on the image discovered these vulns:

25-Mar-2022 13:05:30 | mdawar/rq-exporter:latest (debian 10.11)
-- | --
25-Mar-2022 13:05:30 | ========================================
25-Mar-2022 13:05:30 | Total: 8 (CRITICAL: 8)
25-Mar-2022 13:05:30 |  
25-Mar-2022 13:05:30 | +-----------+------------------+----------+-------------------+-----------------+---------------------------------------+
25-Mar-2022 13:05:30 | \|  LIBRARY  \| VULNERABILITY ID \| SEVERITY \| INSTALLED VERSION \|  FIXED VERSION  \|                 TITLE                 \|
25-Mar-2022 13:05:30 | +-----------+------------------+----------+-------------------+-----------------+---------------------------------------+
25-Mar-2022 13:05:30 | \| libexpat1 \| CVE-2022-22822   \| CRITICAL \| 2.2.6-2+deb10u1   \| 2.2.6-2+deb10u2 \| expat: Integer overflow in            \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| addBinding in xmlparse.c              \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-22822 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +                 +---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-22823   \|          \|                   \|                 \| expat: Integer overflow in            \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| build_model in xmlparse.c             \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-22823 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +                 +---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-22824   \|          \|                   \|                 \| expat: Integer overflow in            \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| defineAttribute in xmlparse.c         \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-22824 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +                 +---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-23852   \|          \|                   \|                 \| expat: Integer overflow               \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| in function XML_GetBuffer             \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-23852 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +                 +---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-23990   \|          \|                   \|                 \| expat: integer overflow               \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| in the doProlog function              \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-23990 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +-----------------+---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-25235   \|          \|                   \| 2.2.6-2+deb10u3 \| expat: Malformed 2- and               \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| 3-byte UTF-8 sequences can            \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| lead to arbitrary code...             \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-25235 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +                 +---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-25236   \|          \|                   \|                 \| expat: Namespace-separator characters \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| in "xmlns[:prefix]" attribute         \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| values can lead to arbitrary code...  \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-25236 \|
25-Mar-2022 13:05:30 | +           +------------------+          +                   +                 +---------------------------------------+
25-Mar-2022 13:05:30 | \|           \| CVE-2022-25315   \|          \|                   \|                 \| expat: Integer overflow               \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| in storeRawNames()                    \|
25-Mar-2022 13:05:30 | \|           \|                  \|          \|                   \|                 \| -->avd.aquasec.com/nvd/cve-2022-25315 \|
25-Mar-2022 13:05:30 | +-----------+------------------+----------+-------------------+-----------------+---------------------------------------+
25-Mar-2022 13:05:30

Image needs rebuilding to pickup security fixes in it's base image.

use of gauge

Hi there, thanks for this nice project! I'm curious about how you configure your rq queues to get useful statistics out of the gauges. The finished jobs are by default automatically cleaned so eventually the gauge loses track of them - or do you not care about historical numbers but really about the current state? Naively I would expect the summary metrics to be more appropriate, but perhaps I have a different use-case in mind.

package in requirements.txt?

Hi,
I am adding rq-exporter to my dh-virtualenv package to enable it to be bundled into a deb. However, I'm getting build errors due to a missing requirements.txt. Could it be included please?

Please see the log below

Collecting rq-exporter
  Created temporary directory: /tmp/pip-unpack-zqh9eel1
  Looking up "https://files.pythonhosted.org/packages/9e/24/51c7a5c6182c09e80a1d7c033e25c7ec0636a56980bf6d73befb2b73e582/rq-exporter-1.7.0.tar.gz" in the cache
  Current age based on date: 1096
  Ignoring unknown cache-control directive: immutable
  Freshness lifetime from max-age: 365000000
  The response is "fresh", returning cached response
  365000000 > 1096
  Using cached rq-exporter-1.7.0.tar.gz (13 kB)
  Added rq-exporter from https://files.pythonhosted.org/packages/9e/24/51c7a5c6182c09e80a1d7c033e25c7ec0636a56980bf6d73befb2b73e582/rq-exporter-1.7.0.tar.gz#sha256=ba04d06995c1e8c80034e5a1338602698e4168947eb8b636db3faa5e02fd5890 (from -r ./requirements.txt (line 48)) to build tracker '/tmp/pip-req-tracker-bfed8oje'
    Running setup.py (path:/tmp/pip-install-sbgw6_s7/rq-exporter_5cb720af2376430982edde4deffb2779/setup.py) egg_info for package rq-exporter
    Created temporary directory: /tmp/pip-pip-egg-info-tkk93zi2
    Running command python setup.py egg_info
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-sbgw6_s7/rq-exporter_5cb720af2376430982edde4deffb2779/setup.py", line 19, in <module>
        with open(os.path.join(cwd, 'requirements.txt'), 'r') as f:
    FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pip-install-sbgw6_s7/rq-exporter_5cb720af2376430982edde4deffb2779/requirements.txt'
WARNING: Discarding https://files.pythonhosted.org/packages/9e/24/51c7a5c6182c09e80a1d7c033e25c7ec0636a56980bf6d73befb2b73e582/rq-exporter-1.7.0.tar.gz#sha256=ba04d06995c1e8c80034e5a1338602698e4168947eb8b636db3faa5e02fd5890 (from https://pypi.org/simple/rq-exporter/) (requires-python:>=3.6). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
  Created temporary directory: /tmp/pip-unpack-hgngpqso
  Looking up "https://files.pythonhosted.org/packages/0b/74/23930e7273410a85f0cad92e6e5916f3d70a82b847d9401e7fd7b4c6f5f3/rq-exporter-1.6.0.tar.gz" in the cache
  No cache entry available
  Starting new HTTPS connection (1): files.pythonhosted.org:443
  https://files.pythonhosted.org:443 "GET /packages/0b/74/23930e7273410a85f0cad92e6e5916f3d70a82b847d9401e7fd7b4c6f5f3/rq-exporter-1.6.0.tar.gz HTTP/1.1" 200 13357
  Downloading rq-exporter-1.6.0.tar.gz (13 kB)
  Ignoring unknown cache-control directive: immutable
  Updating cache with response from "https://files.pythonhosted.org/packages/0b/74/23930e7273410a85f0cad92e6e5916f3d70a82b847d9401e7fd7b4c6f5f3/rq-exporter-1.6.0.tar.gz"
  Caching due to etag
  Added rq-exporter from https://files.pythonhosted.org/packages/0b/74/23930e7273410a85f0cad92e6e5916f3d70a82b847d9401e7fd7b4c6f5f3/rq-exporter-1.6.0.tar.gz#sha256=7e90bcbf5d9939ec33379788d3179136dd31ebb669e3aa265befcbffb76ce4e6 (from -r ./requirements.txt (line 48)) to build tracker '/tmp/pip-req-tracker-bfed8oje'
    Running setup.py (path:/tmp/pip-install-sbgw6_s7/rq-exporter_8aac3f9b0ecd44b7aa6b5d5b8f75fb3e/setup.py) egg_info for package rq-exporter
    Created temporary directory: /tmp/pip-pip-egg-info-ge3qcjgc
    Running command python setup.py egg_info
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-sbgw6_s7/rq-exporter_8aac3f9b0ecd44b7aa6b5d5b8f75fb3e/setup.py", line 19, in <module>
        with open(os.path.join(cwd, 'requirements.txt'), 'r') as f:
    FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pip-install-sbgw6_s7/rq-exporter_8aac3f9b0ecd44b7aa6b5d5b8f75fb3e/requirements.txt'

Export job start/end times

Firstly, RQ Exporter has been an excellent!

Do you think it'd be possible to include an option to export Job start/end times? I believe this should be accessible at job.started_at and job.ended_at per rq docs.

Remove: PR

I created a pull request in the upstream of my forked repo in error.

I closed it but can we remove or hide that in any way from public view?

Cannot run with gunicorn, missing import

[2021-01-06 12:09:08 +0000] [1] [INFO] Starting gunicorn 20.0.4
[2021-01-06 12:09:08 +0000] [1] [INFO] Listening at: http://0.0.0.0:9726 (1)
[2021-01-06 12:09:08 +0000] [1] [INFO] Using worker: threads
[2021-01-06 12:09:08 +0000] [8] [INFO] Booting worker with pid: 8
[2021-01-06 12:09:08 +0000] [8] [ERROR] Exception in worker process
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
    worker.init_process()
  File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/gthread.py", line 92, in init_process
    super().init_process()
  File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/base.py", line 119, in init_process
    self.load_wsgi()
  File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
    self.wsgi = self.app.wsgi()
  File "/usr/local/lib/python3.8/site-packages/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "/usr/local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
    return self.load_wsgiapp()
  File "/usr/local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/usr/local/lib/python3.8/site-packages/gunicorn/util.py", line 411, in import_app
    app = app(*args, **kwargs)
  File "/app/rq_exporter/exporter.py", line 57, in create_app
    worker_class = import_attribute(config.RQ_WORKER_CLASS)
NameError: name 'import_attribute' is not defined
[2021-01-06 12:09:08 +0000] [8] [INFO] Worker exiting (pid: 8)
[2021-01-06 12:09:08 +0000] [1] [INFO] Shutting down: Master
[2021-01-06 12:09:08 +0000] [1] [INFO] Reason: Worker failed to boot.

rq_workers and rq_jobs metrics are empty when checked in Prometheus

rq_workers and rq_jobs metrics are empty when checked in Prometheus. I could see the output for rq_request_processing_seconds_count this metric. All the jobs and workers are under a specific namespace under database 0. Should we specify the namespace in the url RQ_REDIS_URL ? Could you please let me know what could be the reason for workers and jobs metrics are empty ?

how to disable sentinel support in v1.9.0

I have a regular single instance of redis running in a k8s pod, and as a side car app I was running v1.8.0 of rq-exporter. Looked to upgrade the version to v1.9.0 and received the error

  File "/usr/local/lib/python3.8/site-packages/redis/sentinel.py", line 219, in discover_master
    raise MasterNotFoundError("No master found for %r" % (service_name,))
redis.sentinel.MasterNotFoundError: No master found for 'master'

How could I use rq-exporter v1.9.0 just for non-sentinel redis? Thank you and I really am grateful I found this tool for our monitoring purposes.

Concerns about metric labels cardinality

Hi all.

I am running ~100 rq workers and they all generate UUID names, which results in /metrics pollution: each worker-specific metric times 100 -> ~400 metrics. I also deploy my application quite frequently, let's say once a day on weekdays. This results in ~2000 label values per week, ~8000 per month and so on. This is a huge cardinality which translates into high resource usage of the Prometheus infrastructure.

I can't use specific names because they have to be unique. I can't use some kind of sequential worker ID because I have a graceful deployment and those sequences are going to overlap. I am left with some kind of scraper configuration, using regular expressions, which removes the names and makes it less generic worker-type-N -> worker-type. Which looks like a hack. :(

So this is my concern and I would like to hear your opinion. This is still a great library, thank.

  • Have you thought about the cardinality?
  • Was it intentional to have names in the metrics?
  • Have you dealt with these kinds of issues in your usage scenarios?

Version lock to rq==1.4.1

Hello, would it be possible to apply loser version restriction on rq dependency?

Could be rq>1.4 , or if version lock is needed to target the latest rq ( as of writing this 1.5.2) which contains a couple of important bugfixes that I need.

Error: when start the Exporter

Here below is my version details:

Redis:
C:\Users>redis-cli -v
redis-cli 3.0.504

Python :
C:\Users>python
Python 3.10.0 (tags/v3.10.0:b494f59, Oct 4 2021, 19:00:18) [MSC v.1929 64 bit (AMD64)] on win32

How I am starting in my windows environment:

Step 1: C:\Users>pip install rq-exporter
Requirement already satisfied: rq-exporter in c:\program files\python310\lib\site-packages (1.9.0)
Requirement already satisfied: redis>=3.5.3 in c:\program files\python310\lib\site-packages (from rq-exporter) (4.0.1)
Requirement already satisfied: rq>=1.8.0 in c:\program files\python310\lib\site-packages (from rq-exporter) (1.10.0)
Requirement already satisfied: prometheus-client>=0.8.0 in c:\program files\python310\lib\site-packages (from rq-exporter) (0.12.0)
Requirement already satisfied: deprecated in c:\program files\python310\lib\site-packages (from redis>=3.5.3->rq-exporter) (1.2.13)
Requirement already satisfied: click>=5.0.0 in c:\program files\python310\lib\site-packages (from rq>=1.8.0->rq-exporter) (8.0.3)
Requirement already satisfied: colorama in c:\program files\python310\lib\site-packages (from click>=5.0.0->rq>=1.8.0->rq-exporter) (0.4.4)
Requirement already satisfied: wrapt<2,>=1.10 in c:\program files\python310\lib\site-packages (from deprecated->redis>=3.5.3->rq-exporter) (1.13.3)

Step 2: Starting the exporter:
C:\Users>rq-exporter
C:\Program Files\Python310\lib\site-packages\redis\connection.py:72: UserWarning: redis-py works best with hiredis. Please consider installing
warnings.warn(msg)
[2021-11-19 15:01:26] [rq_exporter] [ERROR]: Incorrect RQ class location
Traceback (most recent call last):
File "C:\Program Files\Python310\lib\site-packages\rq_exporter_main_.py", line 241, in main
REGISTRY.register(RQCollector(connection, worker_class, queue_class))
File "C:\Program Files\Python310\lib\site-packages\prometheus_client\registry.py", line 26, in register
names = self._get_names(collector)
File "C:\Program Files\Python310\lib\site-packages\prometheus_client\registry.py", line 66, in _get_names
for metric in desc_func():
File "C:\Program Files\Python310\lib\site-packages\rq_exporter\collector.py", line 55, in collect
for worker in get_workers_stats(self.worker_class):
File "C:\Program Files\Python310\lib\site-packages\rq_exporter\utils.py", line 70, in get_workers_stats
workers = worker_class.all()
File "C:\Program Files\Python310\lib\site-packages\rq\worker.py", line 123, in all
worker_keys = get_keys(queue=queue, connection=connection)
File "C:\Program Files\Python310\lib\site-packages\rq\worker_registration.py", line 47, in get_keys
return {as_text(key) for key in redis.smembers(redis_key)}
File "C:\Program Files\Python310\lib\site-packages\redis\commands\core.py", line 1769, in smembers
return self.execute_command('SMEMBERS', name)
File "C:\Program Files\Python310\lib\site-packages\redis\client.py", line 1067, in execute_command
conn = self.connection or pool.get_connection(command_name, **options)
File "C:\Program Files\Python310\lib\site-packages\redis\connection.py", line 1177, in get_connection
connection.connect()
File "C:\Program Files\Python310\lib\site-packages\redis\sentinel.py", line 45, in connect
self.connect_to(self.connection_pool.get_master_address())
File "C:\Program Files\Python310\lib\site-packages\redis\sentinel.py", line 113, in get_master_address
master_address = self.sentinel_manager.discover_master(
File "C:\Program Files\Python310\lib\site-packages\redis\sentinel.py", line 234, in discover_master
masters = sentinel.sentinel_masters()
AttributeError: 'Redis' object has no attribute 'sentinel_masters'

This is the error I am facing. Guide me where I did wrong or any pre-requisite thing I need to incomplete?

Improve grafana dashboard

Hello,
Please add queue variable in grafana dashboard to be able to filter all graphs by single click

Regards,
Andrii

rq_ metrics are not collected by the exporter

The below metrics are not collected by the exporter

rq_workers | Gauge | name, queues, state | RQ workers
rq_jobs | Gauge | queue, status | RQ jobs by queue and status
rq_workers_success_total | Counter | name, queues | Successful job count by worker
rq_workers_failed_total | Counter | name, queues | Failed job count by worker
rq_workers_working_time_total | Counter | name, queues | Total working time in seconds by worker

Debug logs of the container:

[2023-12-01 18:33:56] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:33:56] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished
[2023-12-01 18:33:56] [rq_exporter] [INFO]: Serving the application on 0.0.0.0:9726
[2023-12-01 18:34:00] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:34:00] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished
[2023-12-01 18:34:04] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:34:04] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished
[2023-12-01 18:34:14] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:34:14] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished
[2023-12-01 18:34:15] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:34:15] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished
[2023-12-01 18:34:24] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:34:24] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished
[2023-12-01 18:34:30] [rq_exporter.collector] [DEBUG]: Collecting the RQ metrics...
[2023-12-01 18:34:30] [rq_exporter.collector] [DEBUG]: RQ metrics collection finished

Metrics exposed by the exporter

# HELP python_gc_objects_collected_total Objects collected during gc
# TYPE python_gc_objects_collected_total counter
python_gc_objects_collected_total{generation="0"} 258.0
python_gc_objects_collected_total{generation="1"} 268.0
python_gc_objects_collected_total{generation="2"} 0.0
# HELP python_gc_objects_uncollectable_total Uncollectable objects found during GC
# TYPE python_gc_objects_uncollectable_total counter
python_gc_objects_uncollectable_total{generation="0"} 0.0
python_gc_objects_uncollectable_total{generation="1"} 0.0
python_gc_objects_uncollectable_total{generation="2"} 0.0
# HELP python_gc_collections_total Number of times this generation was collected
# TYPE python_gc_collections_total counter
python_gc_collections_total{generation="0"} 65.0
python_gc_collections_total{generation="1"} 5.0
python_gc_collections_total{generation="2"} 0.0
# HELP python_info Python platform information
# TYPE python_info gauge
python_info{implementation="CPython",major="3",minor="8",patchlevel="17",version="3.8.17"} 1.0
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 2.58596864e+08
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 3.0138368e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.70145563537e+09
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.19
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 7.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.048576e+06
# HELP rq_request_processing_seconds Time spent collecting RQ data
# TYPE rq_request_processing_seconds summary
rq_request_processing_seconds_count 22.0
rq_request_processing_seconds_sum 0.03231144789606333
# HELP rq_request_processing_seconds_created Time spent collecting RQ data
# TYPE rq_request_processing_seconds_created gauge
rq_request_processing_seconds_created 1.7014556361013677e+09
# HELP rq_workers RQ workers
# TYPE rq_workers gauge
# HELP rq_workers_success_total RQ workers success count
# TYPE rq_workers_success_total counter
# HELP rq_workers_failed_total RQ workers fail count
# TYPE rq_workers_failed_total counter
# HELP rq_workers_working_time_total RQ workers spent seconds
# TYPE rq_workers_working_time_total counter
# HELP rq_jobs RQ jobs by state
# TYPE rq_jobs gauge

"Not a valid RQ worker key" error when using custom classes

$ docker-compose -f docker-compose.yml -f docker-compose.custom.yml up
Recreating rq-exporter_grafana_1                  ... done
Starting rq-exporter_redis_1        ... done
Recreating rq-exporter_prometheus_1               ... done
Starting rq-exporter_dashboard_1                  ... done
Starting rq-exporter_rq_exporter_1                ... done
Starting rq-exporter_rq_exporter_custom_classes_1 ... done
Starting rq-exporter_enqueue_1                    ... done
Starting rq-exporter_enqueue_custom_classes_1     ... done
Starting rq-exporter_worker_1                     ... done
Starting rq-exporter_worker_2                     ... done
Starting rq-exporter_worker_custom_classes_1      ... done
Starting rq-exporter_worker_custom_classes_2      ... done
Attaching to rq-exporter_redis_1, rq-exporter_grafana_1, rq-exporter_dashboard_1, rq-exporter_rq_exporter_1, rq-exporter_rq_exporter_custom_classes_1, rq-exporter_prometheus_1, rq-exporter_enqueue_1, rq-exporter_enqueue_custom_classes_1, rq-exporter_worker_1, rq-exporter_worker_2, rq-exporter_worker_custom_classes_1, rq-exporter_worker_custom_classes_2
dashboard_1                   | RQ Dashboard version 0.6.0
enqueue_custom_classes_1      | Using queues with custom RQ classes
enqueue_custom_classes_1      | Enqueuing job "process_data" on queue "high"
enqueue_1                     | Enqueuing job "process_data" on queue "low"
dashboard_1                   |  * Running on 0.0.0.0:9181
grafana_1                     | t=2020-11-30T17:24:16+0000 lvl=warn msg="phantomJS is deprecated and will be removed in a future release. You should consider migrating from phantomJS to grafana-image-renderer plugin. Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/" logger=rendering renderer=phantomJS
dashboard_1                   |  * Serving Flask app "rq_dashboard.cli" (lazy loading)
dashboard_1                   |  * Environment: production
dashboard_1                   |    WARNING: This is a development server. Do not use it in a production deployment.
dashboard_1                   |    Use a production WSGI server instead.
dashboard_1                   |  * Debug mode: off
redis_1                       | 1:C 30 Nov 2020 17:24:13.503 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1                       | 1:C 30 Nov 2020 17:24:13.503 # Redis version=5.0.10, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1                       | 1:C 30 Nov 2020 17:24:13.503 # Configuration loaded
rq_exporter_1                 | [2020-11-30 17:24:18] [rq_exporter] [INFO]: Serving the application on 0.0.0.0:9726
rq_exporter_custom_classes_1  | [2020-11-30 17:24:18] [rq_exporter] [INFO]: Serving the application on 0.0.0.0:9726
redis_1                       | 1:M 30 Nov 2020 17:24:13.505 * Running mode=standalone, port=6379.
redis_1                       | 1:M 30 Nov 2020 17:24:13.505 # Server initialized
redis_1                       | 1:M 30 Nov 2020 17:24:13.505 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
worker_2                      | 17:24:20 Worker rq:worker:c1f6df2c68ed486292a0deccabc6a049: started, version 1.6.1
worker_2                      | 17:24:20 Subscribing to channel rq:pubsub:c1f6df2c68ed486292a0deccabc6a049
redis_1                       | 1:M 30 Nov 2020 17:24:13.506 * Ready to accept connections
worker_2                      | 17:24:20 *** Listening on high, default, low...
worker_2                      | 17:24:20 Cleaning registries for queue: high
worker_2                      | 17:24:20 Cleaning registries for queue: default
worker_2                      | 17:24:20 Cleaning registries for queue: low
worker_2                      | 17:24:20 low: jobs.process_data(2) (55375777-b6d9-4ca5-80d9-3f3008366af1)
rq-exporter_prometheus_1 exited with code 1
worker_custom_classes_2       | 17:24:20 Worker rq:custom:worker:cc69e2c9c6c145ea823ccf84981bae67: started, version 1.6.1
worker_custom_classes_2       | 17:24:20 Subscribing to channel rq:pubsub:cc69e2c9c6c145ea823ccf84981bae67
worker_custom_classes_2       | 17:24:20 *** Listening on high, default, low...
worker_custom_classes_2       | 17:24:20 Cleaning registries for queue: high
worker_1                      | 17:24:20 Worker rq:worker:358aca2223bd4d2aa04c8ab57044f34e: started, version 1.6.1
worker_1                      | 17:24:20 Subscribing to channel rq:pubsub:358aca2223bd4d2aa04c8ab57044f34e
worker_custom_classes_1       | Traceback (most recent call last):
worker_custom_classes_1       |   File "/usr/local/bin/rq", line 8, in <module>
worker_custom_classes_1       |     sys.exit(main())
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/click/core.py", line 829, in __call__
worker_custom_classes_1       |     return self.main(*args, **kwargs)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/click/core.py", line 782, in main
worker_custom_classes_1       |     rv = self.invoke(ctx)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
worker_custom_classes_1       |     return _process_result(sub_ctx.command.invoke(sub_ctx))
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
worker_custom_classes_1       |     return ctx.invoke(self.callback, **ctx.params)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
worker_custom_classes_1       |     return callback(*args, **kwargs)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/rq/cli/cli.py", line 78, in wrapper
worker_custom_classes_1       |     return ctx.invoke(func, cli_config, *args[1:], **kwargs)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
worker_custom_classes_1       |     return callback(*args, **kwargs)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/rq/cli/cli.py", line 230, in worker
worker_custom_classes_1       |     cleanup_ghosts(cli_config.connection)
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/rq/contrib/legacy.py", line 25, in cleanup_ghosts
worker_custom_classes_1       |     for worker in Worker.all(connection=conn):
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/rq/worker.py", line 120, in all
worker_custom_classes_1       |     workers = [cls.find_by_key(as_text(key),
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/rq/worker.py", line 120, in <listcomp>
worker_custom_classes_1       |     workers = [cls.find_by_key(as_text(key),
worker_custom_classes_1       |   File "/usr/local/lib/python3.8/site-packages/rq/worker.py", line 146, in find_by_key
worker_custom_classes_1       |     raise ValueError('Not a valid RQ worker key: %s' % worker_key)
worker_custom_classes_1       | ValueError: Not a valid RQ worker key: rq:custom:worker:cc69e2c9c6c145ea823ccf84981bae67
worker_1                      | 17:24:20 *** Listening on high, default, low...
worker_custom_classes_2       | 17:24:20 Cleaning registries for queue: default
worker_custom_classes_2       | 17:24:20 Cleaning registries for queue: low
worker_custom_classes_2       | 17:24:20 high: jobs.process_data(2) (d04e44ff-31f8-4306-a987-331f0579ac36)
rq-exporter_worker_custom_classes_1 exited with code 1
worker_2                      | process_data: sleeping for 2 seconds
worker_2                      | 17:24:22 low: Job OK (55375777-b6d9-4ca5-80d9-3f3008366af1)

Average queue latency

Hi! This project looks good. It would be good to get average latency per queue. I think it should be doable by exposing the total_working_time float that rq updates on every job.

Is this something that you've considered? If not, maybe I could try adding it.

Error - Help

[2021-06-10 19:38:47] [rq_exporter] [ERROR]: There was an error starting the RQ exporter
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/redis/connection.py", line 559, in connect
sock = self._connect()
File "/usr/local/lib/python3.6/site-packages/redis/connection.py", line 615, in _connect
raise err
File "/usr/local/lib/python3.6/site-packages/redis/connection.py", line 589, in _connect
sock = socket.socket(family, socktype, proto)
File "/usr/lib64/python3.6/socket.py", line 144, in init
_socket.socket.init(self, family, type, proto, fileno)
OSError: [Errno 97] Address family not supported by protocol

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/rq_exporter/main.py", line 208, in main
REGISTRY.register(RQCollector(connection, worker_class, queue_class))
File "/usr/local/lib/python3.6/site-packages/prometheus_client/registry.py", line 26, in register
names = self._get_names(collector)
File "/usr/local/lib/python3.6/site-packages/prometheus_client/registry.py", line 66, in _get_names
for metric in desc_func():
File "/usr/local/lib/python3.6/site-packages/rq_exporter/collector.py", line 55, in collect
for worker in get_workers_stats(self.worker_class):
File "/usr/local/lib/python3.6/site-packages/rq_exporter/utils.py", line 60, in get_workers_stats
workers = worker_class.all()
File "/usr/local/lib/python3.6/site-packages/rq/worker.py", line 123, in all
worker_keys = get_keys(queue=queue, connection=connection)
File "/usr/local/lib/python3.6/site-packages/rq/worker_registration.py", line 47, in get_keys
return {as_text(key) for key in redis.smembers(redis_key)}
File "/usr/local/lib/python3.6/site-packages/redis/client.py", line 2281, in smembers
return self.execute_command('SMEMBERS', name)
File "/usr/local/lib/python3.6/site-packages/redis/client.py", line 898, in execute_command
conn = self.connection or pool.get_connection(command_name, **options)
File "/usr/local/lib/python3.6/site-packages/redis/connection.py", line 1192, in get_connection
connection.connect()
File "/usr/local/lib/python3.6/site-packages/redis/connection.py", line 563, in connect
raise ConnectionError(self._error_message(e))
redis.exceptions.ConnectionError: Error 97 connecting to localhost:6379. Address family not supported by protocol.

Create binary files

Hi
I would like to use this exporter on a machine without an internet connection and I cannot use the docker image, is there any linux-amd64 binaries for this exporter?

Kubernetes - Horizontal POD auto scaling

Can any one give me an example of how this can be used to export length of queue and autoscale it.

I want to scale workers when the queue size is more than 25.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.