{"id":37401077,"url":"https://github.com/alex-karpenko/psql-query-exporter","last_synced_at":"2026-01-16T05:44:18.994Z","repository":{"id":147549646,"uuid":"552453338","full_name":"alex-karpenko/psql-query-exporter","owner":"alex-karpenko","description":"Prometheus exporter to produce metrics from PostgreSQL queries","archived":false,"fork":false,"pushed_at":"2025-10-31T19:23:11.000Z","size":317,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-31T21:16:19.688Z","etag":null,"topics":["application-metrics","postgres","postgresql","prometheus","prometheus-exporter"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alex-karpenko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-16T16:23:31.000Z","updated_at":"2025-10-31T19:23:11.000Z","dependencies_parsed_at":"2023-11-24T19:31:18.425Z","dependency_job_id":"db0b1ee9-1c77-4b91-b943-6a9d9881af9d","html_url":"https://github.com/alex-karpenko/psql-query-exporter","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/alex-karpenko/psql-query-exporter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-karpenko%2Fpsql-query-exporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-karpenko%2Fpsql-query-exporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-karpenko%2Fpsql-query-exporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-karpenko%2Fpsql-query-exporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alex-karpenko","download_url":"https://codeload.github.com/alex-karpenko/psql-query-exporter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alex-karpenko%2Fpsql-query-exporter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T03:13:13.607Z","status":"ssl_error","status_checked_at":"2026-01-16T03:11:47.863Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["application-metrics","postgres","postgresql","prometheus","prometheus-exporter"],"created_at":"2026-01-16T05:44:18.874Z","updated_at":"2026-01-16T05:44:18.971Z","avatar_url":"https://github.com/alex-karpenko.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# psql-query-exporter\n\n\u003cp\u003e\n\u003ca href=\"https://github.com/alex-karpenko/psql-query-exporter/actions/workflows/ci.yaml\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/alex-karpenko/psql-query-exporter/ci.yaml?label=ci\" alt=\"CI status\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/alex-karpenko/psql-query-exporter/actions/workflows/audit.yaml\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/alex-karpenko/psql-query-exporter/audit.yaml?label=audit\" alt=\"Audit status\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/alex-karpenko/psql-query-exporter/actions/workflows/publish-image.yaml\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/alex-karpenko/psql-query-exporter/publish-image.yaml?label=publish\" alt=\"Docker image publishing status\"\u003e\u003c/a\u003e\n\u003ca href=\"https://app.codecov.io/github/alex-karpenko/psql-query-exporter\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/alex-karpenko/psql-query-exporter\" alt=\"License\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/alex-karpenko/psql-query-exporter/blob/HEAD/LICENSE\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/github/license/alex-karpenko/psql-query-exporter\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n[Prometheus](https://prometheus.io/docs/introduction/overview/) exporter to produce metrics from [PostgreSQL](https://www.postgresql.org/) queries on a periodic basis.\n\n## Features\n\n- Allows querying of multiple DB instances (hosts) and multiple databases within each instance independently.\n- Flexible configuration of queries, sources (fields) of metrics values, labels, querying intervals, etc.\n- Fast, lightweight and scalable.\n\n## Usage\n\nThe easiest way to run exporter is to use [Docker image](#docker-image).\nIf you use Kubernetes to run workload, you can use [Helm chart](#helm-chart) to configure and deploy exporter.\nThe third way to run exporter is to [build native Rust binary](#build-your-own-binary) using Cargo utility and run it.\n\nAnyway, to run exporter, we need a [configuration file](#configuration) with definition of the scraping targets:\nhosts, databases, queries, labels, etc.\n\n### Docker image\n\nUse the following command to get usage help, the same as running it with `--help` command line option:\n\n```bash\ndocker run --rm alexkarpenko/psql-query-exporter:latest\n```\n\nTypical output is:\n\n```console\nPostgreSQL Query Prometheus exporter\n\nUsage: psql-query-exporter [OPTIONS] --config \u003cCONFIG\u003e\n\nOptions:\n  -d, --debug                  Enable extreme logging (debug)\n  -v, --verbose                Enable additional logging (info)\n  -j, --json-log               Write logs in JSON format\n  -l, --listen-on \u003cLISTEN_ON\u003e  IP/hostname to listen on [default: 0.0.0.0]\n  -p, --port \u003cPORT\u003e            Port to serve http on [default: 9090]\n  -c, --config \u003cCONFIG\u003e        Path to config file\n  -h, --help                   Print help\n  -V, --version                Print version\n```\n\nThe only mandatory parameter is a path to configuration file. Detailed explanation of all possible configuration options is in the dedicated [Configuration](#configuration) section. Just for test purpose, there is an [example config](config.yaml) file to query PostgreSQL server at `localhost` for replication lag values. To use it:\n\n```bash\ndocker run --rm --name psql-query-exporter -v $PWD/config.yaml:/config.yaml -e PG_USER=postgres -e PG_PASSWORD=postgres alexkarpenko/psql-query-exporter:latest --config /config.yaml -v\n```\n\n### Helm chart\n\nTo add Helm repository:\n\n```bash\nhelm repo add alex-karpenko https://alex-karpenko.github.io/helm-charts\nhelm repo update\n```\n\nTo deploy release,\ncreate your own values file with overrides of the default values and your own config section\nand deploy Helm release to your K8s cluster:\n\n```bash\nhelm install psql-query-exporter alex-karpenko/psql-query-exporter -f my-values.yaml\n```\n\nFor example, your values can be like below.\nRemember to create secret `psql-query-exporter` with two keys `PG_USER` and `PG_PASSWORD` with username and password\nto access DB.\n\n```yaml\n# info or debug, anything else - warning\nlogLevel: info\n\nsecrets:\n  - psql-query-exporter\n\nconfig:\n  defaults:\n    scrape_interval: 30s\n    query_timeout: 5s\n    backoff_interval: 10s\n    max_backoff_interval: 300s\n\n  sources:\n    postgres:\n      host: psql-server.postgres.svc.cluster.local\n      user: ${PG_USER}\n      password: ${PG_PASSWORD}\n      sslmode: require\n      metric_prefix: postgres_state\n\n      databases:\n        - dbname: postgres\n          queries:\n            - metric_name: replication_lag\n              description: Storage size and state of replication slots\n              query: |\n                select slot_name, slot_type, active::text,\n                (case when not pg_is_in_recovery() then pg_current_wal_lsn() - restart_lsn end)::float as lag_bytes\n                from pg_replication_slots;\n              values:\n                single:\n                  field: lag_bytes\n                  type: float\n              var_labels:\n                - slot_name\n                - slot_type\n                - active\n```\n\n### Build your own binary\n\nSince exported is written in Rust, you can use standard Rust tools to build binary for any platform you need. Of course, you have to have [Rust](https://rust-lang.org) tool-chain installed.\n\n```bash\ncargo build --release\n```\n\nAnd run it:\n\n```bash\ntarget/release/psql-query-exporter --config ./config.yaml -v\n```\n\n## Configuration\n\nConfiguration file has two sections: optional `defaults` and mandatory `sources`.\n\n### Defaults\n\n`defaults` intended to describe config-wide defaults, all values from this section will be applied to all sources/databases/queries from the `sources` section if the particular value isn't overridden in the corresponding section (if applicable).\n\nHere is the default content of the section, so if you don't specify any value, these defaults will be applied:\n\n```yaml\ndefaults:\n  scrape_interval: 30m  # interval to run each query,\n                        # may be overridden by source/db/query config\n\n  query_timeout: 10s    # timeout to wait for a result of each query,\n                        # may be overridden by source/db/query config\n\n  metric_prefix: \"\"     # prefix for metric name,\n                        # may be overridden by source/db/query config\n\n  sslmode: prefer       # SSL mode to connect to the DB, optional,\n                        # possible values are: disable, prefer, require, verify-ca and verify-full\n                        # may be overridden by source/ config\n\n  sslrootcert: \"\"       # path to additional root (CA) certificates file\n                        # should be in PEM format and may contain more than one certificate\n                        # may be overridden by source config\n\n  sslcert: \"\"           # path to client certificates and key files\n  sslkey: \"\"            # should be in PEM format\n                        # may be overridden by source config\n\n  metric_expiration_time: 0s # if all query attempts during this time were failed,\n                             # then metric should be excluded from the output\n                             # until first successful query execution\n\n  backoff_interval: 10s # default interval between failed connection attempts\n  max_backoff_interval: 300s # every time after failed connection to the DB\n                             # interval between connection attempts increases\n                             # by value of backoff_interval, but no more than value\n                             # of the max_backoff_interval\n\n\n```\n\n### Sources\n\nSecond (mandatory) section is `sources`, it describes:\n\n- which queries should be run;\n- on which DBs;\n- and how to extract and present results as metrics.\n\nSo `sources` section is a dictionary, each key is mnemonic name of the source. Each source is a database instance (DB host) with connection parameters (hostname, username, password, etc.) and list of `databases` inside that instance. Each `database` in the list contains list of `queries` to run against that DB with attributes that describe how to interpret query results and create metrics from them.\n\n#### Sources definition\n\nIn the `host`, `port`, `user`, `password`, `sslrootcert`, `sslcert` and `sslkey` values environment variables can be used to set whole value of the field or part of it, by replacing `${NAME}` with value of the `NAME` environment variable. For example:\n\n```yaml\n  host: db.${ENV_NAME}.example.com\n  user: ${PG_USER}\n  password: ${PG_PASSWORD}\n```\n\n#### Some important remarks about queries\n\n- Query can be any arbitrary SQL query that returns at least one numeric value (int of float column). This value is used as a gauge metrics value.\n- If the query returns more than one values (columns), than either first column is used for metrics value (default) or you should explicitly specify a metrics source in `values.single` section.\n- Query can return more than one valuable column. In such a case you should explicitly describe how to interpret each value and associate each one with either some additional label(s) (`values.multi_labels`) or create separate metrics for each value (`values.multi_suffixes`) by adding suffix to the metrics name.\n- If the value of metric has a float (not default integer) type, you should explicitly specify its type.\n- You can add arbitrary label/value pair(s) to the metric (`const_labels`).\n- You can add variable labels (`var_labels`) to the metric using a query result as a source for values of the labels. In such cases, the query should return non-numeric values (columns) with string type (char, varchar, text).\n- It's your responsibility to write a query that returns value(s) with the correct type of the fields: int/float for the metrics values and char/varchar/text for the labels. Exporter doesn't validate the query statement or guess result's types, it just expects the correct column's type.\n- `single`, `multi_labels` and `multi_suffixes` subsections in the `values` section of the query definition are mutually-exclusive.\n\n#### Detailed configuration with explanation\n\nBelow is a detailed explanation of all possible configuration parameters. Default values for optional parameters are specified.\n\nValues of `defaults` (from the previous section) will be propagated to all underneath sections, level by level.\nSo if you specify some value in the `defaults` section,\nthan it will be used in each source, database and query if you don't override it at any level.\nIf you change the value of some parameter,\nit will be propagated in all underneath subsections of the section where it was changed.\n\n```yaml\nsources:\n  source_name_1: # name of the source, just for convenience\n    host: \"\"  # hostname of the DB instance, mandatory,\n              # environment variable can be used here\n    port: 5432  # port number of the DB, default is 5432\n                # environment variable can be used here\n    user: \"\"  # username to log in to the DB, mandatory,\n              # environment variable can be used here\n    password: \"\"  # password to log in to the DB, mandatory,\n                  # environment variable can be used here\n    sslmode: prefer   # SSL mode to connect to the DB, optional,\n                      # possible values are: disable, prefer, require, verify-ca and verify-full\n    sslrootcert: \"\"   # path to additional root (CA) certificates file\n                      # should be in PEM format and may contain more than one certificate\n    sslcert: \"\"       # path to client certificates and key files\n    sslkey: \"\"        # should be in PEM format\n                      # may be overridden by source config\n    scrape_interval: 30m  # scrape interval for all DBs/queries of the source, optional,\n                          # overrides value from the default section,\n                          # can be overridden in the DB/query section\n    query_timeout: 10s  # value of the query timeout for all DBs/queries of the source, optional,\n                        # overrides value from the default section,\n                        # can be overridden in the DB/query section\n    metric_expiration_time: 0s  # if all query attempts during this time were failed,\n                                # then metric should be excluded from the output\n                                # until first successful query execution\n    backoff_interval: 10s # default interval between failed connection attempts\n    max_backoff_interval: 300s # every time after failed connection to the DB\n                              # interval between connection attempts increases\n                              # by value of backoff_interval, but no more than value\n                              # of the max_backoff_interval\n    metric_prefix: \"\" # will be added to names of the all metrics for these DBs/queries, optional,\n                      # overrides value from the default section,\n                      # can be overridden in the DB/query section\n\n    databases:   # list of the databases inside the instance, mandatory\n      - dbname: \"\"  # DB name, mandatory\n        scrape_interval: 30m  # the same as above, applied to all queries of the DB, optional\n        query_timeout: 10s    # the same as above, applied to all queries of the DB, optional\n        metric_expiration_time: 0s  # if all query attempts during this time were failed,\n                                    # then metric should be excluded from the output\n                                    # until first successful query execution\n        backoff_interval: 10s # default interval between failed connection attempts\n        max_backoff_interval: 300s # every time after failed connection to the DB\n                                  # interval between connection attempts increases\n                                  # by value of backoff_interval, but no more than value\n                                  # of the max_backoff_interval\n        metric_prefix: \"\"     # the same as above, applied to all queries of the DB, optional\n\n        queries:  # list of queries to run against this particular instance/db, mandatory\n          - query: \"\" # query string, mandatory\n            description: \"\" # Metrics description, it will be presented in HELP part of the metrics output\n                            # If metric has multi_suffixes (see below) than suffix will be added to the description after semicolon\n                            # Default is metrics name\n            metric_name: \"\" # name that will be joined with the metric_prefix and underscore, mandatory\n                            # if metric_prefix is empty, metric_name is used to form the final name of the metric\n            scrape_interval: 30m  # the same as above, applied to this query, optional\n            query_timeout: 10s    # the same as above, applied to this query, optional\n            metric_expiration_time: 0s  # if all query attempts during this time were failed,\n                                        # then metric should be excluded from the output\n                                        # until first successful query execution\n            metric_prefix: \"\"     # the same as above, applied to this query, optional\n\n            # All values below are just for example, it's not default values.\n            const_labels:           # all key/value pairs of these sections will be added to the metric definition(s) of the query, optional\n              label1: label_value1  # if metric_prefix=\"some_prefix\" and metric_name=\"metric\" then result metric will look like\n              label2: label_value2  # some_prefix_metric{label1=\"label_value1\",label2=\"label_value2\"}\n\n            var_labels: # if query result has text column(s), they can be used as label values\n              - label1  # in such cases, you should specify column names here as label names\n              - label2  # values from the columns will be used as label values\n\n            values: # if you need to explicitly specify metrics source or query returns multi-value result,\n                    # you should use this section to describe how to grab value(s)\n              single: # use single field as a source\n                field: field1\n                type: int # int (default) or float, optional\n              multi_labels: # use several fields and differentiate and create single metric with different additional labels\n                - field: field2\n                  type: int # int (default) or float, optional\n                  labels:\n                    label1: label_value1\n                    label2: label_value2\n                - field: field3\n                  type: int # int (default) or float, optional\n                  labels:\n                    label1: label_value1\n                    label2: label_value3\n              multi_suffixes: # create a separate metric for each value by adding suffix to the metric name\n                - field: field4\n                  type: int # int (default) or float, optional\n                  suffix: suffix1\n                - field: field5\n                  type: int # int (default) or float, optional\n                  suffix: suffix2\n\n          - query: \"\" # next query from the same db\n            .\n            .\n            .\n          - query: ...\n\n      - dbname: \"\" # next db at the same instance\n        .\n        .\n        .\nsource_name_2:\n  .\n  .\n  .\nsource_name_3:\n  .\n  .\n  .\n```\n\n#### Threads and timings\n\nEach database (not DB instance, but each item in the `sources.databases` list) uses its own thread to run querying loop.\nIn other words, one list of queries uses its own thread to process all queries.\nJust for example,\nif you have three DB instances (source) in the config with five DB names in each instance\n(five items in the databases' list), then 15 threads will be run to serve a querying process.\n\nEach thread is lightweight and spends almost all time sleeping and waiting for time to run the next query in the list.\nSo if you need to run heavy queries with long running-time be cautious\nand pay some attention to such parameters as `query_timeout` and `scrape_interval`,\nbecause each query in the list within each database entry will be running one-by-one with respect to the scrape interval of each query.\n\nFor example,\nif you set a scrape interval to the 10s and query timeout to 5s\nand each of two queries in the list needs 5s to return a result,\nthen all other queries within the same database will be postponed until the end of that two.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falex-karpenko%2Fpsql-query-exporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falex-karpenko%2Fpsql-query-exporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falex-karpenko%2Fpsql-query-exporter/lists"}