Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
30b76f6590 | |||
1e76c2883f | |||
158c725ab4 | |||
776c98fb47 |
9 changed files with 154 additions and 23 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -2,4 +2,5 @@
|
|||
config.yaml
|
||||
__pycache__
|
||||
*.pyc
|
||||
venv
|
||||
venv/
|
||||
dist/
|
||||
|
|
16
CHANGELOG.md
Normal file
16
CHANGELOG.md
Normal file
|
@ -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
|
34
README.md
34
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.
|
|
@ -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
|
13
contrib/postgres-connection-exporter.service
Normal file
13
contrib/postgres-connection-exporter.service
Normal file
|
@ -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
|
|
@ -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" },
|
||||
]
|
||||
|
|
6
renovate.json
Normal file
6
renovate.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
|
@ -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:
|
||||
|
|
16
src/postgres_connection_exporter/config.dist.yaml
Normal file
16
src/postgres_connection_exporter/config.dist.yaml
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue