From 776c98fb474935f04bc521428385c01c972e1439 Mon Sep 17 00:00:00 2001 From: Kumi Date: Thu, 16 May 2024 06:33:21 +0200 Subject: [PATCH 1/3] feat: Enhance config flexibility and setup Introduced command-line flags for improved configuration management, including the creation of a default config file, and specified listening address override capabilities. This update facilitates easier and more flexible setup and deployment processes for the PostgreSQL connection exporter. The `.gitignore` and documentation were updated to align with these changes, reflecting the new command-line options and the removal of the `config.dist.yaml` in favor of creating a default configuration through the tool itself. - Command-line flags `--create-config`, `--config`, `--host`, and `--port` added to streamline customization. - Configuration now supports naming database hosts for clearer metrics identification. - Documentation revised to guide through the new configuration and setup process. - Changelog introduced to track project evolution. These enhancements aim to make the exporter more adaptable to various deployment environments and to simplify the initial setup for users. --- .gitignore | 3 +- CHANGELOG.md | 16 ++++ README.md | 34 +++++++- config.dist.yaml | 8 -- pyproject.toml | 2 +- src/postgres_connection_exporter/__main__.py | 79 ++++++++++++++++--- .../config.dist.yaml | 16 ++++ 7 files changed, 135 insertions(+), 23 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 config.dist.yaml create mode 100644 src/postgres_connection_exporter/config.dist.yaml diff --git a/.gitignore b/.gitignore index 91c9bd0..2c07b91 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ config.yaml __pycache__ *.pyc -venv \ No newline at end of file +venv/ +dist/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..eda59e9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +## v0.0.2 + +### Added + +- Add `--create-config` flag to create a default configuration file +- Add `--config` flag to specify a configuration file +- Add `--host` and `--port` flags to specify the address to listen on +- Make listening address configurable in the `config.yaml` file + +## v0.0.1 + +### Added + +- Initial release diff --git a/README.md b/README.md index 78b0e8e..5d6e740 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,27 @@ You can install the exporter from PyPI. Within a virtual environment, run: pip install postgres-connection-exporter ``` -## Usage +## Configuration -The exporter is configured using a `config.yaml`. You can find an example in [config.dist.yaml](config.dist.yaml). +The exporter is configured using a `config.yaml`. You can create a default configuration file in the current working directory with: + +```bash +postgres-connection-exporter --create-config +``` + +Now, edit the `config.yaml` file to match your PostgreSQL connection settings. Here is an example configuration: + +```yaml +hosts: + host: localhost + port: 5432 + user: postgres + password: postgres +``` + +The user must have the `pg_monitor` role to access the `pg_stat_activity` view. + +## Usage After you have created your `config.yaml`, you can start the exporter with: @@ -27,6 +45,18 @@ After you have created your `config.yaml`, you can start the exporter with: postgres-connection-exporter ``` +By default, the exporter listens on `localhost:8989`. You can change the address in the `config.yaml` file, or using the `--host` and `--port` flags: + +```bash +postgres-connection-exporter --host 0.0.0.0 --port 9898 +``` + +You can also specify a different configuration file with the `--config` flag: + +```bash +postgres-connection-exporter --config /path/to/config.yaml +``` + ## License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/config.dist.yaml b/config.dist.yaml deleted file mode 100644 index e166c40..0000000 --- a/config.dist.yaml +++ /dev/null @@ -1,8 +0,0 @@ -hosts: # List of database hosts - # Each host must have a user, password, host, and optionally port - - user: "user1" - password: "password1" - host: "host1" - port: "5432" -exporter: - port: 8989 # Port on which the exporter will listen diff --git a/pyproject.toml b/pyproject.toml index 27a97a3..ebf60f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "postgres-connection-exporter" -version = "0.0.1" +version = "0.0.2" authors = [ { name="Kumi Mitterer", email="postgres-connection-exporter@kumi.email" }, ] diff --git a/src/postgres_connection_exporter/__main__.py b/src/postgres_connection_exporter/__main__.py index f83b53f..557104e 100644 --- a/src/postgres_connection_exporter/__main__.py +++ b/src/postgres_connection_exporter/__main__.py @@ -2,6 +2,10 @@ import yaml from prometheus_client import start_http_server, Gauge import psycopg2 import time +import argparse +import pathlib +import shutil +import sys CONNECTIONS_PER_DB = Gauge( "db_connections_per_database", @@ -56,6 +60,8 @@ def get_all_databases(db_config): def get_db_connections(db_config): try: + host_identifier = db_config.get("name") or db_config["host"] + # Connect to the PostgreSQL database conn = psycopg2.connect( dbname="postgres", @@ -76,7 +82,7 @@ def get_db_connections(db_config): ) db_connections = cursor.fetchall() for db, count in db_connections: - CONNECTIONS_PER_DB.labels(database=db, host=db_config["host"]).set(count) + CONNECTIONS_PER_DB.labels(database=db, host=host_identifier).set(count) # Query to get the number of connections per user cursor.execute( @@ -88,7 +94,7 @@ def get_db_connections(db_config): ) user_connections = cursor.fetchall() for user, count in user_connections: - CONNECTIONS_PER_USER.labels(user=user, host=db_config["host"]).set(count) + CONNECTIONS_PER_USER.labels(user=user, host=host_identifier).set(count) # Query to get the number of connections by state cursor.execute( @@ -100,7 +106,7 @@ def get_db_connections(db_config): ) state_connections = cursor.fetchall() for state, count in state_connections: - CONNECTIONS_BY_STATE.labels(state=state, host=db_config["host"]).set(count) + CONNECTIONS_BY_STATE.labels(state=state, host=host_identifier).set(count) # Query to get the number of connections per source cursor.execute( @@ -112,7 +118,9 @@ def get_db_connections(db_config): ) source_connections = cursor.fetchall() for source, count in source_connections: - CONNECTIONS_PER_SOURCE.labels(source=source, host=db_config["host"]).set(count) + CONNECTIONS_PER_SOURCE.labels(source=source, host=host_identifier).set( + count + ) cursor.close() conn.close() @@ -121,11 +129,45 @@ def get_db_connections(db_config): def main(): - config = load_config() + parser = argparse.ArgumentParser(description="PostgreSQL connection exporter") + parser.add_argument( + "--config", "-c", help="Path to the configuration file", default="config.yaml" + ) + parser.add_argument( + "--create", "-C", help="Create a new configuration file", action="store_true" + ) + parser.add_argument( + "--port", + "-p", + help="Port for the exporter to listen on (default: 8989, or the port specified in the configuration file)", + type=int, + ) + parser.add_argument( + "--host", + help="Host for the exporter to listen on (default: localhost, or the host specified in the configuration file)", + ) + args = parser.parse_args() + + if args.create: + config_file = pathlib.Path(args.config) + if config_file.exists(): + print("Configuration file already exists.") + sys.exit(1) + + template = pathlib.Path(__file__).parent / "config.dist.yaml" + try: + shutil.copy(template, config_file) + print(f"Configuration file created at {config_file}") + sys.exit(0) + except Exception as e: + print(f"Error creating configuration file: {e}") + sys.exit(1) + + config = load_config(args.config) if not ("hosts" in config and config["hosts"]): print("No database hosts specified in the configuration file.") - exit(1) + sys.exit(1) databases_to_query = [] @@ -135,6 +177,7 @@ def main(): exit(1) db_config = { + "name": host.get("name"), "user": host["user"], "password": host["password"], "host": host["host"], @@ -148,13 +191,27 @@ def main(): exit(1) exporter_port = ( - config["exporter"]["port"] - if "exporter" in config and "port" in config["exporter"] - else 8989 + args.port + if args.port + else ( + config["exporter"]["port"] + if "exporter" in config and "port" in config["exporter"] + else 8989 + ) ) - start_http_server(exporter_port) - print(f"Prometheus exporter started on port {exporter_port}") + exporter_host = ( + args.host + if args.host + else ( + config["exporter"]["host"] + if "exporter" in config and "host" in config["exporter"] + else "localhost" + ) + ) + + start_http_server(exporter_port, exporter_host) + print(f"Prometheus exporter started on {exporter_host}:{exporter_port}") while True: for db in databases_to_query: diff --git a/src/postgres_connection_exporter/config.dist.yaml b/src/postgres_connection_exporter/config.dist.yaml new file mode 100644 index 0000000..631295f --- /dev/null +++ b/src/postgres_connection_exporter/config.dist.yaml @@ -0,0 +1,16 @@ +hosts: # List of database hosts + # Each host must have a user, password, host, and optionally port + # A name can be provided to identify the host in the metrics instead of the host address + - name: "myserver" + user: "user1" + password: "password1" + host: "host1" + port: "5432" + - user: "user2" + password: "password2" + host: "host2" + port: "5432" + # As no name is provided, the host address "host2" will be used to identify the host in the metrics +exporter: + host: "localhost" # Network address on which the exporter will listen + port: 8989 # Port on which the exporter will listen From 158c725ab4f5ed38b0669ac48148e5756c70ffd1 Mon Sep 17 00:00:00 2001 From: Kumi Date: Fri, 17 May 2024 15:54:25 +0200 Subject: [PATCH 2/3] feat: Add Postgres Connection Exporter service Introduced a new systemd service for the Postgres Connection Exporter, enhancing monitoring capabilities by tracking database connections. This service configuration ensures it starts after the network is available, runs under a dedicated user and group for security, and is set to automatically restart upon failure, ensuring high availability. The setup aims to streamline deployment and maintenance processes for systems requiring constant database connection monitoring. The service is designed to be easily integrated into multi-user environments, adhering to best practices for system services. --- contrib/postgres-connection-exporter.service | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 contrib/postgres-connection-exporter.service diff --git a/contrib/postgres-connection-exporter.service b/contrib/postgres-connection-exporter.service new file mode 100644 index 0000000..733b727 --- /dev/null +++ b/contrib/postgres-connection-exporter.service @@ -0,0 +1,13 @@ +[Unit] +Description=Postgres Connection Exporter +After=network.target + +[Service] +User=postgres-connection-exporter +Group=postgres-connection-exporter +ExecStart=/srv/postgres-connection-exporter/bin/postgres-connection-exporter +Restart=always +WorkingDirectory=/srv/postgres-connection-exporter + +[Install] +WantedBy=multi-user.target From 1e76c2883f911a9cee0dfe156d6ea1131851b92c Mon Sep 17 00:00:00 2001 From: Renovate Date: Thu, 6 Mar 2025 07:31:06 +0000 Subject: [PATCH 3/3] Add renovate.json --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +}