[
  {
    "path": ".github/workflows/release.yaml",
    "content": "name: Release\n\non:\n  push:\n    tags:\n      - 'v*.*.*'\n\npermissions:\n  contents: write\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Set up Go\n        uses: actions/setup-go@v5\n        with:\n          go-version-file: 'go.mod'\n          cache: true\n\n      - name: Run unit tests\n        run: go test ./...\n\n      - name: Run go vet\n        run: go vet ./...\n\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v3\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to Docker Hub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n\n      - name: Run GoReleaser\n        uses: goreleaser/goreleaser-action@v6\n        with:\n          distribution: goreleaser\n          version: latest\n          args: release --clean\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Upload artifacts\n        uses: actions/upload-artifact@v4\n        if: always()\n        with:\n          name: dist\n          path: dist/\n"
  },
  {
    "path": ".github/workflows/test-release.yaml",
    "content": "name: Test Release\n\non:\n  workflow_dispatch:  # 允许手动触发\n  pull_request:\n    paths:\n      - '.goreleaser.yml'\n      - '.github/workflows/release.yaml'\n      - '.github/workflows/test-release.yaml'\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Set up Go\n        uses: actions/setup-go@v5\n        with:\n          go-version-file: 'go.mod'\n          cache: true\n\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v3\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Run unit tests\n        run: go test ./...\n\n      - name: Run go vet\n        run: go vet ./...\n\n      - name: Test GoReleaser config\n        uses: goreleaser/goreleaser-action@v6\n        with:\n          distribution: goreleaser\n          version: latest\n          args: check\n\n      - name: Build snapshot\n        uses: goreleaser/goreleaser-action@v6\n        with:\n          distribution: goreleaser\n          version: latest\n          args: release --snapshot --clean --skip=publish,docker\n\n      - name: List artifacts\n        run: |\n          echo \"Generated artifacts:\"\n          ls -lh dist/*.tar.gz || true\n          echo \"\"\n          echo \"Checksums:\"\n          cat dist/checksums.txt || true\n"
  },
  {
    "path": ".gitignore",
    "content": "# binary files\npg_exporter\n\n# tmp files\ntest/\ndeploy/\nupload.sh\ntemp/\ndist/\n.DS_Store\n\n# IDE files\n.vscode/\n.idea/\n.code/\n.claude\n.codex/\n.codex_tmp/\npg_exporter.iml\nCLAUDE.md\n\n.hugo_build.lock\npublic/\nresources/\ntmp/\n"
  },
  {
    "path": ".goreleaser.yml",
    "content": "version: 2\n\nenv:\n  - CGO_ENABLED=0\n\nbefore:\n  hooks:\n    - go mod download\n    - go mod tidy\n\nbuilds:\n  - id: pg_exporter\n    main: ./main.go\n    binary: pg_exporter\n    goos:\n      - linux\n      - darwin\n      - windows\n    goarch:\n      - amd64\n      - arm64\n      - ppc64le\n    goarm:\n      - 6\n      - 7\n    goamd64:\n      - v1\n    ignore:\n      # Darwin only supports amd64 and arm64\n      - goos: darwin\n        goarch: ppc64le\n      # Windows only supports amd64 and 386\n      - goos: windows\n        goarch: arm64\n      - goos: windows\n        goarch: arm\n      - goos: windows\n        goarch: ppc64le\n    ldflags:\n      - -s -w\n      - -extldflags \"-static\"\n      - -X 'pg_exporter/exporter.Version={{.Version}}'\n      - -X 'pg_exporter/exporter.Branch={{.Branch}}'\n      - -X 'pg_exporter/exporter.Revision={{.ShortCommit}}'\n      - -X 'pg_exporter/exporter.BuildDate={{.Date}}'\n    flags:\n      - -a\n\narchives:\n  - id: pg_exporter\n    name_template: >-\n      {{ .ProjectName }}-{{ .Version }}.{{ .Os }}-\n      {{- if eq .Arch \"amd64\" }}amd64\n      {{- else if eq .Arch \"386\" }}386\n      {{- else if eq .Arch \"arm64\" }}arm64\n      {{- else if eq .Arch \"arm\" }}armv{{ .Arm }}\n      {{- else if eq .Arch \"ppc64le\" }}ppc64le\n      {{- else }}{{ .Arch }}{{ end }}\n    files:\n      - pg_exporter.yml\n      - LICENSE\n      - package/pg_exporter.default\n      - package/pg_exporter.service\n\nnfpms:\n  - id: pg_exporter_rpm\n    package_name: pg_exporter\n    file_name_template: >-\n      {{ .PackageName }}-{{ .Version }}-{{ .Release }}.\n      {{- if eq .Arch \"amd64\" }}x86_64\n      {{- else if eq .Arch \"arm64\" }}aarch64\n      {{- else }}{{ .Arch }}{{ end }}\n    vendor: PGSTY\n    homepage: https://pigsty.io/docs/pg_exporter\n    maintainer: Ruohang Feng <rh@vonng.com>\n    description: |\n      Prometheus exporter for PostgreSQL / Pgbouncer server metrics.\n      Supported version: Postgres9.4 - 17+ & Pgbouncer 1.8 - 1.24+\n      Part of Project Pigsty -- Battery Included PostgreSQL Distribution\n      with ultimate observability support: https://pigsty.io/docs\n    license: Apache-2.0\n    formats:\n      - rpm\n    bindir: /usr/bin\n    release: \"1\"\n    section: database\n    priority: optional\n    contents:\n      - src: pg_exporter.yml\n        dst: /etc/pg_exporter.yml\n        type: config|noreplace\n        file_info:\n          mode: 0700\n          owner: prometheus\n          group: prometheus\n      - src: package/pg_exporter.default\n        dst: /etc/default/pg_exporter\n        type: config|noreplace\n        file_info:\n          mode: 0700\n          owner: prometheus\n          group: prometheus\n      - src: package/pg_exporter.service\n        dst: /usr/lib/systemd/system/pg_exporter.service\n        type: config\n      - src: LICENSE\n        dst: /usr/share/doc/pg_exporter/LICENSE\n        file_info:\n          mode: 0644\n    scripts:\n      preinstall: package/preinstall.sh\n    rpm:\n      compression: gzip\n      prefixes:\n        - /usr/bin\n\n  - id: pg_exporter_deb\n    package_name: pg-exporter\n    file_name_template: >-\n      {{ .PackageName }}_{{ .Version }}-{{ .Release }}_\n      {{- if eq .Arch \"amd64\" }}amd64\n      {{- else if eq .Arch \"arm64\" }}arm64\n      {{- else }}{{ .Arch }}{{ end }}\n    vendor: PGSTY\n    homepage: https://pigsty.io/docs/pg_exporter\n    maintainer: Ruohang Feng <rh@vonng.com>\n    description: |\n      Prometheus exporter for PostgreSQL / Pgbouncer server metrics.\n      Supported version: Postgres9.4 - 17+ & Pgbouncer 1.8 - 1.24+\n      Part of Project Pigsty -- Battery Included PostgreSQL Distribution\n      with ultimate observability support: https://pigsty.io/docs\n    license: Apache-2.0\n    formats:\n      - deb\n    bindir: /usr/bin\n    release: \"1\"\n    section: database\n    priority: optional\n    contents:\n      - src: pg_exporter.yml\n        dst: /etc/pg_exporter.yml\n        type: config|noreplace\n        file_info:\n          mode: 0700\n          owner: prometheus\n          group: prometheus\n      - src: package/pg_exporter.default\n        dst: /etc/default/pg_exporter\n        type: config|noreplace\n        file_info:\n          mode: 0700\n          owner: prometheus\n          group: prometheus\n      - src: package/pg_exporter.service\n        dst: /lib/systemd/system/pg_exporter.service\n        type: config\n      - src: LICENSE\n        dst: /usr/share/doc/pg_exporter/LICENSE\n        file_info:\n          mode: 0644\n    scripts:\n      preinstall: package/preinstall.sh\n\nchecksum:\n  name_template: 'checksums.txt'\n  algorithm: sha256\n\nsnapshot:\n  version_template: \"{{ .Tag }}-next\"\n\nchangelog:\n  sort: asc\n  filters:\n    exclude:\n      - '^docs:'\n      - '^test:'\n      - '^chore:'\n      - 'Merge pull request'\n      - 'Merge branch'\n\nrelease:\n  github:\n    owner: pgsty\n    name: pg_exporter\n  draft: false\n  prerelease: false\n  mode: replace     # Replace existing release with same tag\n  replace_existing_artifacts: true  # Replace existing artifacts\n  name_template: \"{{.ProjectName}}-v{{.Version}}\"\n  disable: false\n  discussion_category_name: \"\"  # Skip discussion creation\n\nannounce:\n  skip: true  # Skip all announcements\n\n# Docker configuration for multi-arch images\ndockers:\n  - id: pg_exporter_amd64\n    ids: \n      - pg_exporter\n    goos: linux\n    goarch: amd64\n    image_templates:\n      - \"pgsty/pg_exporter:{{ .Version }}-amd64\"\n      - \"pgsty/pg_exporter:latest-amd64\"\n    dockerfile: Dockerfile.goreleaser\n    use: buildx\n    build_flag_templates:\n      - \"--platform=linux/amd64\"\n      - \"--label=org.opencontainers.image.version={{.Version}}\"\n      - \"--label=org.opencontainers.image.created={{.Date}}\"\n      - \"--label=org.opencontainers.image.revision={{.FullCommit}}\"\n    extra_files:\n      - pg_exporter.yml\n      - LICENSE\n\n  - id: pg_exporter_arm64\n    ids:\n      - pg_exporter\n    goos: linux\n    goarch: arm64\n    image_templates:\n      - \"pgsty/pg_exporter:{{ .Version }}-arm64\"\n      - \"pgsty/pg_exporter:latest-arm64\"\n    dockerfile: Dockerfile.goreleaser\n    use: buildx\n    build_flag_templates:\n      - \"--platform=linux/arm64\"\n      - \"--label=org.opencontainers.image.version={{.Version}}\"\n      - \"--label=org.opencontainers.image.created={{.Date}}\"\n      - \"--label=org.opencontainers.image.revision={{.FullCommit}}\"\n    extra_files:\n      - pg_exporter.yml\n      - LICENSE\n\ndocker_manifests:\n  - name_template: \"pgsty/pg_exporter:{{ .Version }}\"\n    image_templates:\n      - \"pgsty/pg_exporter:{{ .Version }}-amd64\"\n      - \"pgsty/pg_exporter:{{ .Version }}-arm64\"\n  - name_template: \"pgsty/pg_exporter:latest\"\n    image_templates:\n      - \"pgsty/pg_exporter:latest-amd64\"\n      - \"pgsty/pg_exporter:latest-arm64\""
  },
  {
    "path": "Dockerfile",
    "content": "# syntax=docker/dockerfile:1\nFROM golang:1.26.2-alpine AS builder-env\n\nARG GOPROXY=https://proxy.golang.org,direct\nARG GOSUMDB=sum.golang.org\nENV GOPROXY=${GOPROXY}\nENV GOSUMDB=${GOSUMDB}\n\n# Build a self-contained pg_exporter container with a clean environment and no\n# dependencies.\n#\n# build with\n#\n#   docker buildx build -f Dockerfile --tag pg_exporter .\n#\n\nWORKDIR /build\n\nCOPY go.mod go.sum ./\nRUN \\\n  --mount=type=cache,target=/go/pkg/mod \\\n  --mount=type=cache,target=/root/.cache/go-build \\\n  CGO_ENABLED=0 GOOS=linux go mod download\n\nCOPY . /build\nRUN \\\n  --mount=type=cache,target=/go/pkg/mod \\\n  --mount=type=cache,target=/root/.cache/go-build \\\n  CGO_ENABLED=0 GOOS=linux go build -a -o /pg_exporter .\n\nFROM scratch\nLABEL org.opencontainers.image.authors=\"Ruohang Feng <rh@vonng.com>, Craig Ringer <craig.ringer@enterprisedb.com>\" \\\n      org.opencontainers.image.url=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.source=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.licenses=\"Apache-2.0\" \\\n      org.opencontainers.image.title=\"pg_exporter\" \\\n      org.opencontainers.image.description=\"PostgreSQL/Pgbouncer metrics exporter for Prometheus\"\n\nWORKDIR /bin\nCOPY --from=builder-env /pg_exporter /bin/pg_exporter\nCOPY pg_exporter.yml /etc/pg_exporter.yml\nEXPOSE 9630/tcp\nENTRYPOINT [\"/bin/pg_exporter\"]\n"
  },
  {
    "path": "Dockerfile.goreleaser",
    "content": "# Dockerfile for goreleaser\n# This uses pre-built binaries from goreleaser instead of building from source\nFROM scratch\n\nLABEL org.opencontainers.image.authors=\"Ruohang Feng <rh@vonng.com>\" \\\n      org.opencontainers.image.url=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.source=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.licenses=\"Apache-2.0\" \\\n      org.opencontainers.image.title=\"pg_exporter\" \\\n      org.opencontainers.image.description=\"PostgreSQL/Pgbouncer metrics exporter for Prometheus\"\n\nWORKDIR /bin\nCOPY pg_exporter /bin/pg_exporter\nCOPY pg_exporter.yml /etc/pg_exporter.yml\nCOPY LICENSE /LICENSE\n\nEXPOSE 9630/tcp\nENTRYPOINT [\"/bin/pg_exporter\"]"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [2019-2025] [Ruohang Feng](rh@vonng.com)\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "#==============================================================#\n# File      :   Makefile\n# Mtime     :   2025-08-14\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\nVERSION      ?= v1.2.2\nBUILD_DATE   := $(shell date '+%Y%m%d%H%M%S')\nGIT_BRANCH   := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo \"unknown\")\nGIT_REVISION := $(shell git rev-parse --short HEAD 2>/dev/null  || echo \"HEAD\")\nLDFLAGS_META := -X 'pg_exporter/exporter.Version=$(VERSION)' \\\n                -X 'pg_exporter/exporter.Branch=$(GIT_BRANCH)' \\\n                -X 'pg_exporter/exporter.Revision=$(GIT_REVISION)' \\\n                -X 'pg_exporter/exporter.BuildDate=$(BUILD_DATE)'\nLDFLAGS_STATIC := -s -w -extldflags \\\"-static\\\" $(LDFLAGS_META)\n\n# Release Dir\nLINUX_AMD_DIR:=dist/$(VERSION)/pg_exporter-$(VERSION).linux-amd64\nLINUX_ARM_DIR:=dist/$(VERSION)/pg_exporter-$(VERSION).linux-arm64\nDARWIN_AMD_DIR:=dist/$(VERSION)/pg_exporter-$(VERSION).darwin-amd64\nDARWIN_ARM_DIR:=dist/$(VERSION)/pg_exporter-$(VERSION).darwin-arm64\nWINDOWS_DIR:=dist/$(VERSION)/pg_exporter-$(VERSION).windows-amd64\n\n\n###############################################################\n#                        Shortcuts                            #\n###############################################################\nbuild:\n\tgo build -ldflags \"$(LDFLAGS_META)\" -o pg_exporter\nclean:\n\trm -rf pg_exporter\nbuild-darwin-amd64:\n\tCGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -ldflags \"$(LDFLAGS_STATIC)\" -o pg_exporter\nbuild-darwin-arm64:\n\tCGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -a -ldflags \"$(LDFLAGS_STATIC)\" -o pg_exporter\nbuild-linux-amd64:\n\tCGO_ENABLED=0 GOOS=linux  GOARCH=amd64 go build -a -ldflags \"$(LDFLAGS_STATIC)\" -o pg_exporter\nbuild-linux-arm64:\n\tCGO_ENABLED=0 GOOS=linux  GOARCH=arm64 go build -a -ldflags \"$(LDFLAGS_STATIC)\" -o pg_exporter\n\nr: release\nrelease: release-linux release-darwin\n\nrelease-linux: linux-amd64 linux-arm64\nlinux-amd64: clean build-linux-amd64\n\trm -rf $(LINUX_AMD_DIR) && mkdir -p $(LINUX_AMD_DIR)\n\tnfpm package --packager rpm --config package/nfpm-amd64-rpm.yaml --target dist/$(VERSION)\n\tnfpm package --packager deb --config package/nfpm-amd64-deb.yaml --target dist/$(VERSION)\n\tcp pg_exporter $(LINUX_AMD_DIR)/pg_exporter\n\tcp pg_exporter.yml $(LINUX_AMD_DIR)/pg_exporter.yml\n\tcp LICENSE $(LINUX_AMD_DIR)/LICENSE\n\ttar -czf dist/$(VERSION)/pg_exporter-$(VERSION).linux-amd64.tar.gz -C dist/$(VERSION) pg_exporter-$(VERSION).linux-amd64\n\trm -rf $(LINUX_AMD_DIR)\n\nlinux-arm64: clean build-linux-arm64\n\trm -rf $(LINUX_ARM_DIR) && mkdir -p $(LINUX_ARM_DIR)\n\tnfpm package --packager rpm --config package/nfpm-arm64-rpm.yaml --target dist/$(VERSION)\n\tnfpm package --packager deb --config package/nfpm-arm64-deb.yaml --target dist/$(VERSION)\n\tcp pg_exporter $(LINUX_ARM_DIR)/pg_exporter\n\tcp pg_exporter.yml $(LINUX_ARM_DIR)/pg_exporter.yml\n\tcp LICENSE $(LINUX_ARM_DIR)/LICENSE\n\ttar -czf dist/$(VERSION)/pg_exporter-$(VERSION).linux-arm64.tar.gz -C dist/$(VERSION) pg_exporter-$(VERSION).linux-arm64\n\trm -rf $(LINUX_ARM_DIR)\n\nrelease-darwin: darwin-amd64 darwin-arm64\ndarwin-amd64: clean build-darwin-amd64\n\trm -rf $(DARWIN_AMD_DIR) && mkdir -p $(DARWIN_AMD_DIR)\n\tcp pg_exporter $(DARWIN_AMD_DIR)/pg_exporter\n\tcp pg_exporter.yml $(DARWIN_AMD_DIR)/pg_exporter.yml\n\tcp LICENSE $(DARWIN_AMD_DIR)/LICENSE\n\ttar -czf dist/$(VERSION)/pg_exporter-$(VERSION).darwin-amd64.tar.gz -C dist/$(VERSION) pg_exporter-$(VERSION).darwin-amd64\n\trm -rf $(DARWIN_AMD_DIR)\n\ndarwin-arm64: clean build-darwin-arm64\n\trm -rf $(DARWIN_ARM_DIR) && mkdir -p $(DARWIN_ARM_DIR)\n\tcp pg_exporter $(DARWIN_ARM_DIR)/pg_exporter\n\tcp pg_exporter.yml $(DARWIN_ARM_DIR)/pg_exporter.yml\n\tcp LICENSE $(DARWIN_ARM_DIR)/LICENSE\n\ttar -czf dist/$(VERSION)/pg_exporter-$(VERSION).darwin-arm64.tar.gz -C dist/$(VERSION) pg_exporter-$(VERSION).darwin-arm64\n\trm -rf $(DARWIN_ARM_DIR)\n\n\n\n###############################################################\n#                      Configuration                          #\n###############################################################\n# generate merged config from separated configuration\nconf:\n\trm -rf pg_exporter.yml\n\tcat config/*.yml >> pg_exporter.yml\n\n# generate legacy merged config for PostgreSQL 9.1 - 9.6\nconf9:\n\trm -rf legacy/pg_exporter.yml\n\tcat legacy/config/*.yml >> legacy/pg_exporter.yml\n\n# Backward-compatible alias (deprecated)\nconf-pg9: conf9\n\n\n###############################################################\n#                         Release                             #\n###############################################################\nrelease-dir:\n\tmkdir -p dist/$(VERSION)\n\nrelease-clean:\n\trm -rf dist/$(VERSION)\n\n###############################################################\n#                      GoReleaser                            #\n###############################################################\n# Install goreleaser if not present\ngoreleaser-install:\n\t@which goreleaser > /dev/null || (echo \"Installing goreleaser...\" && go install github.com/goreleaser/goreleaser/v2@latest)\n\n# Build snapshot release (without publishing)\ngoreleaser-snapshot: goreleaser-install\n\tgoreleaser release --snapshot --clean --skip=publish\n\n# Build release locally (without git tag)\ngoreleaser-build: goreleaser-install\n\tgoreleaser build --snapshot --clean\n\n# Build release locally without snapshot suffix (requires clean git)\ngoreleaser-local: goreleaser-install\n\tgoreleaser release --clean --skip=publish\n\n# Release with goreleaser (requires git tag)\ngoreleaser-release: goreleaser-install\n\tgoreleaser release --clean\n\n# Test release (creates prerelease, no notifications)\ngoreleaser-test-release: goreleaser-install\n\t@echo \"Creating test release (prerelease mode, no notifications)...\"\n\tgoreleaser release --clean\n\n# Production release (set prerelease to false in config first)\ngoreleaser-prod-release: goreleaser-install\n\t@echo \"Creating production release (will notify subscribers if announce.skip is false)...\"\n\tgoreleaser release --clean\n\n# Check goreleaser configuration\ngoreleaser-check: goreleaser-install\n\tgoreleaser check\n\n# New main release task using goreleaser\nrelease-new: goreleaser-release\n\n\n# build docker image\ndocker: docker-build\ndocker-build:\n\t./docker/build.sh\ndocker-release:\n\t./docker/release.sh\n\n###############################################################\n#                         Develop                             #\n###############################################################\ninstall: build\n\tsudo install -m 0755 pg_exporter /usr/bin/pg_exporter\n\nuninstall:\n\tsudo rm -rf /usr/bin/pg_exporter\n\nrunb:\n\t./pg_exporter --log.level=info --config=pg_exporter.yml --auto-discovery\nrun:\n\tgo run main.go --log.level=info --config=pg_exporter.yml --auto-discovery\n\ndebug:\n\tgo run main.go --log.level=debug --config=pg_exporter.yml --auto-discovery\n\ncurl:\n\tcurl localhost:9630/metrics | grep -v '#' | grep pg_\n\nupload:\n\t./upload.sh\n\nd: dev\ndev:\n\thugo serve\n\n.PHONY: build clean build-darwin build-linux\\\n release release-darwin release-linux release-windows docker docker-build docker-release \\\n install uninstall debug curl upload \\\n goreleaser-install goreleaser-snapshot goreleaser-build goreleaser-release goreleaser-test-release \\\n goreleaser-check release-new goreleaser-local\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img src=\"static/logo.png\" alt=\"PG Exporter Logo\" height=\"128\" align=\"middle\">\n</p>\n\n# PG EXPORTER\n\n[![Webite: https://pigsty.io/docs/pg_exporter](https://img.shields.io/badge/website-pigsty.io/docs/pg_exporter-slategray?style=flat&logo=cilium&logoColor=white)](https://pigsty.io/docs/pg_exporter)\n[![DockerHub: pgsty/pg_exporter](https://img.shields.io/badge/docker-pgsty/pg_exporter-slategray?style=flat&logo=docker&logoColor=white)](https://hub.docker.com/r/pgsty/pg_exporter)\n[![Version: 1.2.2](https://img.shields.io/badge/version-1.2.2-slategray?style=flat&logo=cilium&logoColor=white)](https://github.com/pgsty/pg_exporter/releases/tag/v1.2.2)\n[![License: Apache-2.0](https://img.shields.io/github/license/pgsty/pg_exporter?logo=opensourceinitiative&logoColor=green&color=slategray)](https://github.com/pgsty/pg_exporter/blob/main/LICENSE)\n[![GitHub Stars](https://img.shields.io/github/stars/pgsty/pg_exporter?style=flat&logo=github&logoColor=black&color=slategray)](https://star-history.com/#pgsty/pg_exporter&Date)\n[![Go Report Card](https://goreportcard.com/badge/github.com/pgsty/pg_exporter)](https://goreportcard.com/report/github.com/pgsty/pg_exporter)\n\n> **Advanced [PostgreSQL](https://www.postgresql.org) & [pgBouncer](https://www.pgbouncer.org/) metrics [exporter](https://prometheus.io/docs/instrumenting/exporters/) for [Prometheus](https://prometheus.io/)**\n\nPG Exporter brings ultimate monitoring experience to your PostgreSQL with **declarative config**, **dynamic planning**, and **customizable collectors**. \nIt provides **600+** metrics and ~3K time series per instance, covers everything you'll need for PostgreSQL observability.\n\nCheck [**https://demo.pigsty.io**](https://demo.pigsty.io/ui/) for live demo, which is built upon this exporter by [**Pigsty**](https://pigsty.io).\n\n<div align=\"center\">\n    <a href=\"https://pigsty.io/docs/pg_exporter\">Docs</a> •    \n    <a href=\"#quick-start\">Quick Start</a> •\n    <a href=\"#features\">Features</a> •\n    <a href=\"#usage\">Usage</a> •\n    <a href=\"#api\">API</a> •\n    <a href=\"#deployment\">Deployment</a> •\n    <a href=\"#collectors\">Collectors</a> •\n    <a href=\"https://demo.pigsty.io/ui/\">Demo</a>\n</div><br>\n\n[![pigsty-dashboard](https://pigsty.io/img/pigsty/dashboard.jpg)](https://demo.pigsty.io)\n\n\n--------\n\n## Features\n\n- **Highly Customizable**: Define almost all metrics through declarative YAML configs\n- **Full Coverage**: Monitor PostgreSQL (10-18+) and pgBouncer (1.8-1.25+) in a single exporter\n- **Fine-grained Control**: Configure timeout, caching, skip conditions, and fatality per collector\n- **Dynamic Planning**: Define multiple query branches based on different conditions\n- **Self-monitoring**: Rich metrics about pg_exporter [itself](https://demo.pigsty.io/d/pgsql-exporter) for complete observability\n- **Production-Ready**: Battle-tested in real-world environments across 12K+ cores for 6+ years\n- **Auto-discovery**: Automatically discover and monitor multiple databases within an instance\n- **Health Check APIs**: Comprehensive HTTP endpoints for service health and traffic routing\n- **Extension Support**: `timescaledb`, `citus`, `pg_stat_statements`, `pg_wait_sampling`,...\n- **Local-first URL behavior**: Built for on-host deployment, with implicit local target fallback and automatic `sslmode=disable` when omitted\n\n> Also support PG 9.x with [legacy config bundle](legacy/).\n\n\n--------\n\n## Quick Start\n\nRPM / DEB / Tarball available in the GitHub [release page](https://github.com/pgsty/pg_exporter/releases), and Pigsty's YUM / APT [Infra Repo](https://pigsty.io/docs/repo/infra).\n\nTo run this exporter, you need to pass the postgres/pgbouncer URL via env or arg:\n\n```bash\nPG_EXPORTER_URL='postgres://user:pass@host:port/postgres' pg_exporter\ncurl http://localhost:9630/metrics   # access metrics\n```\n\nThere are built-in metrics such as `pg_up`, `pg_version`, `pg_in_recovery`, `pg_exporter_build_info`, and exporter self-metrics under `pg_exporter_*` (disable with `--disable-intro`).\n\n**All other metrics are defined in the [`pg_exporter.yml`](pg_exporter.yml) config file**.\n\nThere are two monitoring dashboards in the [`monitor/`](monitor/) directory.\n\nYou can use [**Pigsty**](https://pigsty.io) to monitor existing PostgreSQL cluster or RDS, it will setup pg_exporter for you. \n\n\n--------\n\n## Usage\n\n```bash\nusage: pg_exporter [<flags>]\n\n\nFlags:\n  -h, --[no-]help            Show context-sensitive help (also try --help-long and --help-man).\n  -u, --url=URL              postgres target url\n  -c, --config=CONFIG        path to config dir or file\n      --web.listen-address=:9630 ...  \n                             Addresses on which to expose metrics and web interface. \n      --web.config.file=\"\"   Path to configuration file that can enable TLS or authentication. \n  -l, --label=\"\"             constant lables:comma separated list of label=value pair ($PG_EXPORTER_LABEL)\n  -t, --tag=\"\"               tags,comma separated list of server tag ($PG_EXPORTER_TAG)\n  -C, --[no-]disable-cache   force not using cache ($PG_EXPORTER_DISABLE_CACHE)\n  -m, --[no-]disable-intro   disable internal/exporter self metrics ($PG_EXPORTER_DISABLE_INTRO)\n  -a, --[no-]auto-discovery  automatically scrape all database for given server ($PG_EXPORTER_AUTO_DISCOVERY)\n  -x, --exclude-database=\"template0,template1,postgres\"  \n                             excluded databases when enabling auto-discovery ($PG_EXPORTER_EXCLUDE_DATABASE)\n  -i, --include-database=\"\"  included databases when enabling auto-discovery ($PG_EXPORTER_INCLUDE_DATABASE)\n  -n, --namespace=\"\"         prefix of built-in metrics, (pg|pgbouncer) by default ($PG_EXPORTER_NAMESPACE)\n  -f, --[no-]fail-fast       fail fast instead of waiting during start-up ($PG_EXPORTER_FAIL_FAST)\n  -T, --connect-timeout=100  connect timeout in ms, 100 by default ($PG_EXPORTER_CONNECT_TIMEOUT)\n  -P, --web.telemetry-path=\"/metrics\"  \n                             URL path under which to expose metrics. ($PG_EXPORTER_TELEMETRY_PATH)\n  -D, --[no-]dry-run         dry run and print raw configs\n  -E, --[no-]explain         explain server planned queries\n      --log.level=\"info\"     log level: debug|info|warn|error]\n      --log.format=\"logfmt\"  log format: logfmt|json\n      --[no-]version         Show application version.\n```\n\nParameters could be given via command-line args or environment variables. \n\n| CLI Arg                | Environment Variable           | Default Value                    |\n|------------------------|--------------------------------|----------------------------------|\n| `--url`                | `PG_EXPORTER_URL`              | `postgresql:///?sslmode=disable` |\n| `--config`             | `PG_EXPORTER_CONFIG`           | `pg_exporter.yml`                |\n| `--label`              | `PG_EXPORTER_LABEL`            |                                  |\n| `--tag`                | `PG_EXPORTER_TAG`              |                                  |\n| `--auto-discovery`     | `PG_EXPORTER_AUTO_DISCOVERY`   | `true`                           |\n| `--disable-cache`      | `PG_EXPORTER_DISABLE_CACHE`    | `false`                          |\n| `--fail-fast`          | `PG_EXPORTER_FAIL_FAST`        | `false`                          |\n| `--exclude-database`   | `PG_EXPORTER_EXCLUDE_DATABASE` |                                  |\n| `--include-database`   | `PG_EXPORTER_INCLUDE_DATABASE` |                                  |\n| `--namespace`          | `PG_EXPORTER_NAMESPACE`        | `pg\\|pgbouncer`                  |\n| `--connect-timeout`    | `PG_EXPORTER_CONNECT_TIMEOUT`  | `100`                            |\n| `--dry-run`            |                                | `false`                          |\n| `--explain`            |                                | `false`                          |\n| `--log.level`          |                                | `info`                           |\n| `--log.format`         |                                | `logfmt`                         |\n| `--web.listen-address` |                                | `:9630`                          |\n| `--web.config.file`    |                                | `\"\"`                             |\n| `--web.telemetry-path` | `PG_EXPORTER_TELEMETRY_PATH`   | `/metrics`                       |\n\n### Connection URL Defaults\n\n- If `--url` / `PG_EXPORTER_URL` is not provided, pg_exporter falls back to a local-first default URL: `postgresql:///?sslmode=disable`.\n- If `sslmode` is not explicitly set in the URL, pg_exporter injects `sslmode=disable` by default.\n- This is an intentional design choice for common on-host deployments (`pg_exporter` and PostgreSQL/PgBouncer on the same machine), where loopback TLS adds overhead with little practical gain.\n- If you need TLS for remote targets, provide `sslmode` explicitly in the connection URL (for example: `sslmode=require`, `verify-ca`, `verify-full`).\n\n\n------\n\n## API\n\nPG Exporter provides a rich set of HTTP endpoints:\n\nHere are `pg_exporter` REST APIs\n\n```bash\n# Fetch metrics (customizable)\ncurl localhost:9630/metrics\n\n# Reload configuration\ncurl -X POST localhost:9630/reload\n\n# Explain configuration\ncurl localhost:9630/explain\n\n# Print Statistics\ncurl localhost:9630/stat\n\n# Aliveness health check (200 up, 503 down)\ncurl localhost:9630/up\ncurl localhost:9630/health\ncurl localhost:9630/liveness\ncurl localhost:9630/readiness\n\n# traffic route health check\n\n### 200 if not in recovery, 404 if in recovery, 503 if server is down\ncurl localhost:9630/primary\ncurl localhost:9630/leader\ncurl localhost:9630/master\ncurl localhost:9630/read-write\ncurl localhost:9630/rw\n\n### 200 if in recovery, 404 if not in recovery, 503 if server is down\ncurl localhost:9630/replica\ncurl localhost:9630/standby\ncurl localhost:9630/read-only\ncurl localhost:9630/ro\n\n### 200 if server is ready for read traffic (including primary), 503 if server is down\ncurl localhost:9630/read\n```\n\n\n--------\n\n## Build\n\nTo build a static stand-alone binary for docker scratch\n\n```bash\nCGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags \"-static\"' -o pg_exporter\n```\n\nOr [download](https://github.com/pgsty/pg_exporter/releases) the latest prebuilt binaries from release pages.\n\nWe also have pre-packaged RPM / DEB packages in the [Pigsty Infra Repo](https://pigsty.io/docs/repo/infra/)\n\n\n--------\n\n## Docker\n\nYou can find pre-built amd64/arm64 docker images here: [pgsty/pg_exporter](https://hub.docker.com/r/pgsty/pg_exporter)\n\n\n--------\n\n## Deployment\n\nRedhat rpm and Debian/Ubuntu deb packages are made with `nfpm` for `x86/arm64`:\n\n* `/usr/bin/pg_exporter`: the pg_exporter binary.\n* [`/etc/pg_exporter.yml`](pg_exporter.yml): the config file\n* [`/usr/lib/systemd/system/pg_exporter.service`](package/pg_exporter.service): systemd service file\n* [`/etc/default/pg_exporter`](package/pg_exporter.default): systemd service envs & options\n\n\nWhich is also available on Pigsty's [Infra Repo](https://pigsty.io/docs/repo/infra).\n\n\n------\n\n## Collectors\n\nConfigs lie in the core of `pg_exporter`. Actually, this project contains more lines of YAML than go.\n\n* A monolith battery-included config file: [`pg_exporter.yml`](pg_exporter.yml)\n* Separated metrics definition in [`config/collector`](config/)\n* Example of how to write a config file:  [`doc.yml`](config/0000-doc.yml)\n* Legacy config bundle for PostgreSQL 9.1 - 9.6: [`legacy/`](legacy/) ([`legacy/README.md`](legacy/README.md))\n\nCurrent `pg_exporter` is shipped with the following metrics collector definition files\n\n- [0000-doc.yml](config/0000-doc.yml)\n- [0110-pg.yml](config/0110-pg.yml)\n- [0120-pg_meta.yml](config/0120-pg_meta.yml)\n- [0130-pg_setting.yml](config/0130-pg_setting.yml)\n- [0210-pg_repl.yml](config/0210-pg_repl.yml)\n- [0220-pg_sync_standby.yml](config/0220-pg_sync_standby.yml)\n- [0230-pg_downstream.yml](config/0230-pg_downstream.yml)\n- [0240-pg_slot.yml](config/0240-pg_slot.yml)\n- [0250-pg_recv.yml](config/0250-pg_recv.yml)\n- [0260-pg_sub.yml](config/0260-pg_sub.yml)\n- [0270-pg_origin.yml](config/0270-pg_origin.yml)\n- [0300-pg_io.yml](config/0300-pg_io.yml)\n- [0310-pg_size.yml](config/0310-pg_size.yml)\n- [0320-pg_archiver.yml](config/0320-pg_archiver.yml)\n- [0330-pg_bgwriter.yml](config/0330-pg_bgwriter.yml)\n- [0331-pg_checkpointer.yml](config/0331-pg_checkpointer.yml)\n- [0340-pg_ssl.yml](config/0340-pg_ssl.yml)\n- [0350-pg_checkpoint.yml](config/0350-pg_checkpoint.yml)\n- [0355-pg_timeline.yml](config/0355-pg_timeline.yml)\n- [0360-pg_recovery.yml](config/0360-pg_recovery.yml)\n- [0370-pg_slru.yml](config/0370-pg_slru.yml)\n- [0380-pg_shmem.yml](config/0380-pg_shmem.yml)\n- [0390-pg_wal.yml](config/0390-pg_wal.yml)\n- [0410-pg_activity.yml](config/0410-pg_activity.yml)\n- [0420-pg_wait.yml](config/0420-pg_wait.yml)\n- [0430-pg_backend.yml](config/0430-pg_backend.yml)\n- [0440-pg_xact.yml](config/0440-pg_xact.yml)\n- [0450-pg_lock.yml](config/0450-pg_lock.yml)\n- [0460-pg_query.yml](config/0460-pg_query.yml)\n- [0510-pg_vacuuming.yml](config/0510-pg_vacuuming.yml)\n- [0520-pg_indexing.yml](config/0520-pg_indexing.yml)\n- [0530-pg_clustering.yml](config/0530-pg_clustering.yml)\n- [0540-pg_backup.yml](config/0540-pg_backup.yml)\n- [0610-pg_db.yml](config/0610-pg_db.yml)\n- [0620-pg_db_confl.yml](config/0620-pg_db_confl.yml)\n- [0640-pg_pubrel.yml](config/0640-pg_pubrel.yml)\n- [0650-pg_subrel.yml](config/0650-pg_subrel.yml)\n- [0700-pg_table.yml](config/0700-pg_table.yml)\n- [0710-pg_index.yml](config/0710-pg_index.yml)\n- [0720-pg_func.yml](config/0720-pg_func.yml)\n- [0730-pg_seq.yml](config/0730-pg_seq.yml)\n- [0740-pg_relkind.yml](config/0740-pg_relkind.yml)\n- [0750-pg_defpart.yml](config/0750-pg_defpart.yml)\n- [0810-pg_table_size.yml](config/0810-pg_table_size.yml)\n- [0820-pg_table_bloat.yml](config/0820-pg_table_bloat.yml)\n- [0830-pg_index_bloat.yml](config/0830-pg_index_bloat.yml)\n- [0910-pgbouncer_list.yml](config/0910-pgbouncer_list.yml)\n- [0920-pgbouncer_database.yml](config/0920-pgbouncer_database.yml)\n- [0930-pgbouncer_stat.yml](config/0930-pgbouncer_stat.yml)\n- [0940-pgbouncer_pool.yml](config/0940-pgbouncer_pool.yml)\n- [1000-pg_wait_event.yml](config/1000-pg_wait_event.yml)\n- [1800-pg_tsdb_hypertable.yml](config/1800-pg_tsdb_hypertable.yml)\n- [1900-pg_citus.yml](config/1900-pg_citus.yml)\n- [2000-pg_heartbeat.yml](config/2000-pg_heartbeat.yml)\n\n\n> #### Note\n>\n> Supported version: PostgreSQL 10, 11, 12, 13, 14, 15, 16, 17, 18+\n>\n> But you can still get PostgreSQL 9.1 - 9.6 support by switching to the [`legacy/pg_exporter.yml`](legacy/pg_exporter.yml) config\n\n`pg_exporter` will generate approximately 600 metrics for a completely new database cluster.\nFor a real-world database with 10 ~ 100 tables, it may generate several 1k ~ 10k metrics. \n\nYou may need to modify or disable some database-level metrics on a database with several thousand or more tables to complete the scrape in time.\n\nConfig files are using YAML format, there are lots of examples in the [conf](https://github.com/pgsty/pg_exporter/tree/main/config/collector) dir. and here is a [sample](config/0000-doc.yml) config.\n\n```\n#==============================================================#\n# 1. Config File\n#==============================================================#\n# The configuration file for pg_exporter is a YAML file.\n# Default configurations are retrieved via following precedence:\n#     1. command line args:      --config=<config path>\n#     2. environment variables:  PG_EXPORTER_CONFIG=<config path>\n#     3. pg_exporter.yml        (Current directory)\n#     4. /etc/pg_exporter.yml   (config file)\n#     5. /etc/pg_exporter       (config dir)\n\n#==============================================================#\n# 2. Config Format\n#==============================================================#\n# pg_exporter config could be a single YAML file, or a directory containing a series of separated YAML files.\n# Each YAML config file consists of one or more metrics Collector definition, which are top-level objects.\n# If a directory is provided, all YAML files in that directory (non-recursive; subdirectories are ignored) will be merged in alphabetic order.\n# Collector definition examples are shown below.\n\n#==============================================================#\n# 3. Collector Example\n#==============================================================#\n#  # Here is an example of a metrics collector definition\n#  pg_primary_only:       # Collector branch name. Must be UNIQUE among the entire configuration\n#    name: pg             # Collector namespace, used as METRIC PREFIX, set to branch name by default, can be override\n#                         # the same namespace may contain multiple collector branches. It`s the user`s responsibility\n#                         # to make sure that AT MOST ONE collector is picked for each namespace.\n#\n#    desc: PostgreSQL basic information (on primary)                 # Collector description\n#    query: |                                                        # Metrics Query SQL\n#\n#      SELECT extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n#             pg_current_wal_lsn() - '0/0'                           AS lsn,\n#             pg_current_wal_insert_lsn() - '0/0'                    AS insert_lsn,\n#             pg_current_wal_lsn() - '0/0'                           AS write_lsn,\n#             pg_current_wal_flush_lsn() - '0/0'                     AS flush_lsn,\n#             extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n#             extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n#             pg_is_in_backup()                                      AS is_in_backup,\n#             extract(EPOCH FROM now() - pg_backup_start_time())     AS backup_time;\n#\n#                             # [OPTIONAL] metadata fields, control collector behavior\n#    ttl: 10                  # Cache TTL: in seconds, how long will pg_exporter cache this collector`s query result.\n#    timeout: 0.1             # Query Timeout: in seconds, queries that exceed this limit will be canceled.\n#    min_version: 100000      # minimal supported version, boundary IS included. In server version number format,\n#    max_version: 130000      # maximal supported version, boundary NOT included, In server version number format\n#    fatal: false             # Collector marked `fatal` fails, the entire scrape will abort immediately and marked as failed\n#    skip: false              # Collector marked `skip` will not be installed during the planning procedure\n#\n#    tags: [cluster, primary] # Collector tags, used for planning and scheduling\n#\n#    # tags are list of strings, which could be:\n#    #   * `cluster` marks this query as cluster level, so it will only execute once for the same PostgreSQL Server\n#    #   * `primary` or `master`  mark this query can only run on a primary instance (WILL NOT execute if pg_is_in_recovery())\n#    #   * `standby` or `replica` mark this query can only run on a replica instance (WILL execute if pg_is_in_recovery())\n#    # some special tag prefix have special interpretation:\n#    #   * `dbname:<dbname>` means this query will ONLY be executed on database with name `<dbname>`\n#    #   * `username:<user>` means this query will only be executed when connect with user `<user>`\n#    #   * `extension:<extname>` means this query will only be executed when extension `<extname>` is installed\n#    #   * `schema:<nspname>` means this query will only by executed when schema `<nspname>` exist\n#    #   * `not:<negtag>` means this query WILL NOT be executed when exporter is tagged with `<negtag>`\n#    #   * `<tag>` means this query WILL be executed when exporter is tagged with `<tag>`\n#    #   ( <tag> could not be cluster,primary,standby,master,replica,etc...)\n#\n#    # One or more \"predicate queries\" may be defined for a metric query. These\n#    # are run before the main metric query (after any cache hit check). If all\n#    # of them, when run sequentially, return a single row with a single column\n#    # boolean true result, the main metric query is executed. If any of them\n#    # return false or return zero rows, the main query is skipped. If any\n#    # predicate query returns more than one row, a non-boolean result, or fails\n#    # with an error, the whole query is marked failed. Predicate queries can be\n#    # used to check for the presence of specific functions, tables, extensions,\n#    # settings, and vendor-specific pg features before running the main query.\n#\n#    predicate_queries:\n#      - name: predicate query name\n#        predicate_query: |\n#          SELECT EXISTS (SELECT 1 FROM information_schema.routines WHERE routine_schema = 'pg_catalog' AND routine_name = 'pg_backup_start_time');\n#\n#    metrics:                 # List of returned columns, each column must have a `name` and `usage`, `rename` and `description` are optional\n#      - timestamp:           # Column name, should be exactly the same as returned column name\n#          usage: GAUGE       # Metric type, `usage` could be\n#                                  * DISCARD: completely ignoring this field\n#                                  * LABEL:   use columnName=columnValue as a label in metric\n#                                  * GAUGE:   Mark column as a gauge metric, full name will be `<query.name>_<column.name>`\n#                                  * COUNTER: Same as above, except it is a counter rather than a gauge.\n#          rename: ts         # [OPTIONAL] Alias, optional, the alias will be used instead of the column name\n#          description: xxxx  # [OPTIONAL] Description of the column, will be used as a metric description\n#          default: 0         # [OPTIONAL] Default value, will be used when column is NULL\n#          scale:   1000      # [OPTIONAL] Scale the value by this factor\n#      - lsn:\n#          usage: COUNTER\n#          description: log sequence number, current write location (on primary)\n#      - insert_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal inserting\n#      - write_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal writing\n#      - flush_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal syncing\n#      - uptime:\n#          usage: GAUGE\n#          description: seconds since postmaster start\n#      - conf_reload_time:\n#          usage: GAUGE\n#          description: seconds since last configuration reload\n#      - is_in_backup:\n#          usage: GAUGE\n#          description: 1 if backup is in progress\n#      - backup_time:\n#          usage: GAUGE\n#          description: seconds since the current backup start. null if don`t have one\n#\n#      .... # you can also use rename & scale to customize the metric name and value:\n#      - checkpoint_write_time:\n#          rename: write_time\n#          usage: COUNTER\n#          scale: 1e-3\n#          description: Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\n\n#==============================================================#\n# 4. Collector Presets\n#==============================================================#\n# pg_exporter is shipped with a series of preset collectors (already numbered and ordered by filename)\n#\n# 1xx  Basic metrics:        basic info, metadata, settings\n# 2xx  Replication metrics:  replication, walreceiver, downstream, sync standby, slots, subscription\n# 3xx  Persist metrics:      size, wal, background writer, checkpointer, ssl, checkpoint, recovery, slru cache, shmem usage\n# 4xx  Activity metrics:     backend count group by state, wait event, locks, xacts, queries\n# 5xx  Progress metrics:     clustering, vacuuming, indexing, basebackup, copy\n# 6xx  Database metrics:     pg_database, publication, subscription\n# 7xx  Object metrics:       pg_class, table, index, function, sequence, default partition\n# 8xx  Optional metrics:     optional metrics collector (disable by default, slow queries)\n# 9xx  Pgbouncer metrics:    metrics from pgbouncer admin database `pgbouncer`\n#\n# 100-599 Metrics for entire database cluster  (scrape once)\n# 600-899 Metrics for single database instance (scrape for each database ,except for pg_db itself)\n\n#==============================================================#\n# 5. Cache TTL\n#==============================================================#\n# Cache can be used for reducing query overhead, it can be enabled by setting a non-zero value for `ttl`\n# It is highly recommended to use cache to avoid duplicate scrapes. Especially when you got multiple Prometheus\n# scraping the same instance with slow monitoring queries. Setting `ttl` to zero or leaving blank will disable\n# result caching, which is the default behavior\n#\n# TTL has to be smaller than your scrape interval. 15s scrape interval and 10s TTL is a good start for\n# production environment. Some expensive monitoring queries (such as size/bloat check) will have longer `ttl`\n# which can also be used as a mechanism to achieve `different scrape frequency`\n\n#==============================================================#\n# 6. Query Timeout\n#==============================================================#\n# Collectors can be configured with an optional Timeout. If the collector's query executes more than that\n# timeout, it will be canceled immediately. Setting the `timeout` to 0 or leaving blank will reset it to\n# default timeout 0.1 (100ms). Setting it to any negative number will disable the query timeout feature.\n# All queries have a default timeout of 100ms, if exceeded, the query will be canceled immediately to avoid\n# avalanche. You can explicitly overwrite that option. but beware: in some extreme cases, if all your\n# timeouts sum up greater your scrape/cache interval (usually 15s), the queries may still be jammed.\n# or, you can just disable potential slow queries.\n\n#==============================================================#\n# 7. Version Compatibility\n#==============================================================#\n# Each collector has two optional version compatibility parameters: `min_version` and `max_version`.\n# These two parameters specify the version compatibility of the collector. If target postgres/pgbouncer's\n# version is less than `min_version`, or higher than `max_version`, the collector will not be installed.\n# These two parameters are using PostgreSQL server version number format, which is a 6-digit integer\n# format as <major:2 digit><minor:2 digit>:<release: 2 digit>.\n# For example, 090600 stands for 9.6, and 120100 stands for 12.1\n# And beware that version compatibility range is left-inclusive right exclusive: [min, max), set to zero or\n# leaving blank will affect as -inf or +inf\n\n#==============================================================#\n# 8. Fatality\n#==============================================================#\n# If a collector is marked with `fatal` falls, the entire scrape operation will be marked as fail and key metrics\n# `pg_up` / `pgbouncer_up` will be reset to 0. It is always a good practice to set up AT LEAST ONE fatal\n# collector for pg_exporter. `pg.pg_primary_only` and `pgbouncer_list` are the default fatal collector.\n#\n# If a collector without `fatal` flag fails, it will increase global fail counters. But the scrape operation\n# will carry on. The entire scrape result will not be marked as faile, thus will not affect the `<xx>_up` metric.\n\n#==============================================================#\n# 9. Skip\n#==============================================================#\n# Collector with `skip` flag set to true will NOT be installed.\n# This could be a handy option to disable collectors\n\n#==============================================================#\n# 10. Tags and Planning\n#==============================================================#\n# Tags are designed for collector planning & schedule. It can be handy to customize which queries run\n# on which instances. And thus you can use one-single monolith config for multiple environments\n#\n#  Tags are a list of strings, each string could be:\n#  Pre-defined special tags\n#    * `cluster` marks this collector as cluster level, so it will ONLY BE EXECUTED ONCE for the same PostgreSQL Server\n#    * `primary` or `master` mark this collector as primary-only, so it WILL NOT work iff pg_is_in_recovery()\n#    * `standby` or `replica` mark this collector as replica-only, so it WILL work iff pg_is_in_recovery()\n#  Special tag prefix which have different interpretation:\n#    * `dbname:<dbname>` means this collector will ONLY work on database with name `<dbname>`\n#    * `username:<user>` means this collector will ONLY work when connect with user `<user>`\n#    * `extension:<extname>` means this collector will ONLY work when extension `<extname>` is installed\n#    * `schema:<nspname>` means this collector will only work when schema `<nspname>` exists\n#  Customized positive tags (filter) and negative tags (taint)\n#    * `not:<negtag>` means this collector WILL NOT work when exporter is tagged with `<negtag>`\n#    * `<tag>` means this query WILL work if exporter is tagged with `<tag>` (special tags not included)\n#\n#  pg_exporter will trigger the Planning procedure after connecting to the target. It will gather database facts\n#  and match them with tags and other metadata (such as supported version range). Collector will only\n#  be installed if and only if it is compatible with the target server.\n\n```\n\n\n\n--------------------\n\n## About\n\nAuthor: [Vonng](https://vonng.com/en) ([rh@vonng.com](mailto:rh@vonng.com))\n\nContributors: https://github.com/pgsty/pg_exporter/graphs/contributors\n\nLicense: [Apache-2.0](LICENSE)\n\nCopyright: 2018-2026 rh@vonng.com\n\n<p align=\"center\">\n  <img src=\"static/logo.png\" alt=\"PG Exporter Logo\" height=\"128\" align=\"middle\">\n</p>\n"
  },
  {
    "path": "config/0000-doc.yml",
    "content": "#==============================================================#\n# Desc      :   pg_exporter metrics collector definition\n# Ver       :   PostgreSQL 10 ~ 18+ and pgbouncer 1.9~1.25+\n# Ctime     :   2019-12-09\n# Mtime     :   2026-03-21\n# Homepage  :   https://pigsty.io\n# Author    :   Ruohang Feng (rh@vonng.com)\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\n\n\n#==============================================================#\n# 1. Config File\n#==============================================================#\n# The configuration file for pg_exporter is a YAML file.\n# Default configurations are retrieved via following precedence:\n#     1. command line args:      --config=<config path>\n#     2. environment variables:  PG_EXPORTER_CONFIG=<config path>\n#     3. pg_exporter.yml        (Current directory)\n#     4. /etc/pg_exporter.yml   (config file)\n#     5. /etc/pg_exporter       (config dir)\n\n#==============================================================#\n# 2. Config Format\n#==============================================================#\n# pg_exporter config could be a single YAML file, or a directory containing a series of separated YAML files.\n# Each YAML config file consists of one or more metrics Collector definition, which are top-level objects.\n# If a directory is provided, all YAML in that directory will be merged in alphabetic order.\n# Collector definition examples are shown below.\n\n#==============================================================#\n# 3. Collector Example\n#==============================================================#\n#  # Here is an example of a metrics collector definition\n#  pg_primary_only:       # Collector branch name. Must be UNIQUE among the entire configuration\n#    name: pg             # Collector namespace, used as METRIC PREFIX, set to branch name by default, can be override\n#                         # the same namespace may contain multiple collector branches. It`s the user`s responsibility\n#                         # to make sure that AT MOST ONE collector is picked for each namespace.\n#\n#    desc: PostgreSQL basic information (on primary)                 # Collector description\n#    query: |                                                        # Metrics Query SQL\n#\n#      SELECT extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n#             pg_current_wal_lsn() - '0/0'                           AS lsn,\n#             pg_current_wal_insert_lsn() - '0/0'                    AS insert_lsn,\n#             pg_current_wal_lsn() - '0/0'                           AS write_lsn,\n#             pg_current_wal_flush_lsn() - '0/0'                     AS flush_lsn,\n#             extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n#             extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n#             pg_is_in_backup()                                      AS is_in_backup,\n#             extract(EPOCH FROM now() - pg_backup_start_time())     AS backup_time;\n#\n#                             # [OPTIONAL] metadata fields, control collector behavior\n#    ttl: 10                  # Cache TTL: in seconds, how long will pg_exporter cache this collector`s query result.\n#    timeout: 0.1             # Query Timeout: in seconds, queries that exceed this limit will be canceled.\n#    min_version: 100000      # minimal supported version, boundary IS included. In server version number format,\n#    max_version: 130000      # maximal supported version, boundary NOT included, In server version number format\n#    fatal: false             # Collector marked `fatal` fails, the entire scrape will abort immediately and marked as failed\n#    skip: false              # Collector marked `skip` will not be installed during the planning procedure\n#\n#    tags: [cluster, primary] # Collector tags, used for planning and scheduling\n#\n#    # tags are list of strings, which could be:\n#    #   * `cluster` marks this query as cluster level, so it will only execute once for the same PostgreSQL Server\n#    #   * `primary` or `master`  mark this query can only run on a primary instance (WILL NOT execute if pg_is_in_recovery())\n#    #   * `standby` or `replica` mark this query can only run on a replica instance (WILL execute if pg_is_in_recovery())\n#    # some special tag prefix have special interpretation:\n#    #   * `dbname:<dbname>` means this query will ONLY be executed on database with name `<dbname>`\n#    #   * `username:<user>` means this query will only be executed when connect with user `<user>`\n#    #   * `extension:<extname>` means this query will only be executed when extension `<extname>` is installed\n#    #   * `schema:<nspname>` means this query will only by executed when schema `<nspname>` exist\n#    #   * `not:<negtag>` means this query WILL NOT be executed when exporter is tagged with `<negtag>`\n#    #   * `<tag>` means this query WILL be executed when exporter is tagged with `<tag>`\n#    #   ( <tag> could not be cluster,primary,standby,master,replica,etc...)\n#\n#    # One or more \"predicate queries\" may be defined for a metric query. These\n#    # are run before the main metric query (after any cache hit check). If all\n#    # of them, when run sequentially, return a single row with a single column\n#    # boolean true result, the main metric query is executed. If any of them\n#    # return false or return zero rows, the main query is skipped. If any\n#    # predicate query returns more than one row, a non-boolean result, or fails\n#    # with an error, the whole query is marked failed. Predicate queries can be\n#    # used to check for the presence of specific functions, tables, extensions,\n#    # settings, and vendor-specific pg features before running the main query.\n#\n#    predicate_queries:\n#      - name: predicate query name\n#        predicate_query: |\n#          SELECT EXISTS (SELECT 1 FROM information_schema.routines WHERE routine_schema = 'pg_catalog' AND routine_name = 'pg_backup_start_time');\n#\n#    metrics:                 # List of returned columns, each column must have a `name` and `usage`, `rename` and `description` are optional\n#      - timestamp:           # Column name, should be exactly the same as returned column name\n#          usage: GAUGE       # Metric type, `usage` could be\n#                                  * DISCARD: completely ignoring this field\n#                                  * LABEL:   use columnName=columnValue as a label in metric\n#                                  * GAUGE:   Mark column as a gauge metric, full name will be `<query.name>_<column.name>`\n#                                  * COUNTER: Same as above, except it is a counter rather than a gauge.\n#          rename: ts         # [OPTIONAL] Alias, optional, the alias will be used instead of the column name\n#          description: xxxx  # [OPTIONAL] Description of the column, will be used as a metric description\n#          default: 0         # [OPTIONAL] Default value, will be used when column is NULL\n#          scale:   1000      # [OPTIONAL] Scale the value by this factor\n#      - lsn:\n#          usage: COUNTER\n#          description: log sequence number, current write location (on primary)\n#      - insert_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal inserting\n#      - write_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal writing\n#      - flush_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal syncing\n#      - uptime:\n#          usage: GAUGE\n#          description: seconds since postmaster start\n#      - conf_reload_time:\n#          usage: GAUGE\n#          description: seconds since last configuration reload\n#      - is_in_backup:\n#          usage: GAUGE\n#          description: 1 if backup is in progress\n#      - backup_time:\n#          usage: GAUGE\n#          description: seconds since the current backup start. null if don`t have one\n#\n#      .... # you can also use rename & scale to customize the metric name and value:\n#      - checkpoint_write_time:\n#          rename: write_time\n#          usage: COUNTER\n#          scale: 1e-3\n#          description: Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\n\n#==============================================================#\n# 4. Collector Presets\n#==============================================================#\n# pg_exporter is shipped with a series of preset collectors (already numbered and ordered by filename)\n#\n# 1xx  Basic metrics:        basic info, metadata, settings\n# 2xx  Replication metrics:  replication, walreceiver, downstream, sync standby, slots, subscription\n# 3xx  Persist metrics:      size, wal, background writer, checkpointer, ssl, checkpoint, recovery, slru cache, shmem usage\n# 4xx  Activity metrics:     backend count group by state, wait event, locks, xacts, queries\n# 5xx  Progress metrics:     clustering, vacuuming, indexing, basebackup, copy\n# 6xx  Database metrics:     pg_database, publication, subscription\n# 7xx  Object metrics:       pg_class, table, index, function, sequence, default partition\n# 8xx  Optional metrics:     optional metrics collector (disable by default, slow queries)\n# 9xx  Pgbouncer metrics:    metrics from pgbouncer admin database `pgbouncer`\n#\n# 100-599 Metrics for entire database cluster  (scrape once)\n# 600-899 Metrics for single database instance (scrape for each database ,except for pg_db itself)\n\n#==============================================================#\n# 5. Cache TTL\n#==============================================================#\n# Cache can be used for reducing query overhead, it can be enabled by setting a non-zero value for `ttl`\n# It is highly recommended to use cache to avoid duplicate scrapes. Especially when you got multiple Prometheus\n# scraping the same instance with slow monitoring queries. Setting `ttl` to zero or leaving blank will disable\n# result caching, which is the default behavior\n#\n# TTL has to be smaller than your scrape interval. 15s scrape interval and 10s TTL is a good start for\n# production environment. Some expensive monitoring queries (such as size/bloat check) will have longer `ttl`\n# which can also be used as a mechanism to achieve `different scrape frequency`\n\n#==============================================================#\n# 6. Query Timeout\n#==============================================================#\n# Collectors can be configured with an optional Timeout. If the collector's query executes more than that\n# timeout, it will be canceled immediately. Setting the `timeout` to 0 or leaving blank will reset it to\n# default timeout 0.1 (100ms). Setting it to any negative number will disable the query timeout feature.\n# All queries have a default timeout of 100ms, if exceeded, the query will be canceled immediately to avoid\n# avalanche. You can explicitly overwrite that option. but beware: in some extreme cases, if all your\n# timeouts sum up greater your scrape/cache interval (usually 15s), the queries may still be jammed.\n# or, you can just disable potential slow queries.\n\n#==============================================================#\n# 7. Version Compatibility\n#==============================================================#\n# Each collector has two optional version compatibility parameters: `min_version` and `max_version`.\n# These two parameters specify the version compatibility of the collector. If target postgres/pgbouncer's\n# version is less than `min_version`, or higher than `max_version`, the collector will not be installed.\n# These two parameters are using PostgreSQL server version number format, which is a 6-digit integer\n# format as <major:2 digit><minor:2 digit>:<release: 2 digit>.\n# For example, 090600 stands for 9.6, and 120100 stands for 12.1\n# And beware that version compatibility range is left-inclusive right exclusive: [min, max), set to zero or\n# leaving blank will affect as -inf or +inf\n\n#==============================================================#\n# 8. Fatality\n#==============================================================#\n# If a collector is marked with `fatal` falls, the entire scrape operation will be marked as fail and key metrics\n# `pg_up` / `pgbouncer_up` will be reset to 0. It is always a good practice to set up AT LEAST ONE fatal\n# collector for pg_exporter. `pg.pg_primary_only` and `pgbouncer_list` are the default fatal collector.\n#\n# If a collector without `fatal` flag fails, it will increase global fail counters. But the scrape operation\n# will carry on. The entire scrape result will not be marked as faile, thus will not affect the `<xx>_up` metric.\n\n#==============================================================#\n# 9. Skip\n#==============================================================#\n# Collector with `skip` flag set to true will NOT be installed.\n# This could be a handy option to disable collectors\n\n#==============================================================#\n# 10. Tags and Planning\n#==============================================================#\n# Tags are designed for collector planning & schedule. It can be handy to customize which queries run\n# on which instances. And thus you can use one-single monolith config for multiple environments\n#\n#  Tags are a list of strings, each string could be:\n#  Pre-defined special tags\n#    * `cluster` marks this collector as cluster level, so it will ONLY BE EXECUTED ONCE for the same PostgreSQL Server\n#    * `primary` or `master` mark this collector as primary-only, so it WILL NOT work iff pg_is_in_recovery()\n#    * `standby` or `replica` mark this collector as replica-only, so it WILL work iff pg_is_in_recovery()\n#  Special tag prefix which have different interpretation:\n#    * `dbname:<dbname>` means this collector will ONLY work on database with name `<dbname>`\n#    * `username:<user>` means this collector will ONLY work when connect with user `<user>`\n#    * `extension:<extname>` means this collector will ONLY work when extension `<extname>` is installed\n#    * `schema:<nspname>` means this collector will only work when schema `<nspname>` exists\n#  Customized positive tags (filter) and negative tags (taint)\n#    * `not:<negtag>` means this collector WILL NOT work when exporter is tagged with `<negtag>`\n#    * `<tag>` means this query WILL work if exporter is tagged with `<tag>` (special tags not included)\n#\n#  pg_exporter will trigger the Planning procedure after connecting to the target. It will gather database facts\n#  and match them with tags and other metadata (such as supported version range). Collector will only\n#  be installed if and only if it is compatible with the target server.\n\n\n"
  },
  {
    "path": "config/0110-pg.yml",
    "content": "#==============================================================#\n# 0110 pg\n#==============================================================#\npg_primary_only:\n  name: pg\n  desc: PostgreSQL basic information (on primary)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      pg_current_wal_lsn() - '0/0'                           AS lsn,\n      pg_current_wal_insert_lsn() - '0/0'                    AS insert_lsn,\n      pg_current_wal_lsn() - '0/0'                           AS write_lsn,\n      pg_current_wal_flush_lsn() - '0/0'                     AS flush_lsn,\n      NULL::BIGINT                                           AS receive_lsn,\n      NULL::BIGINT                                           AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      NULL::FLOAT                                            AS last_replay_time,\n      0::FLOAT                                               AS lag,\n      pg_is_in_recovery()                                    AS is_in_recovery,\n      FALSE                                                  AS is_wal_replay_paused;\n  tags: [ cluster, primary ]\n  ttl: 1\n  min_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\npg_replica_only:\n  name: pg\n  desc: PostgreSQL basic information (on replica)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      pg_last_wal_replay_lsn() - '0/0'                       AS lsn,\n      NULL::BIGINT                                           AS insert_lsn,\n      NULL::BIGINT                                           AS write_lsn,\n      NULL::BIGINT                                           AS flush_lsn,\n      pg_last_wal_receive_lsn() - '0/0'                      AS receive_lsn,\n      pg_last_wal_replay_lsn() - '0/0'                       AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      extract(EPOCH FROM pg_last_xact_replay_timestamp())    AS last_replay_time,\n      CASE WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0\n          ELSE EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp()) END AS lag,\n      pg_is_in_recovery() AS is_in_recovery,\n      pg_is_wal_replay_paused() AS is_wal_replay_paused;\n\n  tags: [ cluster, replica ]\n  ttl: 1\n  min_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\n\n"
  },
  {
    "path": "config/0120-pg_meta.yml",
    "content": "#==============================================================#\n# 0120 pg_meta\n#==============================================================#\npg_meta_13:\n  name: pg_meta\n  desc: PostgreSQL meta info for pg 13+, with extra primary conninfo\n  query: |\n    SELECT \n      (SELECT system_identifier FROM pg_control_system()) AS cluster_id,\n      current_setting('cluster_name')                     AS cluster_name,\n      current_setting('port')                             AS listen_port,\n      current_setting('data_directory', true)             AS data_dir,\n      current_setting('config_file', true)                AS conf_path,\n      current_setting('hba_file', true)                   AS hba_path,\n      current_setting('wal_level')                        AS wal_level,\n      current_setting('server_encoding')                  AS encoding,\n      current_setting('server_version')                   AS version,\n      current_setting('server_version_num')               AS ver_num,\n      version()                                           AS ver_str,\n      current_setting('shared_preload_libraries', true)   AS extensions,\n      current_setting('primary_conninfo', true)           AS primary_conninfo,\n      1                                                   AS info\n  ttl: 10\n  min_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\npg_meta_10:\n  name: pg_meta\n  desc: PostgreSQL meta info\n  query: |\n    SELECT \n      (SELECT system_identifier FROM pg_control_system()) AS cluster_id,\n      current_setting('cluster_name')                     AS cluster_name,\n      current_setting('port')                             AS listen_port,\n      current_setting('data_directory', true)             AS data_dir,\n      current_setting('config_file', true)                AS conf_path,\n      current_setting('hba_file', true)                   AS hba_path,\n      current_setting('wal_level')                        AS wal_level,\n      current_setting('server_encoding')                  AS encoding,\n      current_setting('server_version')                   AS version,\n      current_setting('server_version_num')               AS ver_num,\n      version()                                           AS ver_str,\n      current_setting('shared_preload_libraries', true)   AS extensions,\n      'N/A'                                               AS primary_conninfo,\n      1                                                   AS info\n  ttl: 10\n  min_version: 090600\n  max_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\n"
  },
  {
    "path": "config/0130-pg_setting.yml",
    "content": "#==============================================================#\n# 0130 pg_setting\n#==============================================================#\n# Key PostgreSQL configuration parameters\n# All parameters use current_setting(name, missing_ok) for version safety\n# Parameters introduced after PG10 use missing_ok=true to return NULL on older versions\npg_setting:\n  name: pg_setting\n  desc: PostgreSQL shared configuration parameters (shared across all databases)\n  query: |\n    SELECT\n      current_setting('max_connections')::int                          AS max_connections,\n      current_setting('max_prepared_transactions')::int                AS max_prepared_transactions,\n      current_setting('max_locks_per_transaction')::int                AS max_locks_per_transaction,\n      current_setting('max_worker_processes')::int                     AS max_worker_processes,\n      current_setting('max_parallel_workers')::int                     AS max_parallel_workers,\n      current_setting('max_parallel_workers_per_gather')::int          AS max_parallel_workers_per_gather,\n      current_setting('max_parallel_maintenance_workers', true)::int   AS max_parallel_maintenance_workers,\n      current_setting('max_replication_slots')::int                    AS max_replication_slots,\n      current_setting('max_wal_senders')::int                          AS max_wal_senders,\n      current_setting('block_size')::int                               AS block_size,\n      current_setting('wal_block_size')::int                           AS wal_block_size,\n      pg_size_bytes(current_setting('segment_size'))                   AS segment_size,\n      pg_size_bytes(current_setting('wal_segment_size'))               AS wal_segment_size,\n      CASE current_setting('data_checksums') WHEN 'on' THEN 1 ELSE 0 END AS data_checksums,\n      CASE current_setting('wal_log_hints') WHEN 'on' THEN 1 ELSE 0 END AS wal_log_hints,\n      CASE current_setting('fsync') WHEN 'on' THEN 1 ELSE 0 END AS fsync,\n      CASE current_setting('full_page_writes') WHEN 'on' THEN 1 ELSE 0 END AS full_page_writes,\n      CASE current_setting('wal_level') WHEN 'logical' THEN 3 WHEN 'replica' THEN 2 WHEN 'minimal' THEN 1 ELSE 0 END AS wal_level,\n      pg_size_bytes(current_setting('min_wal_size'))                   AS min_wal_size,\n      pg_size_bytes(current_setting('max_wal_size'))                   AS max_wal_size,\n      pg_size_bytes(current_setting('max_slot_wal_keep_size', true))   AS max_slot_wal_keep_size,\n      pg_size_bytes(current_setting('shared_buffers'))                 AS shared_buffers,\n      pg_size_bytes(current_setting('work_mem'))                       AS work_mem,\n      pg_size_bytes(current_setting('maintenance_work_mem'))           AS maintenance_work_mem,\n      pg_size_bytes(current_setting('effective_cache_size'))           AS effective_cache_size,\n      pg_size_bytes(current_setting('shared_memory_size', true))       AS shared_memory_size,\n      CASE current_setting('huge_pages_status', true) WHEN 'on' THEN 1 WHEN 'off' THEN 0 WHEN 'unknown' THEN -1 ELSE NULL END AS hugepage_status,\n      current_setting('shared_memory_size_in_huge_pages', true)::int   AS hugepage_count,\n      CASE current_setting('archive_mode') WHEN 'off' THEN 0 WHEN 'on' THEN 1 WHEN 'always' THEN 2 ELSE -1 END AS archive_mode,\n      CASE current_setting('autovacuum') WHEN 'on' THEN 1 ELSE 0 END AS autovacuum,\n      current_setting('autovacuum_max_workers')::int                   AS autovacuum_max_workers,\n      extract(epoch from current_setting('checkpoint_timeout')::interval)::int AS checkpoint_timeout,\n      current_setting('checkpoint_completion_target')::float           AS checkpoint_completion_target,\n      CASE current_setting('hot_standby') WHEN 'on' THEN 1 ELSE 0 END AS hot_standby,\n      CASE current_setting('synchronous_commit')\n        WHEN 'off' THEN 0 WHEN 'local' THEN 1 WHEN 'remote_write' THEN 2\n        WHEN 'on' THEN 3 WHEN 'remote_apply' THEN 4 ELSE -1 END AS synchronous_commit,\n      CASE current_setting('io_method', true)\n        WHEN 'sync' THEN 0 WHEN 'worker' THEN 1 WHEN 'io_uring' THEN 2 ELSE NULL END AS io_method;\n\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - max_connections:                  { usage: GAUGE ,description: \"maximum number of concurrent connections to the database server\" }\n    - max_prepared_transactions:        { usage: GAUGE ,description: \"maximum number of transactions that can be in the prepared state simultaneously\" }\n    - max_locks_per_transaction:        { usage: GAUGE ,description: \"maximum number of locks per transaction\" }\n    - max_worker_processes:             { usage: GAUGE ,description: \"maximum number of background processes\" }\n    - max_parallel_workers:             { usage: GAUGE ,description: \"maximum number of parallel workers that can be active at one time\" }\n    - max_parallel_workers_per_gather:  { usage: GAUGE ,description: \"maximum number of parallel workers per Gather node\" }\n    - max_parallel_maintenance_workers: { usage: GAUGE ,description: \"maximum number of parallel maintenance workers (PG11+, NULL on older)\" }\n    - max_replication_slots:            { usage: GAUGE ,description: \"maximum number of replication slots\" }\n    - max_wal_senders:                  { usage: GAUGE ,description: \"maximum number of concurrent WAL sender connections\" }\n    - block_size:                       { usage: GAUGE ,description: \"database block size in bytes (default 8192)\" }\n    - wal_block_size:                   { usage: GAUGE ,description: \"WAL block size in bytes\" }\n    - segment_size:                     { usage: GAUGE ,description: \"database file segment size in bytes\" }\n    - wal_segment_size:                 { usage: GAUGE ,description: \"WAL segment size in bytes\" }\n    - data_checksums:                   { usage: GAUGE ,description: \"data checksums enabled, 1=on 0=off\" }\n    - wal_log_hints:                    { usage: GAUGE ,description: \"WAL log hints enabled, 1=on 0=off\" }\n    - fsync:                            { usage: GAUGE ,description: \"fsync enabled (CRITICAL for data safety), 1=on 0=off\" }\n    - full_page_writes:                 { usage: GAUGE ,description: \"full page writes enabled, 1=on 0=off\" }\n    - wal_level:                        { usage: GAUGE ,description: \"WAL level, 1=minimal 2=replica 3=logical\" }\n    - min_wal_size:                     { usage: GAUGE ,description: \"minimum WAL size in bytes\" }\n    - max_wal_size:                     { usage: GAUGE ,description: \"maximum WAL size in bytes\" }\n    - max_slot_wal_keep_size:           { usage: GAUGE ,description: \"maximum WAL size retained by replication slots in bytes (PG13+, NULL on older)\" }\n    - shared_buffers:                   { usage: GAUGE ,description: \"shared buffer size in bytes\" }\n    - work_mem:                         { usage: GAUGE ,description: \"work memory size in bytes\" }\n    - maintenance_work_mem:             { usage: GAUGE ,description: \"maintenance work memory size in bytes\" }\n    - effective_cache_size:             { usage: GAUGE ,description: \"planner's assumption about effective OS cache size in bytes\" }\n    - shared_memory_size:               { usage: GAUGE ,description: \"total shared memory size in bytes (PG13+, NULL on older)\" }\n    - hugepage_status:                  { usage: GAUGE ,description: \"huge pages status, 1=on 0=off -1=unknown NULL=unavailable (PG14+)\" }\n    - hugepage_count:                   { usage: GAUGE ,description: \"number of huge pages needed for shared memory (PG14+, NULL on older)\" }\n    - archive_mode:                     { usage: GAUGE ,description: \"archive mode, 0=off 1=on 2=always\" }\n    - autovacuum:                       { usage: GAUGE ,description: \"autovacuum enabled, 1=on 0=off\" }\n    - autovacuum_max_workers:           { usage: GAUGE ,description: \"maximum number of autovacuum worker processes\" }\n    - checkpoint_timeout:               { usage: GAUGE ,description: \"checkpoint timeout in seconds\" }\n    - checkpoint_completion_target:     { usage: GAUGE ,description: \"checkpoint completion target (0.0-1.0)\" }\n    - hot_standby:                      { usage: GAUGE ,description: \"hot standby mode enabled, 1=on 0=off\" }\n    - synchronous_commit:               { usage: GAUGE ,description: \"synchronous commit level, 0=off 1=local 2=remote_write 3=on 4=remote_apply\" }\n    - io_method:                         { usage: GAUGE ,description: \"I/O method (PG18+), 0=sync 1=worker 2=io_uring NULL=unavailable\" }\n\n\n\n"
  },
  {
    "path": "config/0210-pg_repl.yml",
    "content": "#==============================================================#\n# 0210 pg_repl\n#==============================================================#\npg_repl_12:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 12+\n  query: |\n    SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n           CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n           CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n           sync_priority, backend_xmin::TEXT::BIGINT AS backend_xmin, current.lsn - '0/0' AS lsn,\n           current.lsn - sent_lsn AS sent_diff, current.lsn - write_lsn AS write_diff, current.lsn - flush_lsn AS flush_diff, current.lsn - replay_lsn AS replay_diff,\n           sent_lsn - '0/0' AS sent_lsn, write_lsn - '0/0' AS write_lsn, flush_lsn - '0/0' AS flush_lsn, replay_lsn - '0/0' AS replay_lsn,\n           coalesce(extract(EPOCH FROM write_lag), 0)  AS write_lag, coalesce(extract(EPOCH FROM flush_lag), 0)  AS flush_lag, coalesce(extract(EPOCH FROM replay_lag), 0) AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time, extract(EPOCH FROM reply_time) AS reply_time\n    FROM pg_stat_replication, (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END AS lsn) current;\n  ttl: 10\n  min_version: 120000\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback.\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n    - reply_time:        { usage: GAUGE   ,description: \"Send time of last reply message received from standby server\" }\n\npg_repl_10:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics v10 v11\n  query: |\n    SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n           CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n           CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n           sync_priority, backend_xmin::TEXT::BIGINT AS backend_xmin, current.lsn - '0/0' AS lsn,\n           current.lsn - sent_lsn AS sent_diff, current.lsn - write_lsn AS write_diff, current.lsn - flush_lsn AS flush_diff, current.lsn - replay_lsn AS replay_diff,\n           sent_lsn - '0/0' AS sent_lsn, write_lsn - '0/0' AS write_lsn, flush_lsn - '0/0' AS flush_lsn, replay_lsn - '0/0' AS replay_lsn,\n           coalesce(extract(EPOCH FROM write_lag), 0)  AS write_lag, coalesce(extract(EPOCH FROM flush_lag), 0)  AS flush_lag, coalesce(extract(EPOCH FROM replay_lag), 0) AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM pg_stat_replication, (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END AS lsn) current;\n  ttl: 10\n  min_version: 100000\n  max_version: 120000\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback.\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\n\n"
  },
  {
    "path": "config/0220-pg_sync_standby.yml",
    "content": "#==============================================================#\n# 0220 pg_sync_standby\n#==============================================================#\npg_sync_standby:\n  name: pg_sync_standby\n  desc: PostgreSQL synchronous standby status and names\n  query: |\n    SELECT CASE WHEN names <> '' THEN names ELSE '<null>' END AS names, CASE WHEN names <> '' THEN 1 ELSE 0 END AS enabled FROM (SELECT current_setting('synchronous_standby_names') AS names) n;\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - names:             { usage: LABEL ,description: \"List of standby servers that can support synchronous replication, <null> if not enabled\" }\n    - enabled:           { usage: GAUGE ,description: \"Synchronous commit enabled, 1 if enabled, 0 if disabled\" }\n\n\n"
  },
  {
    "path": "config/0230-pg_downstream.yml",
    "content": "#==============================================================#\n# 0230 pg_downstream\n#==============================================================#\npg_downstream:\n  name: pg_downstream\n  desc: PostgreSQL replication client count group by state\n  query: |\n    SELECT l.state, coalesce(count, 0 ) AS count FROM unnest(ARRAY ['streaming','startup','catchup', 'backup', 'stopping']) l(state) LEFT JOIN (SELECT state, count(*) AS count FROM pg_stat_replication GROUP BY state)r ON l.state =  r.state;\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - state:             { usage: LABEL ,description: \"Replication client state, could be one of startup|catchup|streaming|backup|stopping\" }\n    - count:             { usage: GAUGE ,description: \"Count of corresponding state\" }\n\n\n"
  },
  {
    "path": "config/0240-pg_slot.yml",
    "content": "#==============================================================#\n# 0240 pg_slot\n#==============================================================#\npg_slot_17:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v17, slot also exists on standby\n  query: |-\n    SELECT s.slot_name, s.slot_type, plugin, database AS datname,datoid,active_pid,\n       active,temporary,two_phase,conflicting,failover,synced,\n       xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n       restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n       CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n       safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status,\n       spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,extract(EPOCH FROM stats_reset) AS reset_time,\n       extract(EPOCH FROM inactive_since) AS inactive_since, CASE invalidation_reason WHEN 'wal_removed' THEN 1 WHEN 'rows_removed' THEN 2 WHEN 'wal_level_insufficient' THEN 3 ELSE 0 END AS invalidation_reason \n    FROM pg_replication_slots s LEFT OUTER JOIN pg_stat_replication_slots ss ON s.slot_name = ss.slot_name;\n\n  ttl: 10\n  min_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - two_phase:           { usage: GAUGE    ,description: \"True(1) if the slot is enabled for decoding prepared transactions. Always false for physical slots.\" }\n    - conflicting:         { usage: GAUGE    ,description: \"True(1) if this logical slot conflicted with recovery. Always NULL for physical slots.\" }\n    - failover:            { usage: GAUGE    ,description: \"True(1) if this is a logical slot enabled to be synced to the standbys\" }\n    - synced:              { usage: GAUGE    ,description: \"True(1) if this is a logical slot that was synced from a primary server\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n    - spill_txns:          { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)\" }\n    - spill_count:         { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding\" }\n    - spill_bytes:         { usage: COUNTER  ,description: \"Bytes that spilled to disk due to logical decode mem exceeding\" }\n    - stream_txns:         { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_count:        { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_bytes:        { usage: COUNTER  ,description: \"Bytes that streamed to decoding output plugin after mem exceed\" }\n    - total_txns:          { usage: COUNTER  ,description: \"Number of decoded xacts sent to the decoding output plugin for this slot\" }\n    - total_bytes:         { usage: COUNTER  ,description: \"Number of decoded bytes sent to the decoding output plugin for this slot\" }\n    - reset_time:          { usage: GAUGE    ,description: \"When statistics were last reset\" }\n    - invalidation_reason: { usage: GAUGE    ,description: \"ok=0, wal_removed=1, rows_removed=2, wal_level_insufficient=3\" }\n    - inactive_since:      { usage: GAUGE    ,description: \"The time when the slot became inactive\" }\n\npg_slot_16:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v16 with conflicting, now slot also exists on standby\n  query: |-\n    SELECT s.slot_name, s.slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,two_phase,conflicting,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n      safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status,\n      spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_replication_slots s LEFT OUTER JOIN pg_stat_replication_slots ss ON s.slot_name = ss.slot_name;\n\n  ttl: 10\n  min_version: 160000\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - two_phase:           { usage: GAUGE    ,description: \"True(1) if the slot is enabled for decoding prepared transactions. Always false for physical slots.\" }\n    - conflicting:         { usage: GAUGE    ,description: \"True if this logical slot conflicted with recovery. Always NULL for physical slots.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n    - spill_txns:          { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)\" }\n    - spill_count:         { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding\" }\n    - spill_bytes:         { usage: COUNTER  ,description: \"Bytes that spilled to disk due to logical decode mem exceeding\" }\n    - stream_txns:         { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_count:        { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_bytes:        { usage: COUNTER  ,description: \"Bytes that streamed to decoding output plugin after mem exceed\" }\n    - total_txns:          { usage: COUNTER  ,description: \"Number of decoded xacts sent to the decoding output plugin for this slot\" }\n    - total_bytes:         { usage: COUNTER  ,description: \"Number of decoded bytes sent to the decoding output plugin for this slot\" }\n    - reset_time:          { usage: GAUGE    ,description: \"When statistics were last reset\" }\n\npg_slot_14:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v14 with pg_stat_replication_slots metrics\n  query: |-\n    SELECT s.slot_name, s.slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,two_phase,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n      safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status,\n      spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_replication_slots s LEFT OUTER JOIN pg_stat_replication_slots ss ON s.slot_name = ss.slot_name;\n\n  ttl: 10\n  min_version: 140000\n  max_version: 160000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - two_phase:           { usage: GAUGE    ,description: \"True(1) if the slot is enabled for decoding prepared transactions. Always false for physical slots.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n    - spill_txns:          { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)\" }\n    - spill_count:         { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding\" }\n    - spill_bytes:         { usage: COUNTER  ,description: \"Bytes that spilled to disk due to logical decode mem exceeding\" }\n    - stream_txns:         { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_count:        { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_bytes:        { usage: COUNTER  ,description: \"Bytes that streamed to decoding output plugin after mem exceed\" }\n    - total_txns:          { usage: COUNTER  ,description: \"Number of decoded xacts sent to the decoding output plugin for this slot\" }\n    - total_bytes:         { usage: COUNTER  ,description: \"Number of decoded bytes sent to the decoding output plugin for this slot\" }\n    - reset_time:          { usage: GAUGE    ,description: \"When statistics were last reset\" }\n\npg_slot_13:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v13 (wal safe size and status)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n      safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status\n    FROM pg_replication_slots;\n\n  ttl: 10\n  min_version: 130000\n  max_version: 140000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n\npg_slot_10:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 10 ~ 12\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes\n    FROM pg_replication_slots;\n\n  ttl: 10\n  min_version: 100000\n  max_version: 130000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\n\n"
  },
  {
    "path": "config/0250-pg_recv.yml",
    "content": "#==============================================================#\n# 0250 pg_recv\n#==============================================================#\npg_recv_13:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics 13+\n  query: |-\n    SELECT \n      coalesce(sender_host, (regexp_match(conninfo, '.*host=(\\S+).*'))[1]) AS sender_host, coalesce(sender_port::TEXT, (regexp_match(conninfo, '.*port=(\\S+).*'))[1]) AS sender_port, coalesce(slot_name, 'NULL') AS slot_name,\n      pid, CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      receive_start_lsn - '0/0' AS init_lsn,receive_start_tli AS init_tli,\n      flushed_lsn - '0/0' AS flush_lsn,written_lsn - '0/0' AS write_lsn, received_tli AS flush_tli, latest_end_lsn - '0/0' AS reported_lsn,\n      last_msg_send_time AS msg_send_time,last_msg_receipt_time AS msg_recv_time,latest_end_time AS reported_time,now() AS time FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  min_version: 130000\n  tags: [ cluster, replica ]\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - write_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and written to disk, but not flushed.\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\npg_recv_11:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics (11-12)\n  query: |-\n    SELECT \n      coalesce(sender_host, (regexp_match(conninfo, '.*host=(\\S+).*'))[1]) AS sender_host, coalesce(sender_port::TEXT, (regexp_match(conninfo, '.*port=(\\S+).*'))[1]) AS sender_port, coalesce(slot_name, 'NULL') AS slot_name,\n      pid, CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      receive_start_lsn - '0/0' AS init_lsn,receive_start_tli AS init_tli,\n      received_lsn - '0/0' AS flush_lsn, received_tli AS flush_tli, latest_end_lsn - '0/0' AS reported_lsn,\n      last_msg_send_time AS msg_send_time,last_msg_receipt_time AS msg_recv_time,latest_end_time AS reported_time,now() AS time FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  tags: [ cluster, replica ]\n  min_version: 110000\n  max_version: 130000\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\npg_recv_10:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics (10)\n  query: |-\n    SELECT \n      (regexp_match(conninfo, '.*host=(\\S+).*'))[1] AS sender_host, (regexp_match(conninfo, '.*port=(\\S+).*'))[1] AS sender_port, coalesce(slot_name, 'NULL') AS slot_name,\n      pid, CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      receive_start_lsn - '0/0' AS init_lsn,receive_start_tli AS init_tli,\n      received_lsn - '0/0' AS flush_lsn, received_tli AS flush_tli, latest_end_lsn - '0/0' AS reported_lsn,\n      last_msg_send_time AS msg_send_time,last_msg_receipt_time AS msg_recv_time,latest_end_time AS reported_time,now() AS time FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  tags: [ cluster, replica ]\n  min_version: 100000\n  max_version: 110000\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\n"
  },
  {
    "path": "config/0260-pg_sub.yml",
    "content": "#==============================================================#\n# 0260 pg_sub\n#==============================================================#\npg_sub_16:\n  name: pg_sub\n  desc: PostgreSQL subscription statistics (16+)\n  query: |-\n    SELECT \n      s1.subname, subid AS id, pid, received_lsn, reported_lsn,\n      msg_send_time, msg_recv_time, reported_time,\n      apply_error_count, sync_error_count\n    FROM\n      (SELECT\n        subname, subid, pid,\n        received_lsn - '0/0' AS received_lsn, latest_end_lsn - '0/0' AS reported_lsn,\n        extract(epoch from last_msg_send_time) AS msg_send_time,\n        extract(epoch from last_msg_receipt_time) AS msg_recv_time,\n        extract(epoch from latest_end_time) AS reported_time\n      FROM pg_stat_subscription \n      WHERE relid IS NULL AND leader_pid IS NULL) s1\n    LEFT OUTER JOIN pg_stat_subscription_stats s2 USING(subid);\n\n  ttl: 10\n  min_version: 160000\n  tags: [ cluster ]\n  metrics:\n    - subname:             { usage: LABEL   ,description: \"Name of this subscription\" }\n    - id:                  { usage: GAUGE   ,description: \"OID of the subscription\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the subscription leader apply worker\" }\n    - received_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location received\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - apply_error_count:   { usage: COUNTER ,description: \"Number of times an error occurred while applying changes\" }\n    - sync_error_count:    { usage: COUNTER ,description: \"Number of times an error occurred during the initial table synchronization\" }\n\npg_sub_15:\n  name: pg_sub\n  desc: PostgreSQL subscription statistics (15)\n  query: |-\n    SELECT \n      s1.subname, subid AS id, pid, received_lsn, reported_lsn,\n      msg_send_time, msg_recv_time, reported_time,\n      apply_error_count, sync_error_count\n    FROM\n      (SELECT\n        subname, subid, pid,\n        received_lsn - '0/0' AS received_lsn, latest_end_lsn - '0/0' AS reported_lsn,\n        extract(epoch from last_msg_send_time) AS msg_send_time,\n        extract(epoch from last_msg_receipt_time) AS msg_recv_time,\n        extract(epoch from latest_end_time) AS reported_time\n      FROM pg_stat_subscription WHERE relid ISNULL) s1\n    LEFT OUTER JOIN pg_stat_subscription_stats s2 USING(subid);\n\n  ttl: 10\n  min_version: 150000\n  max_version: 160000\n  tags: [ cluster ]\n  metrics:\n    - subname:             { usage: LABEL   ,description: \"Name of this subscription\" }\n    - id:                  { usage: GAUGE   ,description: \"OID of the subscription\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the subscription main apply worker process\" }\n    - received_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location received\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - apply_error_count:   { usage: COUNTER ,description: \"Number of times an error occurred while applying changes.\" }\n    - sync_error_count:    { usage: COUNTER ,description: \"Number of times an error occurred during the initial table synchronization\" }\n\npg_sub_10:\n  name: pg_sub\n  desc: PostgreSQL subscription statistics (10-14)\n  query: |-\n    SELECT \n      subname, subid AS id, pid,\n      received_lsn - '0/0' AS received_lsn, latest_end_lsn - '0/0' AS reported_lsn,\n      extract(epoch from last_msg_send_time) AS msg_send_time,\n      extract(epoch from last_msg_receipt_time) AS msg_recv_time,\n      extract(epoch from latest_end_time) AS reported_time\n    FROM pg_stat_subscription WHERE relid ISNULL;\n\n  ttl: 10\n  min_version: 100000\n  max_version: 150000\n  tags: [ cluster ]\n  metrics:\n    - subname:             { usage: LABEL   ,description: \"Name of this subscription\" }\n    - id:                  { usage: GAUGE   ,description: \"OID of the subscription\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the subscription main apply worker process\" }\n    - received_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location received\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n\n\n"
  },
  {
    "path": "config/0270-pg_origin.yml",
    "content": "#==============================================================#\n# 0270 pg_origin\n#==============================================================#\n# skip by default, require additional privilege setup\n# GRANT SELECT ON pg_replication_origin, pg_replication_origin_status TO pg_monitor;\npg_origin:\n  name: pg_origin\n  desc: PostgreSQL replay state (approximate) for a certain origin\n  query: SELECT roname, remote_lsn - '0/0' AS remote_lsn, local_lsn - '0/0' AS local_lsn FROM pg_replication_origin o LEFT JOIN pg_replication_origin_status os ON o.roident = os.local_id;\n  ttl: 10\n  min_version: 090500\n  skip: true\n  tags: [ cluster ]\n  metrics:\n    - roname:              { usage: LABEL     ,description: \"The external, user defined, name of a replication origin.\" }\n    - remote_lsn:          { usage: COUNTER   ,description: \"The origin node's LSN up to which data has been replicated.\" }\n    - local_lsn:           { usage: COUNTER   ,description: \"This node's LSN at which remote_lsn has been replicated.\" }\n\n\n"
  },
  {
    "path": "config/0300-pg_io.yml",
    "content": "#==============================================================#\n# 0300 pg_io\n#==============================================================#\npg_io_18:\n  name: pg_io\n  desc: PostgreSQL I/O stats since v18\n  query: |-\n    SELECT backend_type AS \"type\",object,context,reads,read_bytes,read_time,writes,write_bytes,write_time,writebacks,writeback_time,\n    extends,extend_bytes,extend_time,hits,evictions,reuses,fsyncs,fsync_time,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_io;\n\n  ttl: 10\n  timeout: 1\n  min_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - type:               { usage: LABEL                              ,description: \"Type of backend\" }\n    - object:             { usage: LABEL                              ,description: \"Target object of an I/O operation, relation or temp\" }\n    - context:            { usage: LABEL                              ,description: \"The context of an I/O operation. normal,vacuum,bulkread,bulkwrite\" }\n    - reads:              { usage: COUNTER ,default: 0                ,description: \"Number of read operations, each of the size specified in op_bytes.\" }\n    - read_bytes:         { usage: COUNTER ,default: 0                ,description: \"Number of read bytes\" }\n    - read_time:          { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in read operations in seconds\" }\n    - writes:             { usage: COUNTER ,default: 0                ,description: \"Number of write operations, each of the size specified in op_bytes.\" }\n    - write_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in write operations in seconds\" }\n    - write_bytes:        { usage: COUNTER ,default: 0                ,description: \"Number of write bytes\" }\n    - writebacks:         { usage: COUNTER ,default: 0                ,description: \"Number of units of size op_bytes which the process requested the kernel write out to permanent storage.\" }\n    - writeback_time:     { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in writeback operations in seconds\" }\n    - extends:            { usage: COUNTER ,default: 0                ,description: \"Number of relation extend operations, each of the size specified in op_bytes.\" }\n    - extend_bytes:       { usage: COUNTER ,default: 0                ,description: \"Number of extend bytes\" }\n    - extend_time:        { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in extend operations in seconds\" }\n    - hits:               { usage: COUNTER ,default: 0                ,description: \"The number of times a desired block was found in a shared buffer.\" }\n    - evictions:          { usage: COUNTER ,default: 0                ,description: \"Number of times a block has been written out from a shared or local buffer\" }\n    - reuses:             { usage: COUNTER ,default: 0                ,description: \"The number of times an existing buffer is reused\" }\n    - fsyncs:             { usage: COUNTER ,default: 0                ,description: \"Number of fsync calls. These are only tracked in context normal\" }\n    - fsync_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in fsync operations in seconds\" }\n    - reset_time:         { usage: GAUGE                              ,description: \"Timestamp at which these statistics were last reset\" }\n\npg_io_16:\n  name: pg_io\n  desc: PostgreSQL I/O stats\n  query: |-\n    SELECT backend_type AS \"type\", object, context, reads, read_time,writes,write_time,writebacks,writeback_time,extends,\n      extend_time,hits,evictions,reuses,fsyncs,fsync_time,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_io;\n\n  ttl: 10\n  timeout: 1\n  min_version: 160000\n  max_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - type:               { usage: LABEL                              ,description: \"Type of backend\" }\n    - object:             { usage: LABEL                              ,description: \"Target object of an I/O operation, relation or temp\" }\n    - context:            { usage: LABEL                              ,description: \"The context of an I/O operation. normal,vacuum,bulkread,bulkwrite\" }\n    - reads:              { usage: COUNTER ,default: 0                ,description: \"Number of read operations, each of the size specified in op_bytes.\" }\n    - read_time:          { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in read operations in seconds\" }\n    - writes:             { usage: COUNTER ,default: 0                ,description: \"Number of write operations, each of the size specified in op_bytes.\" }\n    - write_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in write operations in seconds\" }\n    - writebacks:         { usage: COUNTER ,default: 0                ,description: \"Number of units of size op_bytes which the process requested the kernel write out to permanent storage.\" }\n    - writeback_time:     { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in writeback operations in seconds\" }\n    - extends:            { usage: COUNTER ,default: 0                ,description: \"Number of relation extend operations, each of the size specified in op_bytes.\" }\n    - extend_time:        { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in extend operations in seconds\" }\n    - hits:               { usage: COUNTER ,default: 0                ,description: \"The number of times a desired block was found in a shared buffer.\" }\n    - evictions:          { usage: COUNTER ,default: 0                ,description: \"Number of times a block has been written out from a shared or local buffer\" }\n    - reuses:             { usage: COUNTER ,default: 0                ,description: \"The number of times an existing buffer is reused\" }\n    - fsyncs:             { usage: COUNTER ,default: 0                ,description: \"Number of fsync calls. These are only tracked in context normal\" }\n    - fsync_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in fsync operations in seconds\" }\n    - reset_time:         { usage: GAUGE                              ,description: \"Timestamp at which these statistics were last reset\" }\n\n\n"
  },
  {
    "path": "config/0310-pg_size.yml",
    "content": "#==============================================================#\n# 0310 pg_size\n#==============================================================#\npg_size:\n  name: pg_size\n  desc: PostgreSQL Database, WAL, Log size since v10\n  query: |-\n    SELECT datname, pg_database_size(oid) AS bytes FROM pg_database\n    UNION ALL SELECT 'log', CASE WHEN current_setting('logging_collector') = 'on' THEN COALESCE((SELECT SUM(size) FROM pg_catalog.pg_ls_logdir()), 0) ELSE 0 END\n    UNION ALL SELECT 'wal', COALESCE((SELECT SUM(size) FROM pg_catalog.pg_ls_waldir()), 0);\n\n  ttl: 60\n  timeout: 1\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Database name, or special category wal, or log\" }\n    - bytes:               { usage: GAUGE   ,description: \"File size in bytes\" }\n\n\n"
  },
  {
    "path": "config/0320-pg_archiver.yml",
    "content": "#==============================================================#\n# 0320 pg_archiver\n#==============================================================#\npg_archiver:\n  name: pg_archiver\n  desc: PostgreSQL archiver process statistics\n  query: |-\n    SELECT archived_count AS finish_count,failed_count,\n      extract(epoch FROM last_archived_time) AS finish_time,\n      extract(epoch FROM last_failed_time) AS failed_time,\n      extract(epoch FROM stats_reset) AS reset_time\n    FROM pg_stat_archiver;\n\n  ttl: 60\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - finish_count:        { usage: COUNTER ,description: \"Number of WAL files that have been successfully archived\" }\n    - failed_count:        { usage: COUNTER ,description: \"Number of failed attempts for archiving WAL files\" }\n    - finish_time:         { usage: GAUGE   ,description: \"Time of the last successful archive operation\" }\n    - failed_time:         { usage: GAUGE   ,description: \"Time of the last failed archival operation\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which archive statistics were last reset\" }\n\n\n"
  },
  {
    "path": "config/0330-pg_bgwriter.yml",
    "content": "#==============================================================#\n# 0330 pg_bgwriter\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_bgwriter.html\npg_bgwriter_17:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics PG 17+\"\n  query: SELECT buffers_clean, maxwritten_clean, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - buffers_clean:       { usage: COUNTER ,description: \"Number of buffers written by the background writer\" }\n    - maxwritten_clean:    { usage: COUNTER ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_alloc:       { usage: COUNTER ,description: \"Number of buffers allocated\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which bgwriter statistics were last reset\" }\n\npg_bgwriter_10:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics (PG 9.4-16)\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, buffers_clean, buffers_backend, maxwritten_clean, buffers_backend_fsync, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 090400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER              ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER              ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER              ,description: \"Number of buffers written during checkpoints\" }\n    - buffers_clean:         { usage: COUNTER              ,description: \"Number of buffers written by the background writer\" }\n    - buffers_backend:       { usage: COUNTER              ,description: \"Number of buffers written directly by a backend\" }\n    - maxwritten_clean:      { usage: COUNTER              ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_backend_fsync: { usage: COUNTER              ,description: \"Number of times a backend had to execute its own fsync call\" }\n    - buffers_alloc:         { usage: COUNTER              ,description: \"Number of buffers allocated\" }\n    - reset_time:            { usage: GAUGE                ,description: \"Time at which bgwriter statistics were last reset\" }\n\n"
  },
  {
    "path": "config/0331-pg_checkpointer.yml",
    "content": "#==============================================================#\n# 0331 pg_checkpointer\n#==============================================================#\npg_checkpointer_18:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 18+\"\n  query: SELECT num_timed, num_requested, num_done, restartpoints_timed, restartpoints_req, restartpoints_done, write_time, sync_time, buffers_written, slru_written, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_checkpointer;\n  ttl: 10\n  min_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - num_timed:             { usage: COUNTER ,rename: timed ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - num_requested:         { usage: COUNTER ,rename: req   ,description: \"Number of requested checkpoints that have been performed\" }\n    - num_done:              { usage: COUNTER ,rename: done  ,description: \"Number of checkpoints that have been performed\" }\n    - restartpoints_timed:   { usage: COUNTER                ,description: \"Number of scheduled restartpoints due to timeout or after a failed attempt to perform it\" }\n    - restartpoints_req:     { usage: COUNTER                ,description: \"Number of requested restartpoints\" }\n    - restartpoints_done:    { usage: COUNTER                ,description: \"Number of restartpoints that have been performed\" }\n    - write_time:            { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - sync_time:             { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_written:       { usage: COUNTER                ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - slru_written:          { usage: COUNTER                ,description: \"Number of SLRU buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                  ,description: \"Time at which checkpointer statistics were last reset\" }\n\npg_checkpointer_17:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 17\"\n  query: SELECT num_timed, num_requested, restartpoints_timed, restartpoints_req, restartpoints_done, write_time, sync_time, buffers_written, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_checkpointer;\n  ttl: 10\n  min_version: 170000\n  max_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - num_timed:             { usage: COUNTER ,rename: timed ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - num_requested:         { usage: COUNTER ,rename: req   ,description: \"Number of requested checkpoints that have been performed\" }\n    - restartpoints_timed:   { usage: COUNTER                ,description: \"Number of scheduled restartpoints due to timeout or after a failed attempt to perform it\" }\n    - restartpoints_req:     { usage: COUNTER                ,description: \"Number of requested restartpoints\" }\n    - restartpoints_done:    { usage: COUNTER                ,description: \"Number of restartpoints that have been performed\" }\n    - write_time:            { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - sync_time:             { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_written:       { usage: COUNTER                ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                  ,description: \"Time at which checkpointer statistics were last reset\" }\n\npg_checkpointer_10:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 9.4-16\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 090400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER ,rename: timed                   ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER ,rename: req                     ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,rename: write_time ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,rename: sync_time  ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER ,rename: buffers_written         ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                                    ,description: \"Time at which checkpointer statistics were last reset\" }\n\n"
  },
  {
    "path": "config/0340-pg_ssl.yml",
    "content": "#==============================================================#\n# 0340 pg_ssl\n#==============================================================#\npg_ssl:\n  name: pg_ssl\n  desc: PostgreSQL SSL client connection count\n  query: |\n    SELECT count(*) FILTER (WHERE ssl) AS enabled, count(*) FILTER ( WHERE NOT ssl) AS disabled FROM pg_stat_ssl;\n  ttl: 10\n  min_version: 090500\n  tags: [ cluster ]\n  metrics:\n    - enabled:            { usage: GAUGE   ,description: \"Number of client connection that use ssl\" }\n    - disabled:           { usage: GAUGE   ,description: \"Number of client connection that does not use ssl\" }\n\n\n"
  },
  {
    "path": "config/0350-pg_checkpoint.yml",
    "content": "#==============================================================#\n# 0350 pg_checkpoint\n#==============================================================#\npg_checkpoint:\n  name: pg_checkpoint\n  desc: checkpoint information from pg_control_checkpoint since 10\n  query: |-\n    SELECT \n      checkpoint_lsn - '0/0' AS checkpoint_lsn,\n      redo_lsn - '0/0' AS redo_lsn,\n      timeline_id AS tli,\n      prev_timeline_id AS prev_tli,\n      full_page_writes,\n      split_part(next_xid, ':', 1) AS next_xid_epoch,\n      split_part(next_xid, ':', 2) AS next_xid,\n      next_oid::BIGINT,\n      next_multixact_id::text::BIGINT,\n      next_multi_offset::text::BIGINT,\n      oldest_xid::text::BIGINT,\n      oldest_xid_dbid::text::BIGINT,\n      oldest_active_xid::text::BIGINT,\n      oldest_multi_xid::text::BIGINT,\n      oldest_multi_dbid::BIGINT,\n      oldest_commit_ts_xid::text::BIGINT,\n      newest_commit_ts_xid::text::BIGINT,\n      checkpoint_time                             AS time,\n      extract(epoch from now() - checkpoint_time) AS elapse\n    FROM pg_control_checkpoint();\n\n  ttl: 60\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - checkpoint_lsn:       { usage: COUNTER ,description: \"Latest checkpoint location\" }\n    - redo_lsn:             { usage: COUNTER ,description: \"Latest checkpoint's REDO location\" }\n    - tli:                  { usage: COUNTER ,description: \"Latest checkpoint's TimeLineID\" }\n    - prev_tli:             { usage: COUNTER ,description: \"Latest checkpoint's PrevTimeLineID\" }\n    - full_page_writes:     { usage: GAUGE   ,description: \"Latest checkpoint's full_page_writes enabled\" }\n    - next_xid_epoch:       { usage: COUNTER ,description: \"Latest checkpoint's NextXID epoch\" }\n    - next_xid:             { usage: COUNTER ,description: \"Latest checkpoint's NextXID xid\" }\n    - next_oid:             { usage: COUNTER ,description: \"Latest checkpoint's NextOID\" }\n    - next_multixact_id:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiXactId\" }\n    - next_multi_offset:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiOffset\" }\n    - oldest_xid:           { usage: COUNTER ,description: \"Latest checkpoint's oldestXID\" }\n    - oldest_xid_dbid:      { usage: GAUGE   ,description: \"Latest checkpoint's oldestXID's DB OID\" }\n    - oldest_active_xid:    { usage: COUNTER ,description: \"Latest checkpoint's oldestActiveXID\" }\n    - oldest_multi_xid:     { usage: COUNTER ,description: \"Latest checkpoint's oldestMultiXid\" }\n    - oldest_multi_dbid:    { usage: GAUGE   ,description: \"Latest checkpoint's oldestMulti's DB OID\" }\n    - oldest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's oldestCommitTsXid\" }\n    - newest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's newestCommitTsXid\" }\n    - time:                 { usage: COUNTER ,description: \"Time of latest checkpoint\" }\n    - elapse:               { usage: GAUGE   ,description: \"Seconds elapsed since latest checkpoint in seconds\" }\n\n\n"
  },
  {
    "path": "config/0355-pg_timeline.yml",
    "content": "#==============================================================#\n# 0355 pg_timeline\n#==============================================================#\npg_timeline:\n  name: pg_timeline\n  desc: Current timeline ID from primary or replica\n  query: |\n    SELECT COALESCE(\n      (SELECT received_tli FROM pg_stat_wal_receiver),\n      (SELECT timeline_id FROM pg_control_checkpoint())\n    ) AS id;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - id: { usage: GAUGE ,description: \"Current timeline ID\" }\n\n\n"
  },
  {
    "path": "config/0360-pg_recovery.yml",
    "content": "#==============================================================#\n# 0360 pg_recovery\n#==============================================================#\npg_recovery:\n  name: pg_recovery\n  desc: PostgreSQL control recovery metrics (9.6+)\n  query: |\n    SELECT min_recovery_end_timeline    AS min_timeline,\n      min_recovery_end_lsn - '0/0' AS min_lsn,\n      backup_start_lsn - '0/0'     AS backup_start_lsn,\n      backup_end_lsn - '0/0'       AS backup_end_lsn,\n      end_of_backup_record_required AS require_record\n    FROM pg_control_recovery();\n  ttl: 10\n  min_version: 090600\n  tags: [ cluster, replica ]\n  metrics:\n    - min_timeline:      { usage: COUNTER ,description: \"Min recovery ending loc's timeline\" }\n    - min_lsn:           { usage: COUNTER ,description: \"Minimum recovery ending location\" }\n    - backup_start_lsn:  { usage: COUNTER ,description: \"Backup start location\" }\n    - backup_end_lsn:    { usage: COUNTER ,description: \"Backup end location\" }\n    - require_record:    { usage: GAUGE   ,description: \"End-of-backup record required\" }\n\npg_recovery_prefetch:\n  name: pg_recovery_prefetch\n  desc: PostgreSQL recovery prefetch metrics (15+)\n  query: SELECT prefetch,hit,skip_init,skip_new,skip_fpw,skip_rep,wal_distance,block_distance,io_depth,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_recovery_prefetch;\n  ttl: 10\n  min_version: 150000\n  tags: [ cluster, replica ]\n  metrics:\n    - prefetch:       { usage: COUNTER ,description: \"Number of blocks prefetched because they were not in the buffer pool\" }\n    - hit:            { usage: COUNTER ,description: \"Number of blocks not prefetched because they were already in the buffer pool\" }\n    - skip_init:      { usage: COUNTER ,description: \"Number of blocks not prefetched because they would be zero-initialized\" }\n    - skip_new:       { usage: COUNTER ,description: \"Number of blocks not prefetched because they didn't exist yet\" }\n    - skip_fpw:       { usage: COUNTER ,description: \"Number of blocks not prefetched because a full page image was included in the WAL\" }\n    - skip_rep:       { usage: COUNTER ,description: \"Number of blocks not prefetched because they were already recently prefetched\" }\n    - wal_distance:   { usage: GAUGE   ,description: \"How many bytes ahead the prefetcher is looking\" }\n    - block_distance: { usage: GAUGE   ,description: \"How many blocks ahead the prefetcher is looking\" }\n    - io_depth:       { usage: GAUGE   ,description: \"How many prefetches have been initiated but are not yet known to have completed\" }\n    - reset_time:     { usage: GAUGE   ,description: \"Time at which these recovery prefetch statistics were last reset\" }\n\n\n"
  },
  {
    "path": "config/0370-pg_slru.yml",
    "content": "#==============================================================#\n# 0370 pg_slru\n#==============================================================#\npg_slru_13:\n  name: pg_slru\n  desc: PostgreSQL simple-least-recently-used (SLRU) cache statistics v13\n  query: SELECT name, blks_zeroed, blks_hit, blks_read, blks_written, blks_exists, flushes, truncates, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_slru;\n  ttl: 60\n  min_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - name:         { usage: LABEL   ,description: \"Name of the SLRU\" }\n    - blks_zeroed:  { usage: COUNTER ,description: \"Number of blocks zeroed during initializations\" }\n    - blks_hit:     { usage: COUNTER ,description: \"Number of times disk blocks were found already in the SLRU, so that a read was not necessary\" }\n    - blks_read:    { usage: COUNTER ,description: \"Number of disk blocks read for this SLRU\" }\n    - blks_written: { usage: COUNTER ,description: \"Number of disk blocks written for this SLRU\" }\n    - blks_exists:  { usage: COUNTER ,description: \"Number of blocks checked for existence for this SLRU\" }\n    - flushes:      { usage: COUNTER ,description: \"Number of flushes of dirty data for this SLRU\" }\n    - truncates:    { usage: COUNTER ,description: \"Number of truncates for this SLRU\" }\n    - reset_time:   { usage: GAUGE   ,description: \"Time at which these statistics were last reset\" }\n\n\n"
  },
  {
    "path": "config/0380-pg_shmem.yml",
    "content": "#==============================================================#\n# 0380 pg_shmem\n#==============================================================#\n# pg_shmem require su privilege to work. Disable it or create auxiliary function with su before use:\n# CREATE OR REPLACE FUNCTION monitor.pg_shmem() RETURNS SETOF pg_shmem_allocations AS $$ SELECT * FROM pg_shmem_allocations;$$ LANGUAGE SQL SECURITY DEFINER;\npg_shmem:\n  name: pg_shmem\n  desc: Allocations made from the server's main shared memory segment\n  query: SELECT coalesce(name, 'Free') AS name, off AS offset, size, allocated_size FROM monitor.pg_shmem();\n  ttl: 60\n  min_version: 130000\n  skip: true            # disable it by default\n  tags: [cluster, \"schema:monitor\" ]\n  metrics:\n    - name:            { usage: LABEL ,description: \"Name of the shared memory allocation\" }\n    - offset:          { usage: GAUGE ,description: \"The offset at which the allocation starts\" }\n    - size:            { usage: GAUGE ,description: \"Size of the allocation\" }\n    - allocated_size:  { usage: GAUGE ,description: \"Size of the allocation including padding\" }\n\n\n"
  },
  {
    "path": "config/0390-pg_wal.yml",
    "content": "#==============================================================#\n# 0390 pg_wal\n#==============================================================#\npg_wal_18:\n  name: pg_wal\n  desc: PostgreSQL WAL statistics since v18 with some col removed\n  query: SELECT wal_records AS records, wal_fpi AS fpi, wal_bytes AS bytes, wal_buffers_full AS buffers_full,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_wal;\n  ttl: 10\n  tags: [ cluster ]\n  min_version: 180000\n  metrics:\n    - records:      { usage: COUNTER              ,description: \"Total number of WAL records generated\" }\n    - fpi:          { usage: COUNTER              ,description: \"Total number of WAL full page images generated\" }\n    - bytes:        { usage: COUNTER              ,description: \"Total amount of WAL generated in bytes\" }\n    - buffers_full: { usage: COUNTER              ,description: \"Number of times WAL data was written to disk because WAL buffers became full\" }\n    - reset_time:   { usage: GAUGE                ,description: \"When statistics were last reset\" }\n\npg_wal_14:\n  name: pg_wal\n  desc: PostgreSQL WAL statistics since v14\n  query: SELECT wal_records AS records, wal_fpi AS fpi, wal_bytes AS bytes, wal_buffers_full AS buffers_full, wal_write AS write, wal_sync AS sync, wal_write_time AS write_time, wal_sync_time AS sync_time, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_wal;\n  ttl: 10\n  tags: [ cluster ]\n  min_version: 140000\n  max_version: 180000\n  metrics:\n    - records:      { usage: COUNTER              ,description: \"Total number of WAL records generated\" }\n    - fpi:          { usage: COUNTER              ,description: \"Total number of WAL full page images generated\" }\n    - bytes:        { usage: COUNTER              ,description: \"Total amount of WAL generated in bytes\" }\n    - buffers_full: { usage: COUNTER              ,description: \"Number of times WAL data was written to disk because WAL buffers became full\" }\n    - write:        { usage: COUNTER              ,description: \"Number of times WAL buffers were written out to disk via XLogWrite request.\" }\n    - sync:         { usage: COUNTER              ,description: \"Number of times WAL files were synced to disk via issue_xlog_fsync request\" }\n    - write_time:   { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent writing WAL buffers to disk via XLogWrite request in seconds\" }\n    - sync_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent syncing WAL files to disk via issue_xlog_fsync request, in seconds\" }\n    - reset_time:   { usage: GAUGE                ,description: \"When statistics were last reset\" }\n\n\n"
  },
  {
    "path": "config/0410-pg_activity.yml",
    "content": "#==============================================================#\n# 0410 pg_activity\n#==============================================================#\npg_activity:\n  name: pg_activity\n  desc: PostgreSQL backend activity group by database and state\n  query: |-\n    SELECT datname, state, coalesce(count, 0) AS count, coalesce(max_duration, 0) AS max_duration, coalesce(max_tx_duration, 0) AS max_tx_duration, coalesce(max_conn_duration, 0) AS max_conn_duration FROM\n        (SELECT d.datname, a.state FROM pg_database d, unnest(ARRAY ['active','idle','idle in transaction','idle in transaction (aborted)','fastpath function call','disabled']) a(state) WHERE d.datallowconn AND NOT d.datistemplate) base\n          LEFT JOIN (SELECT datname, state, count(*) AS count, max(extract(epoch from now() - state_change)) AS max_duration, max(extract(epoch from now() - xact_start))\n          AS max_tx_duration, max(extract(epoch from now() - backend_start)) AS max_conn_duration FROM pg_stat_activity WHERE pid <> pg_backend_pid() GROUP BY 1,2) data USING (datname,state);\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - state:             { usage: LABEL ,description: \"Current overall state of this backend.\" }\n    - count:             { usage: GAUGE ,description: \"Count of connection among (datname,state)\" }\n    - max_duration:      { usage: GAUGE ,description: \"Max duration since last state change among (datname, state)\" }\n    - max_tx_duration:   { usage: GAUGE ,description: \"Max transaction duration since state change among (datname, state)\" }\n    - max_conn_duration: { usage: GAUGE ,description: \"Max backend session duration since state change among (datname, state)\" }\n\n\n"
  },
  {
    "path": "config/0420-pg_wait.yml",
    "content": "#==============================================================#\n# 0420 pg_wait\n#==============================================================#\npg_wait:\n  name: pg_wait\n  desc: PostgreSQL backend client count group by wait event type since 9.6\n  query: |\n    SELECT coalesce(datname, '_system') AS datname, coalesce(wait_event_type, 'Running') AS event, count(*) AS count FROM pg_stat_activity GROUP BY 1, 2;\n  ttl: 10\n  min_version: 090600\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database, _system for global process\" }\n    - event:   { usage: LABEL ,description: \"Wait event type\" }\n    - count:   { usage: GAUGE ,description: \"Count of WaitEvent on target database\" }\n\n\n"
  },
  {
    "path": "config/0430-pg_backend.yml",
    "content": "#==============================================================#\n# 0430 pg_backend\n#==============================================================#\npg_backend:\n  name: pg_backend\n  desc: PostgreSQL backend client count group by wait event type since 10\n  query: SELECT backend_type AS \"type\", count(*) AS count FROM pg_stat_activity GROUP BY backend_type;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - type:  { usage: LABEL ,description: \"Database backend process type\" }\n    - count: { usage: GAUGE ,description: \"Database backend process count by backend_type\" }\n\n\n"
  },
  {
    "path": "config/0440-pg_xact.yml",
    "content": "#==============================================================#\n# 0440 pg_xact\n#==============================================================#\npg_xact:\n  name: pg_xact\n  desc: PostgreSQL transaction identifier metrics\n  query: WITH snap(v) AS (SELECT txid_current_snapshot()), xset(v) AS  (SELECT txid_snapshot_xip(v) FROM snap), xnum(v) AS (SELECT count(*) from xset), xmin(v) AS (SELECT txid_snapshot_xmin(v) FROM snap), xmax(v) AS (SELECT txid_snapshot_xmax(v) FROM snap) SELECT xmin.v AS xmin, xmax.v AS xmax, xnum.v AS xnum FROM xmin, xmax, xnum;\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - xmin: { usage: COUNTER ,description: \"Earliest txid that is still active\" }\n    - xmax: { usage: COUNTER ,description: \"First as-yet-unassigned txid. txid >= this are invisible.\" }\n    - xnum: { usage: GAUGE   ,description: \"Current active transaction count\" }\n\n\n"
  },
  {
    "path": "config/0450-pg_lock.yml",
    "content": "#==============================================================#\n# 0450 pg_lock\n#==============================================================#\npg_lock:\n  name: pg_lock\n  desc: PostgreSQL lock distribution by mode and database\n  query: |\n    SELECT datname, mode, coalesce(count, 0) AS count\n      FROM (SELECT d.oid AS database, d.datname, l.mode FROM pg_database d, unnest(ARRAY ['AccessShareLock','RowShareLock','RowExclusiveLock','ShareUpdateExclusiveLock', 'ShareLock','ShareRowExclusiveLock','ExclusiveLock','AccessExclusiveLock']) l(mode) WHERE d.datallowconn AND NOT d.datistemplate) base\n      LEFT JOIN (SELECT database, mode, count(*) AS count FROM pg_locks WHERE database IS NOT NULL GROUP BY 1, 2) cnt USING (database, mode);\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - mode:    { usage: LABEL ,description: \"Name of the lock mode held or desired by this process\" }\n    - count:   { usage: GAUGE ,description: \"Number of locks of corresponding mode and database\" }\n\n\n"
  },
  {
    "path": "config/0460-pg_query.yml",
    "content": "#==============================================================#\n# 0460 pg_query\n#==============================================================#\npg_query_17:\n  name: pg_query\n  desc: PostgreSQL Query metrics, require pg_stat_statements installed, 17+\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_exec_time) AS exec_time, sum(shared_blk_read_time) + sum(shared_blk_write_time) AS io_time, sum(wal_bytes) AS wal_bytes\n    ,sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n      FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 170000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - wal_bytes:    { usage: COUNTER ,description: \"Total amount of WAL bytes generated by the statement\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\npg_query_13:\n  name: pg_query\n  desc: PostgreSQL Query metrics, require pg_stat_statements installed, 13 - 16\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_exec_time) AS exec_time, sum(blk_read_time) + sum(blk_write_time) AS io_time, sum(wal_bytes) AS wal_bytes\n    ,sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n      FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 130000\n  max_version: 170000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - wal_bytes:    { usage: COUNTER ,description: \"Total amount of WAL bytes generated by the statement\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\npg_query_10:\n  name: pg_query\n  desc: PostgreSQL query statement metrics, require pg_stat_statements installed, 9.4 ~ 12\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_time) AS exec_time, sum(blk_read_time) + sum(blk_write_time) AS io_time,\n    sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n    FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 090400\n  max_version: 130000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\n\n"
  },
  {
    "path": "config/0510-pg_vacuuming.yml",
    "content": "#==============================================================#\n# 0510 pg_vacuuming\n#==============================================================#\npg_vacuuming_18:\n  name: pg_vacuuming\n  desc: PostgreSQL vacuum progress 18+\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      CASE phase WHEN 'scanning heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_scanned / heap_blks_total ELSE 0.0 END)\n        WHEN 'vacuuming heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_vacuumed / heap_blks_total ELSE 0 END) ELSE NULL END AS progress,\n      indexes_total, indexes_processed, dead_tuple_bytes, delay_time\n    FROM pg_stat_progress_vacuum;\n\n  ttl: 10\n  min_version: 180000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:           { usage: LABEL   ,description: \"database name\" }\n    - pid:               { usage: LABEL   ,description: \"process id of vacuum worker\" }\n    - relname:           { usage: LABEL   ,description: \"relation name of vacuuming table\" }\n    - progress:          { usage: GAUGE   ,description: \"vacuum progress ratio (0-1) based on heap blocks scanned/vacuumed\" }\n    - indexes_total:     { usage: GAUGE   ,description: \"total number of indexes that will be vacuumed or cleaned up\" }\n    - indexes_processed: { usage: GAUGE   ,description: \"number of indexes that have been vacuumed or cleaned up\" }\n    - dead_tuple_bytes:  { usage: GAUGE   ,description: \"total size of dead tuples collected since the beginning of vacuum in bytes\" }\n    - delay_time:        { usage: COUNTER ,scale: 1e-3 ,description: \"total time spent sleeping due to cost-based delay in seconds\" }\n\npg_vacuuming_17:\n  name: pg_vacuuming\n  desc: PostgreSQL vacuum progress 17 (with index progress tracking)\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      CASE phase WHEN 'scanning heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_scanned / heap_blks_total ELSE 0.0 END)\n        WHEN 'vacuuming heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_vacuumed / heap_blks_total ELSE 0 END) ELSE NULL END AS progress,\n      indexes_total, indexes_processed, dead_tuple_bytes\n    FROM pg_stat_progress_vacuum;\n\n  ttl: 10\n  min_version: 170000\n  max_version: 180000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"database name\" }\n    - pid:               { usage: LABEL ,description: \"process id of vacuum worker\" }\n    - relname:           { usage: LABEL ,description: \"relation name of vacuuming table\" }\n    - progress:          { usage: GAUGE ,description: \"vacuum progress ratio (0-1) based on heap blocks scanned/vacuumed\" }\n    - indexes_total:     { usage: GAUGE ,description: \"total number of indexes that will be vacuumed or cleaned up\" }\n    - indexes_processed: { usage: GAUGE ,description: \"number of indexes that have been vacuumed or cleaned up\" }\n    - dead_tuple_bytes:  { usage: GAUGE ,description: \"total size of dead tuples collected since the beginning of vacuum in bytes\" }\n\npg_vacuuming_12:\n  name: pg_vacuuming\n  desc: PostgreSQL vacuum progress 12-16\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      CASE phase WHEN 'scanning heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_scanned / heap_blks_total ELSE 0.0 END)\n        WHEN 'vacuuming heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_vacuumed / heap_blks_total ELSE 0 END) ELSE NULL END AS progress\n    FROM pg_stat_progress_vacuum;\n\n  ttl: 10\n  min_version: 120000\n  max_version: 170000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:   { usage: LABEL ,description: \"database name\" }\n    - pid:       { usage: LABEL ,description: \"process id of vacuum worker\" }\n    - relname:   { usage: LABEL ,description: \"relation name of vacuuming table\" }\n    - progress:  { usage: GAUGE ,description: \"vacuum progress ratio (0-1) based on heap blocks scanned/vacuumed\" }\n\n\n"
  },
  {
    "path": "config/0520-pg_indexing.yml",
    "content": "#==============================================================#\n# 0520 pg_indexing\n#==============================================================#\npg_indexing:\n  name: pg_indexing\n  desc: PostgreSQL index creating progress (v12+)\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      (CASE WHEN blocks_total > 0 THEN 1.0 * blocks_done / blocks_total ELSE NULL END) AS blocks,\n      (CASE WHEN tuples_total > 0 THEN 1.0 * tuples_done / tuples_total ELSE NULL END) AS tuples,\n      (CASE WHEN partitions_total > 0 THEN 1.0 * partitions_done / partitions_total ELSE NULL END) AS partitions,\n      (CASE WHEN lockers_total > 0 THEN 1.0 * lockers_done / lockers_total ELSE NULL END) AS lockers\n    FROM pg_stat_progress_create_index pspci;\n\n  ttl: 10\n  min_version: 120000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:     { usage: LABEL ,description: \"Name of the database\" }\n    - pid:         { usage: LABEL ,description: \"Process id of indexing table\" }\n    - relname:     { usage: LABEL ,description: \"Relation name of indexed table\" }\n    - blocks:      { usage: GAUGE ,description: \"Percent of blocks been proceeded\" }\n    - tuples:      { usage: GAUGE ,description: \"Percent of tuples been proceeded\" }\n    - partitions:  { usage: GAUGE ,description: \"Percent of partitions been proceeded\" }\n    - lockers:     { usage: GAUGE ,description: \"Percent of lockers been proceeded\" }\n\n\n"
  },
  {
    "path": "config/0530-pg_clustering.yml",
    "content": "#==============================================================#\n# 0530 pg_clustering\n#==============================================================#\npg_clustering:\n  name: pg_clustering\n  desc: PostgreSQL cluster or vacuum full progress (v12+)\n  query: SELECT datname, pid, relid::RegClass AS relname, param4 AS tup_scan, CASE WHEN param6 > 0 THEN 1.0 * param7 / param6 ELSE 0 END AS progress FROM pg_stat_get_progress_info('cluster') s LEFT JOIN pg_database d ON s.datid = d.oid;\n  ttl: 10\n  min_version: 120000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:     { usage: LABEL ,description: \"Name of database been clustering\" }\n    - pid:         { usage: LABEL ,description: \"Process id of indexing table\" }\n    - relname:     { usage: LABEL ,description: \"Relation name of indexed table\" }\n    - tup_scan:    { usage: GAUGE ,description: \"How much tuple been scanned\" }\n    - progress:    { usage: GAUGE ,description: \"Progress of heap been processed\" }\n\n\n"
  },
  {
    "path": "config/0540-pg_backup.yml",
    "content": "#==============================================================#\n# 0540 pg_backup\n#==============================================================#\npg_backup:\n  name: pg_backup\n  desc: PostgreSQL basebackup progress since 13\n  query: SELECT pid, param1 AS phase, CASE param2 WHEN -1::integer THEN NULL::bigint ELSE param2 END AS total_bytes, param3 AS sent_bytes FROM pg_stat_get_progress_info('BASEBACKUP');\n  ttl: 10\n  min_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - pid:           { usage: LABEL ,description: \"process id of basebackup sender\" }\n    - phase:         { usage: GAUGE ,description: \"Phase encoded in 0~5 initial, wait checkpoint, estimate, streaming, waiting archive, transfer archive\" }\n    - total_bytes:   { usage: GAUGE ,description: \"Total amount of data that will be streamed\" }\n    - sent_bytes:    { usage: GAUGE ,description: \"Amount of data streamed\" }\n\n\n"
  },
  {
    "path": "config/0610-pg_db.yml",
    "content": "#==============================================================#\n# 0610 pg_db\n#==============================================================#\npg_db_18:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v18\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total,blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,coalesce(checksum_failures, -1) AS cks_fails, checksum_last_failure AS cks_fail_time,blk_read_time,blk_write_time,\n      session_time,active_time,idle_in_transaction_time AS ixact_time,sessions,sessions_abandoned,sessions_fatal,sessions_killed,parallel_workers_to_launch,parallel_workers_launched,\n      extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n\n  ttl: 10\n  min_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - cks_fails:           { usage: COUNTER ,description: \"Number of data page checksum failures detected in this database, -1 for not enabled\" }\n    - cks_fail_time:       { usage: GAUGE   ,description: \"Time at which the last data page checksum failure was detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - session_time:        { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent by database sessions in this database, in seconds\" }\n    - active_time:         { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent executing SQL statements in this database, in seconds\" }\n    - ixact_time:          { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent idling while in a transaction in this database, in seconds\" }\n    - sessions:            { usage: COUNTER ,description: \"Total number of sessions established to this database\" }\n    - sessions_abandoned:  { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated because connection to the client was lost\" }\n    - sessions_fatal:      { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by fatal errors\" }\n    - sessions_killed:     { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by operator intervention\" }\n    - parallel_workers_to_launch: { usage: COUNTER ,description: \"Number of parallel workers planned to be launched by queries on this database\" }\n    - parallel_workers_launched:  { usage: COUNTER ,description: \"Number of parallel workers launched by queries on this database\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\npg_db_14:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v14 (with 7 new time & session metrics)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total,blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,coalesce(checksum_failures, -1) AS cks_fails, checksum_last_failure AS cks_fail_time,blk_read_time,blk_write_time,\n      session_time,active_time,idle_in_transaction_time AS ixact_time,sessions,sessions_abandoned,sessions_fatal,sessions_killed,extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n\n  ttl: 10\n  min_version: 140000\n  max_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - cks_fails:           { usage: COUNTER ,description: \"Number of data page checksum failures detected in this database, -1 for not enabled\" }\n    - cks_fail_time:       { usage: GAUGE   ,description: \"Time at which the last data page checksum failure was detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - session_time:        { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent by database sessions in this database, in seconds\" }\n    - active_time:         { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent executing SQL statements in this database, in seconds\" }\n    - ixact_time:          { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent idling while in a transaction in this database, in seconds\" }\n    - sessions:            { usage: COUNTER ,description: \"Total number of sessions established to this database\" }\n    - sessions_abandoned:  { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated because connection to the client was lost\" }\n    - sessions_fatal:      { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by fatal errors\" }\n    - sessions_killed:     { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by operator intervention\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\n\npg_db_12:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v12 v13 (with 2 new checksum metrics)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total,blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,coalesce(checksum_failures, -1) AS cks_fails, checksum_last_failure AS cks_fail_time,blk_read_time,blk_write_time,\n      extract(EPOCH FROM stats_reset) AS reset_time FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n\n  ttl: 10\n  min_version: 120000\n  max_version: 140000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - cks_fails:           { usage: COUNTER ,description: \"Number of data page checksum failures detected in this database, -1 for not enabled\" }\n    - cks_fail_time:       { usage: GAUGE   ,description: \"Time at which the last data page checksum failure was detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\npg_db_10:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v10 v11 (actually since 9.2)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total, blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,blk_read_time,blk_write_time, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n  ttl: 10\n  min_version: 090200\n  max_version: 120000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\n\n"
  },
  {
    "path": "config/0620-pg_db_confl.yml",
    "content": "#==============================================================#\n# 0620 pg_db_confl\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_database_conflicts.html\n\npg_db_confl_16:\n  name: pg_db_confl\n  desc: PostgreSQL database conflicts metrics for PG16+\n  query: SELECT * FROM pg_stat_database_conflicts;\n  ttl: 10\n  min_version: 160000\n  tags: [ cluster, replica ]\n  metrics:\n    - datid:                { usage: DISCARD }\n    - datname:              { usage: LABEL   ,description: \"Name of this database\" }\n    - confl_tablespace:     { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to dropped tablespaces\" }\n    - confl_lock:           { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to lock timeouts\" }\n    - confl_snapshot:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to old snapshots\" }\n    - confl_bufferpin:      { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to pinned buffers\" }\n    - confl_deadlock:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to deadlocks\" }\n    - confl_active_logicalslot: { usage: COUNTER ,description: \"Number of uses of logical slots in this database that have been canceled due to old snapshots or too low a wal_level on the primary\" }\n\npg_db_confl_15:\n  name: pg_db_confl\n  desc: PostgreSQL database conflicts metrics for pg 9.1 - 15\n  query: SELECT * FROM pg_stat_database_conflicts;\n  ttl: 10\n  min_version: 90100\n  max_version: 160000\n  tags: [ cluster, replica ]\n  metrics:\n    - datid:                { usage: DISCARD }\n    - datname:              { usage: LABEL   ,description: \"Name of this database\" }\n    - confl_tablespace:     { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to dropped tablespaces\" }\n    - confl_lock:           { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to lock timeouts\" }\n    - confl_snapshot:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to old snapshots\" }\n    - confl_bufferpin:      { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to pinned buffers\" }\n    - confl_deadlock:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to deadlocks\" }\n\n\n"
  },
  {
    "path": "config/0640-pg_pubrel.yml",
    "content": "#==============================================================#\n# 0640 pg_pubrel\n#==============================================================#\npg_pubrel:\n  name: pg_pubrel\n  desc: PostgreSQL publication and relation count\n  query: SELECT CURRENT_CATALOG AS datname, pubname, count(*) AS count FROM pg_publication p, LATERAL pg_get_publication_tables(pubname) GROUP BY pubname;\n  ttl: 10\n  min_version: 100000\n  metrics:\n    - datname:              { usage: LABEL  ,description: \"Name of the database which publication belonged\" }\n    - pubname:              { usage: LABEL  ,description: \"Name of the publication\" }\n    - count:                { usage: GAUGE  ,description: \"Count of relation in the publication\" }\n\n\n"
  },
  {
    "path": "config/0650-pg_subrel.yml",
    "content": "#==============================================================#\n# 0650 pg_subrel\n#==============================================================#\npg_subrel:\n  name: pg_subrel\n  desc: PostgreSQL subscripted relation group by state\n  query: SELECT CURRENT_CATALOG AS datname, subname, srsubstate::TEXT AS state, count(*) AS count FROM pg_subscription_rel sr LEFT JOIN pg_stat_subscription  ss ON sr.srsubid = ss.subid GROUP BY 2, 3;\n  ttl: 10\n  min_version: 100000\n  metrics:\n    - datname:              { usage: LABEL  ,description: \"Name of the database which publication belonged\" }\n    - subname:              { usage: LABEL  ,description: \"Name of the subscription\" }\n    - state:                { usage: LABEL  ,description: \"State of table in subscription, i=initialize, d=data copy, s=sync, r=ready\" }\n    - count:                { usage: GAUGE  ,description: \"Count of relation in this subscription and corresponding state\" }\n\n\n"
  },
  {
    "path": "config/0700-pg_table.yml",
    "content": "#==============================================================#\n# 0700 pg_table\n#==============================================================#\npg_table_18:\n  name: pg_table\n  desc: PostgreSQL table metrics v18+\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_tup_newpage_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.n_ins_since_vacuum,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,psut.last_seq_scan,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psut.total_vacuum_time AS vacuum_time,psut.total_autovacuum_time AS autovacuum_time,psut.total_analyze_time AS analyze_time,psut.total_autoanalyze_time AS autoanalyze_time,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 180000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_tup_newpage_upd:   { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated where the successor version goes onto a new heap page\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - n_ins_since_vacuum:  { usage: GAUGE                 ,description: \"Estimated number of rows inserted since this table was last vacuumed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - last_seq_scan:       { usage: DISCARD               ,description: \"The timestamp of the last seq scan on this table\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - vacuum_time:        { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been manually vacuumed, in seconds\" }\n    - autovacuum_time:    { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been vacuumed by the autovacuum daemon, in seconds\" }\n    - analyze_time:       { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been manually analyzed, in seconds\" }\n    - autoanalyze_time:   { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been analyzed by the autovacuum daemon, in seconds\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_16:\n  name: pg_table\n  desc: PostgreSQL table metrics 16-17\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_tup_newpage_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.n_ins_since_vacuum,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,psut.last_seq_scan,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 160000\n  max_version: 180000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_tup_newpage_upd:   { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated where the successor version goes onto a new heap page\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - n_ins_since_vacuum:  { usage: GAUGE                 ,description: \"Estimated number of rows inserted since this table was last vacuumed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - last_seq_scan:       { usage: DISCARD               ,description: \"The timestamp of the last seq scan on this table\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_13:\n  name: pg_table\n  desc: PostgreSQL table metrics 13-15 (with n_ins_since_vacuum)\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.n_ins_since_vacuum,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 130000\n  max_version: 160000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - n_ins_since_vacuum:  { usage: GAUGE                 ,description: \"Estimated number of rows inserted since this table was last vacuumed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_10:\n  name: pg_table\n  desc: PostgreSQL table metrics 9.4-12\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 090400\n  max_version: 130000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\n\n"
  },
  {
    "path": "config/0710-pg_index.yml",
    "content": "#==============================================================#\n# 0710 pg_index\n#==============================================================#\npg_index:\n  name: pg_index\n  desc: PostgreSQL index metrics\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, schemaname || '.' || indexrelname AS idxname, schemaname || '.' || relname AS relname ,indexrelid AS relid,\n        relpages, reltuples, idx_scan, idx_tup_read, idx_tup_fetch, idx_blks_read, idx_blks_hit\n    FROM pg_stat_user_indexes psui, LATERAL (SELECT idx_blks_read, idx_blks_hit FROM pg_statio_user_indexes psio WHERE psio.indexrelid = psui.indexrelid LIMIT 1) p2,\n        LATERAL (SELECT relpages,reltuples FROM pg_class c WHERE c.oid = psui.indexrelid LIMIT 1) p3\n    WHERE schemaname !~ '^pg_' AND schemaname !~ '^_' AND schemaname !~ '^timescaledb' AND schemaname !~ '^citus' AND schemaname !~ '^columnar' AND schemaname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor')\n    ORDER BY idx_tup_read DESC LIMIT 512;\n\n  ttl: 10\n  timeout: 1\n  min_version: 090400\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - idxname:             { usage: LABEL    ,description: \"Name of this index (full-qualified schema name)\" }\n    - relname:             { usage: LABEL    ,description: \"Name of the table for this index (full-qualified schema name)\" }\n    - relid:               { usage: LABEL    ,description: \"Relation oid of this index\" }\n    - relpages:            { usage: GAUGE    ,description: \"Size of the on-disk representation of this index in pages\" }\n    - reltuples:           { usage: GAUGE    ,description: \"Estimate relation tuples\" }\n    - idx_scan:            { usage: COUNTER  ,description: \"Number of index scans initiated on this index\" }\n    - idx_tup_read:        { usage: COUNTER  ,description: \"Number of index entries returned by scans on this index\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,description: \"Number of live table rows fetched by simple index scans using this index\" }\n    - idx_blks_read:       { usage: COUNTER  ,description: \"Number of disk blocks read from this index\" }\n    - idx_blks_hit:        { usage: COUNTER  ,description: \"Number of buffer hits in this index\" }\n\n\n"
  },
  {
    "path": "config/0720-pg_func.yml",
    "content": "#==============================================================#\n# 0720 pg_func\n#==============================================================#\npg_func:\n  desc: PostgreSQL function metrics\n  query: SELECT CURRENT_CATALOG AS datname, schemaname || '.' || funcname AS funcname, sum(calls) AS calls, sum(total_time) AS total_time, sum(self_time) AS self_time FROM pg_stat_user_functions GROUP BY 2 ORDER BY 4 DESC LIMIT 128;\n  ttl: 10\n  min_version: 090400\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Name of belonged database\" }\n    - funcname:            { usage: LABEL    ,description: \"Name of this function, may have multiple override\" }\n    - calls:               { usage: COUNTER  ,description: \"Number of times this function has been called\" }\n    - total_time:          { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function and all other functions called by it, in seconds\" }\n    - self_time:           { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function itself, not including other functions called by it, in seconds\" }\n\n\n"
  },
  {
    "path": "config/0730-pg_seq.yml",
    "content": "#==============================================================#\n# 0730 pg_seq\n#==============================================================#\npg_seq:\n  desc: PostgreSQL sequence metrics\n  query: SELECT CURRENT_CATALOG AS datname, schemaname || '.' || sequencename AS seqname, last_value, blks_read, blks_hit FROM pg_sequences s, LATERAL (SELECT relid, blks_read, blks_hit FROM pg_statio_all_sequences sio WHERE s.schemaname = sio.schemaname AND s.sequencename = sio.relname LIMIT 1) d LIMIT 128;\n  ttl: 10\n  min_version: 100000\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this sequence\" }\n    - seqname:             { usage: LABEL    ,description: \"Fully schema qualified sequence name\" }\n    - last_value:          { usage: COUNTER  ,description: \"The last sequence value written to disk\" }\n    - blks_read:           { usage: COUNTER  ,description: \"Number of disk blocks read from this sequence\" }\n    - blks_hit:            { usage: COUNTER  ,description: \"Number of buffer hits in this sequence\" }\n\n\n"
  },
  {
    "path": "config/0740-pg_relkind.yml",
    "content": "#==============================================================#\n# 0740 pg_relkind\n#==============================================================#\npg_relkind:\n  name: pg_relkind\n  desc: Postgres relation count by kind (category, r,i,m,t,...)\n  query: SELECT CURRENT_CATALOG AS datname, relkind, count(*) AS count FROM pg_class GROUP BY relkind;\n  ttl: 60\n  timeout: 1\n  min_version: 090400\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Name of database\" }\n    - relkind:             { usage: LABEL    ,description: \"Kind of this relation, could be r,i,S,t,v,m,c,f,p,I\" }\n    - count:               { usage: GAUGE    ,description: \"Number of relations of corresponding relkind\" }\n\n\n"
  },
  {
    "path": "config/0750-pg_defpart.yml",
    "content": "#==============================================================#\n# 0750 pg_defpart\n#==============================================================#\npg_defpart:\n  name: pg_defpart\n  desc: PostgreSQL default partition tuples\n  query: SELECT CURRENT_CATALOG AS datname, relnamespace::RegNamespace || '.' || relname AS relname, reltuples AS tuples FROM pg_class WHERE relpartbound IS NOT NULL AND pg_catalog.pg_get_expr(relpartbound, oid) = 'DEFAULT' ORDER BY reltuples DESC LIMIT 64;\n  ttl: 60\n  timeout: 1\n  min_version: 110000\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this default partition\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified default partition relation name\" }\n    - tuples:              { usage: GAUGE    ,description: \"Number of tuples in this default partition\" }\n\n\n"
  },
  {
    "path": "config/0810-pg_table_size.yml",
    "content": "#==============================================================#\n# 0810 pg_table_size\n#==============================================================#\npg_table_size:\n  desc: PostgreSQL table size metrics, quite slow\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || rel.relname AS relname,\n       pg_total_relation_size(rel.oid)       AS bytes,\n       pg_relation_size(rel.oid)             AS relsize,\n       pg_indexes_size(rel.oid)              AS indexsize,\n       pg_total_relation_size(reltoastrelid) AS toastsize\n    FROM pg_namespace nsp JOIN pg_class rel ON nsp.oid = rel.relnamespace\n    WHERE nspname <> ALL(ARRAY['pg_catalog', 'information_schema']) AND rel.relkind = 'r'\n    ORDER BY 3 DESC NULLS LAST LIMIT 256;\n\n  ttl: 300\n  timeout: 2\n  min_version: 100000\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified table name\" }\n    - bytes:               { usage: GAUGE    ,default: 0  ,description: \"Total bytes of this table (including toast, index, toast index)\" }\n    - relsize:             { usage: GAUGE    ,default: 0  ,description: \"Bytes of this table itself (main, vm, fsm)\" }\n    - indexsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of all related indexes of this table\" }\n    - toastsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of toast tables of this table\" }\n\n\n"
  },
  {
    "path": "config/0820-pg_table_bloat.yml",
    "content": "#==============================================================#\n# 0820 pg_table_bloat\n#==============================================================#\n# pg_table_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_table_bloat:\n  name: pg_table_bloat\n  desc: PostgreSQL table bloat metrics, require auxiliary view pg_table_bloat to work\n  query: SELECT datname, nspname || '.' || relname AS relname, size, ratio FROM pg_table_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 090400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified name of this table\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this table\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this table from 0 to 1\" }\n\n\n"
  },
  {
    "path": "config/0830-pg_index_bloat.yml",
    "content": "#==============================================================#\n# 0830 pg_index_bloat\n#==============================================================#\n# pg_index_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_index_bloat:\n  name: pg_index_bloat\n  desc: PostgreSQL index bloat metrics (btree only), require pg_index_bloat\n  query: SELECT datname, nspname || '.' || relname AS relname, size, ratio FROM pg_index_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 090400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified index name\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this index\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this index, 0~1\" }\n\n\n"
  },
  {
    "path": "config/0910-pgbouncer_list.yml",
    "content": "#==============================================================#\n# 0910 pgbouncer_list\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-lists\npgbouncer_list:\n  name: pgbouncer_list\n  desc: Pgbouncer entry list\n  query: SHOW LISTS;\n  ttl: 10\n  min_version: 10800\n  fatal: true\n  tags: [ pgbouncer ]\n  metrics:\n    - list:                { usage: LABEL                 ,description: \"Pgbouncer internal list name\" }\n    - items:               { usage: GAUGE                 ,description: \"Number of corresponding pgbouncer object\" }\n\n\n"
  },
  {
    "path": "config/0920-pgbouncer_database.yml",
    "content": "#==============================================================#\n# 0920 pgbouncer_database\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-databases\npgbouncer_database_124:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (since 1.24)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                       { usage: LABEL  ,rename: datname       ,description: \"Name of configured database entry\" }\n    - host:                       { usage: LABEL                         ,description: \"Host that pgbouncer will connects to\" }\n    - port:                       { usage: LABEL                         ,description: \"Port that pgbouncer will connects to\" }\n    - database:                   { usage: LABEL  ,rename: real_datname  ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:                 { usage: DISCARD }\n    - pool_size:                  { usage: GAUGE                         ,description: \"Maximum number of server connections\" }\n    - min_pool_size:              { usage: GAUGE                         ,description: \"Minimum number of server connections\" }\n    - reserve_pool_size:          { usage: GAUGE  ,rename: reserve_pool  ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:            { usage: GAUGE                         ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:                  { usage: DISCARD }\n    - load_balance_hosts:         { usage: DISCARD }\n    - max_connections:            { usage: GAUGE                         ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections:        { usage: GAUGE                         ,description: \"Current number of connections for this database\" }\n    - max_client_connections:     { usage: GAUGE                         ,description: \"Maximum number of allowed client connections for this pgbouncer instance\" }\n    - current_client_connections: { usage: GAUGE                         ,description: \"Current number of client connections for this database\" }\n    - paused:                     { usage: GAUGE                         ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:                   { usage: GAUGE                         ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_123:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats 1.23\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:     { usage: GAUGE                       ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_116:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.16-1.22)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 11600\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_108:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.08-1.15)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\n\n"
  },
  {
    "path": "config/0930-pgbouncer_stat.yml",
    "content": "#==============================================================#\n# 0930 pgbouncer_stat\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-stats\npgbouncer_stat_124:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (since 1.24)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - total_client_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created by clients\" }\n    - total_server_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created on a server.\" }\n    - total_bind_count:              { usage: COUNTER                  ,description: \"Total number of prepared statements readied for execution by clients and forwarded to postgres\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n    - avg_client_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created by clients\" }\n    - avg_server_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created on a server.\" }\n    - avg_bind_count:                { usage: GAUGE                    ,description: \"Average number of prepared statements readied for execution by clients and forwarded to postgres\" }\n\npgbouncer_stat_123:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.23)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\npgbouncer_stat_108:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.08 - 1.22)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 10800\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\n\n"
  },
  {
    "path": "config/0940-pgbouncer_pool.yml",
    "content": "#==============================================================#\n# 0940 pgbouncer_pool\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-pools\npgbouncer_pool_124:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.24+)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n    - load_balance_hosts:    { usage: LABEL,                                 description: \"The load_balance_hosts in use\" }\n\npgbouncer_pool_118:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.18-1.23)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11800\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n\npgbouncer_pool_116:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.16-1.17)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11600\n  max_version: 11800\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_cancel_req:         { usage: GAUGE, rename: cancel_clients,   description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\npgbouncer_pool_108:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.08-1.15)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\n\n"
  },
  {
    "path": "config/1000-pg_wait_event.yml",
    "content": "#==============================================================#\n# 1000 pg_wait_event\n#==============================================================#\npg_wait_event:\n  name: pg_wait_event\n  desc: PostgreSQL wait event sampling based on pg_wait_sampling extension\n  query: SELECT coalesce(event_type, 'Running') AS etype, coalesce(event, 'Running') AS event, sum(count) AS count FROM pg_wait_sampling_profile GROUP BY 1,2;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster, \"extension:pg_wait_sampling\" ]\n  metrics:\n    - etype: { usage: \"LABEL\"   ,description: \"wait event type\" }\n    - event: { usage: \"LABEL\"   ,description: \"wait event name\" }\n    - count: { usage: \"COUNTER\" ,description: \"Total count of wait events sampled\" }\n\npg_wait_event_1s:\n  name: pg_wait_event_1s\n  desc: PostgreSQL wait event sampling based on pg_wait_sampling extension\n  query: SELECT coalesce(event_type, 'Running') AS etype, coalesce(event, 'Running') AS event, count(*) FROM pg_wait_sampling_history WHERE ts BETWEEN now() - '1s'::INTERVAL AND now() GROUP BY 1,2;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster, \"extension:pg_wait_sampling\" ]\n  metrics:\n    - etype: { usage: \"LABEL\"   ,description: \"wait event type\" }\n    - event: { usage: \"LABEL\"   ,description: \"wait event name\" }\n    - count: { usage: \"GAUGE\"   ,description: \"Number of wait events in last second\" }\n\n\n"
  },
  {
    "path": "config/1800-pg_tsdb_hypertable.yml",
    "content": "#==============================================================#\n# 1800 pg_tsdb_hypertable\n#==============================================================#\n# this collector reqires timescaledb extension to be installed\npg_tsdb_hypertable:\n  name: pg_tsdb_hypertable\n  desc: TimescaleDB hypertable overview\n  query: |-\n    SELECT \n      current_database() AS datname,\n      format('%I.%I', hypertable_schema, hypertable_name) AS relname,\n      num_dimensions AS dimensions, num_chunks AS chunks,\n      compression_enabled::BOOLEAN::int AS compressed,\n      hypertable_size(format('\"%I\".\"%I\"', hypertable_schema, hypertable_name)::RegClass) AS bytes\n    FROM timescaledb_information.hypertables;\n\n  ttl: 60\n  timeout: 2\n  min_version: 100000\n  skip: true\n  tags: [ \"extension:timescaledb\", \"schema:timescaledb_information\" ]\n  metrics:\n    - datname:         { usage: LABEL ,description: \"database name\" }\n    - relname:         { usage: LABEL ,description: \"Hypertable relation name\" }\n    - dimensions:      { usage: GAUGE ,description: \"Number of partitioning dimensions\" }\n    - chunks:          { usage: GAUGE ,description: \"Total chunks of this hypertable\" }\n    - compressed:      { usage: GAUGE ,description: \"1 if compression enabled\" }\n    - bytes:           { usage: GAUGE ,description: \"Total size of hypertable in bytes\" }\n\n\n"
  },
  {
    "path": "config/1900-pg_citus.yml",
    "content": "#==============================================================#\n# 1900 pg_citus_node\n#==============================================================#\n# https://docs.citusdata.com/en/latest/develop/api_metadata.html#worker-node-table\npg_citus_node:\n  name: pg_citus_node\n  desc: Citus worker coordinator node inventory\n  query: |-\n    SELECT\n      CONCAT(nodename, ':', nodeport) AS node,\n      current_database() AS datname,\n      nodeid AS id,\n      groupid AS group,\n      hasmetadata::BOOLEAN::INT AS has_meta,\n      isactive::BOOLEAN::INT AS is_active,\n      metadatasynced::BOOLEAN::INT AS meta_synced,\n      shouldhaveshards::BOOLEAN::INT AS have_shards\n    FROM pg_dist_node;\n  ttl: 60\n  min_version: 100000\n  tags: [ \"extension:citus\" ]\n  metrics:\n    - node:             { usage: LABEL ,description: \"nodename:port of the PostgreSQL instance\" }\n    - datname:          { usage: LABEL ,description: \"database name\" }\n    - id:               { usage: GAUGE ,description: \"auto‑generated node identifier\" }\n    - group:            { usage: GAUGE ,description: \"replication group id (primary + secondaries)\" }\n    - has_meta:         { usage: GAUGE ,description: \"1 = internal use flag set\" }\n    - is_active:        { usage: GAUGE ,description: \"1 = node currently accepts shards\" }\n    - meta_synced:      { usage: GAUGE ,description: \"1 = metadata fully synced to node\" }\n    - have_shards:      { usage: GAUGE ,description: \"1 = rebalancer may place shards here\" }\n\n\n"
  },
  {
    "path": "config/2000-pg_heartbeat.yml",
    "content": "#==============================================================#\n# 2000 heartbeat\n#==============================================================#\n# this is a example of application monitoring and predicate queries\npg_heartbeat:\n  name: pg_heartbeat\n  desc: monitoring heartbeat in monitor.heartbeat table\n  predicate_queries:\n    - name: if heartbeat table exists\n      predicate_query: |\n        SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'monitor' AND table_name = 'heartbeat');\n  query: |-\n    SELECT id AS cluster_name, extract(EPOCH FROM ts) AS ts, lsn, txid FROM monitor.heartbeat;\n\n  ttl: 10\n  min_version: 090100\n  tags: [ \"dbname:postgres\", \"schema:monitor\" ]\n  skip: true\n  metrics:\n    - cluster_name:     { usage: LABEL   ,description: \"cluster_name param of this database cluster\" }\n    - ts:               { usage: GAUGE   ,description: \"unix timestamp of the heartbeat\" }\n    - lsn:              { usage: COUNTER ,description: \"lsn of the heartbeat\" }\n    - txid:             { usage: GAUGE   ,description: \"txid of the heartbeat\" }\n\n\n"
  },
  {
    "path": "docker/.dockerignore",
    "content": "*\n!go.mod\n!go.sum\n!main.go\n!exporter\n!pg_exporter.yml\n"
  },
  {
    "path": "docker/README.md",
    "content": "# Docker Build Scripts\n\nThis directory contains scripts for building Docker images for pg_exporter.\n\n## Scripts\n\n### `build.sh` - Local Development Build\n\nBuilds a single-architecture Docker image for local development and testing.\n\n```bash\n# Build for current architecture\n./docker/build.sh\n\n# Build for specific architecture\nARCH=arm64 ./docker/build.sh\n\n# Use custom repository\nDOCKER_REPO=myrepo/pg_exporter ./docker/build.sh\n```\n\n**Features:**\n- Detects current architecture automatically\n- Builds only for the current platform\n- Creates local tags: `<repo>:dev`, `<repo>:latest-<arch>`, `<repo>:<version>-<arch>`\n- Does not push to registry\n- Automatically builds missing Linux binaries if needed\n\n### `release.sh` - Production Multi-Arch Release\n\nBuilds and pushes multi-architecture Docker images with manifest list support.\n\n```bash\n# Build and push multi-arch images\n./docker/release.sh\n\n# Build locally without pushing (for testing)\nPUSH=false ./docker/release.sh\n\n# Custom repository\nDOCKER_REPO=pgsty/pg_exporter ./docker/release.sh\n\n# Custom platforms\nPLATFORMS=linux/amd64,linux/arm64,linux/arm/v7 ./docker/release.sh\n```\n\n**Features:**\n- Builds for multiple architectures (amd64, arm64 by default)\n- Creates the manifest list for automatic architecture selection\n- Pushes to Docker registry\n- Creates tags: `<repo>:<version>`, `<repo>:latest`\n- Requires pre-built Linux binaries (`make release-linux`)\n\n## How Multi-Arch Works\n\nThe `release.sh` script uses Docker buildx to create a **manifest list** (also called \"fat manifest\"). This allows users to pull images without specifying architecture:\n\n```bash\n# Users can simply run:\ndocker pull pgsty/pg_exporter:latest\n\n# Docker automatically selects the right architecture:\n# - On AMD64 systems: pulls linux/amd64 image\n# - On ARM64 systems: pulls linux/arm64 image\n```\n\n## Prerequisites\n\n### For Local Build (`build.sh`)\n- Docker\n- Make (for building binaries if needed)\n\n### For Production Release (`release.sh`)\n- Docker with buildx support\n- Docker registry authentication (for pushing)\n- Pre-built Linux binaries: `make release-linux`\n\n## Environment Variables\n\n| Variable      | Default                   | Description                              |\n|---------------|---------------------------|------------------------------------------|\n| `VERSION`     | From Makefile             | Image version tag                        |\n| `DOCKER_REPO` | `pgsty/pg_exporter`       | Docker repository                        |\n| `ARCH`        | Auto-detected             | Target architecture (build.sh only)      |\n| `PLATFORMS`   | `linux/amd64,linux/arm64` | Target platforms (release.sh only)       |\n| `PUSH`        | `true`                    | Whether to push images (release.sh only) |\n\n## Examples\n\n```bash\n# Local development\n./docker/build.sh\ndocker run --rm pgsty/pg_exporter:dev --version\n\n# Production release\nmake release-linux  # Build binaries first\n./docker/release.sh\n\n# Test locally without pushing\nPUSH=false ./docker/release.sh\n\n# Custom repository and platforms\nDOCKER_REPO=mycompany/pg_exporter \\\nPLATFORMS=linux/amd64,linux/arm64,linux/arm/v7 \\\n./docker/release.sh\n```"
  },
  {
    "path": "docker/build.sh",
    "content": "#!/bin/bash\n#==============================================================#\n# File      :   docker/build.sh\n# Desc      :   Build single-arch Docker image locally with Go\n# Mtime     :   2025-07-17\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\n\nset -euo pipefail\n\n# Get current script directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(dirname \"${SCRIPT_DIR}\")\"\n\ncd \"${PROJECT_ROOT}\"\n\n# Get version from Makefile or environment\nVERSION=${VERSION:-$(grep '^VERSION' Makefile | cut -d'=' -f2 | tr -d ' ?')}\nDOCKER_REPO=${DOCKER_REPO:-vonng/pg_exporter}\n\necho \"Building Docker image for pg_exporter ${VERSION} - LOCAL BUILD (Go source)\"\n\n# Create Dockerfile for local Go build\ncat > \"${SCRIPT_DIR}/Dockerfile.local\" << 'EOF'\n# syntax=docker/dockerfile:1\nFROM golang:1.26.2-alpine AS builder-env\n\nARG GOPROXY=https://proxy.golang.org,direct\nARG GOSUMDB=sum.golang.org\nENV GOPROXY=${GOPROXY}\nENV GOSUMDB=${GOSUMDB}\n\nWORKDIR /build\n\n# Copy dependency files and download deps\nCOPY go.mod go.sum ./\nRUN \\\n  --mount=type=cache,target=/go/pkg/mod \\\n  --mount=type=cache,target=/root/.cache/go-build \\\n  CGO_ENABLED=0 GOOS=linux go mod download\n\n# Copy source code\nCOPY . /build\n\n# Build static binary\nRUN \\\n  --mount=type=cache,target=/go/pkg/mod \\\n  --mount=type=cache,target=/root/.cache/go-build \\\n  CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags \"-static\"' -o /pg_exporter .\n\nFROM scratch\n\nLABEL org.opencontainers.image.authors=\"Ruohang Feng <rh@vonng.com>\" \\\n      org.opencontainers.image.url=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.source=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.licenses=\"Apache-2.0\" \\\n      org.opencontainers.image.title=\"pg_exporter\" \\\n      org.opencontainers.image.description=\"PostgreSQL/Pgbouncer metrics exporter for Prometheus\"\n\nWORKDIR /bin\nCOPY --from=builder-env /pg_exporter /bin/pg_exporter\nCOPY pg_exporter.yml /etc/pg_exporter.yml\n\nEXPOSE 9630/tcp\nENTRYPOINT [\"/bin/pg_exporter\"]\nEOF\n\necho \"Building Docker image with Go source...\"\n\n# Build image using Go source (local only, no push)\ndocker build \\\n    -f \"${SCRIPT_DIR}/Dockerfile.local\" \\\n    --build-arg \"GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}\" \\\n    --build-arg \"GOSUMDB=${GOSUMDB:-sum.golang.org}\" \\\n    -t \"${DOCKER_REPO}:${VERSION}-dev\" \\\n    -t \"${DOCKER_REPO}:dev\" \\\n    \"${PROJECT_ROOT}\"\n\necho \"Docker image built successfully:\"\necho \"  ${DOCKER_REPO}:${VERSION}-dev\"\necho \"  ${DOCKER_REPO}:dev\"\necho \"\"\necho \"To test the image:\"\necho \"  docker run --rm ${DOCKER_REPO}:dev --version\"\n\n# Clean up\nrm -f \"${SCRIPT_DIR}/Dockerfile.local\"\n"
  },
  {
    "path": "docker/release.sh",
    "content": "#!/bin/bash\n#==============================================================#\n# File      :   docker/release.sh\n# Desc      :   Build and release multi-arch Docker images\n# Mtime     :   2025-07-17\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\n\nset -euo pipefail\n\n# Get current script directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(dirname \"${SCRIPT_DIR}\")\"\n\ncd \"${PROJECT_ROOT}\"\n\n# Get version from Makefile or environment\nVERSION=${VERSION:-$(grep '^VERSION' Makefile | cut -d'=' -f2 | tr -d ' ?')}\nDOCKER_REPO=${DOCKER_REPO:-pgsty/pg_exporter}\nPLATFORMS=${PLATFORMS:-linux/amd64,linux/arm64}\nPUSH=${PUSH:-true}\n\necho \"Building and releasing multi-arch Docker images for pg_exporter ${VERSION}\"\necho \"Platforms: ${PLATFORMS}\"\necho \"Repository: ${DOCKER_REPO}\"\n\n# Check if both arch binaries exist\necho \"Checking if release binaries exist...\"\nif [[ ! -d \"dist/${VERSION}\" ]]; then\n    echo \"Error: dist/${VERSION} directory not found. Building Linux binaries first...\"\n    make release-linux\nfi\n\nAMD64_TAR=\"dist/${VERSION}/pg_exporter-${VERSION}.linux-amd64.tar.gz\"\nARM64_TAR=\"dist/${VERSION}/pg_exporter-${VERSION}.linux-arm64.tar.gz\"\n\nif [[ ! -f \"${AMD64_TAR}\" ]] || [[ ! -f \"${ARM64_TAR}\" ]]; then\n    echo \"Error: Required binaries not found. Building them now...\"\n    make release-linux\n    if [[ ! -f \"${AMD64_TAR}\" ]] || [[ ! -f \"${ARM64_TAR}\" ]]; then\n        echo \"Error: Failed to build required binaries\"\n        exit 1\n    fi\nfi\n\n# Create temporary build contexts for each architecture\nBUILD_DIR=$(mktemp -d)\ntrap \"rm -rf ${BUILD_DIR}\" EXIT\n\necho \"Created temporary build directory: ${BUILD_DIR}\"\n\n# Extract binaries for both architectures\necho \"Extracting binaries...\"\n\nmkdir -p \"${BUILD_DIR}/amd64\" \"${BUILD_DIR}/arm64\"\n\ntar -xzf \"${AMD64_TAR}\" -C \"${BUILD_DIR}/amd64\" --strip-components=1\ntar -xzf \"${ARM64_TAR}\" -C \"${BUILD_DIR}/arm64\" --strip-components=1\n\n# Create multi-arch Dockerfile that works with buildx\ncat > \"${BUILD_DIR}/Dockerfile\" << 'EOF'\nFROM scratch\n\nLABEL org.opencontainers.image.authors=\"Ruohang Feng <rh@vonng.com>\" \\\n      org.opencontainers.image.url=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.source=\"https://github.com/pgsty/pg_exporter\" \\\n      org.opencontainers.image.licenses=\"Apache-2.0\" \\\n      org.opencontainers.image.title=\"pg_exporter\" \\\n      org.opencontainers.image.description=\"PostgreSQL/Pgbouncer metrics exporter for Prometheus\"\n\nWORKDIR /bin\nCOPY pg_exporter /bin/pg_exporter\nCOPY pg_exporter.yml /etc/pg_exporter.yml\nCOPY LICENSE /LICENSE\n\nEXPOSE 9630/tcp\nENTRYPOINT [\"/bin/pg_exporter\"]\nEOF\n\n# Copy Dockerfile to both arch directories\ncp \"${BUILD_DIR}/Dockerfile\" \"${BUILD_DIR}/amd64/Dockerfile\"\ncp \"${BUILD_DIR}/Dockerfile\" \"${BUILD_DIR}/arm64/Dockerfile\"\n\necho \"Setting up Docker buildx...\"\n\n# Create or use existing buildx builder\nBUILDER_NAME=\"pg_exporter_builder\"\nif ! docker buildx ls | grep -q \"${BUILDER_NAME}\"; then\n    echo \"Creating new buildx builder: ${BUILDER_NAME}\"\n    docker buildx create --name \"${BUILDER_NAME}\" --use --bootstrap\nelse\n    echo \"Using existing buildx builder: ${BUILDER_NAME}\"\n    docker buildx use \"${BUILDER_NAME}\"\nfi\n\nif [[ \"${PUSH}\" == \"true\" ]]; then\n    echo \"Building and pushing multi-arch images...\"\n    echo \"This will create a manifest list that automatically selects the right architecture.\"\n    \n    # Build and push multi-arch images with manifest list\n    # This creates the \"fat manifest\" that allows automatic architecture selection\n    docker buildx build \\\n        --platform \"${PLATFORMS}\" \\\n        --file \"${BUILD_DIR}/amd64/Dockerfile\" \\\n        --tag \"${DOCKER_REPO}:${VERSION}\" \\\n        --tag \"${DOCKER_REPO}:latest\" \\\n        --push \\\n        \"${BUILD_DIR}/amd64\"\nelse\n    echo \"Building multi-arch images locally (no push)...\"\n    echo \"This will create local images for testing.\"\n    \n    # Build multi-arch images locally without pushing\n    docker buildx build \\\n        --platform \"${PLATFORMS}\" \\\n        --file \"${BUILD_DIR}/amd64/Dockerfile\" \\\n        --tag \"${DOCKER_REPO}:${VERSION}\" \\\n        --tag \"${DOCKER_REPO}:latest\" \\\n        --load \\\n        \"${BUILD_DIR}/amd64\"\nfi\n\necho \"\"\nif [[ \"${PUSH}\" == \"true\" ]]; then\n    echo \"✅ Multi-arch Docker images released successfully!\"\n    echo \"\"\n    echo \"Images pushed:\"\n    echo \"  ${DOCKER_REPO}:${VERSION}\"\n    echo \"  ${DOCKER_REPO}:latest\"\nelse\n    echo \"✅ Multi-arch Docker images built locally!\"\n    echo \"\"\n    echo \"Images created:\"\n    echo \"  ${DOCKER_REPO}:${VERSION}\"\n    echo \"  ${DOCKER_REPO}:latest\"\nfi\necho \"\"\necho \"These images support the following architectures:\"\necho \"  - linux/amd64\"\necho \"  - linux/arm64\"\necho \"\"\nif [[ \"${PUSH}\" == \"true\" ]]; then\n    echo \"Users can now pull without specifying architecture:\"\n    echo \"  docker pull ${DOCKER_REPO}:${VERSION}\"\n    echo \"  docker pull ${DOCKER_REPO}:latest\"\n    echo \"\"\n    echo \"Docker will automatically select the correct architecture for their platform.\"\n    \n    # Verify the manifest\n    echo \"\"\n    echo \"Verifying manifest list...\"\n    docker buildx imagetools inspect \"${DOCKER_REPO}:${VERSION}\" || echo \"Note: manifest inspection requires authentication\"\nelse\n    echo \"To test the local images:\"\n    echo \"  docker run --rm ${DOCKER_REPO}:${VERSION} --version\"\n    echo \"\"\n    echo \"To push later:\"\n    echo \"  docker push ${DOCKER_REPO}:${VERSION}\"\n    echo \"  docker push ${DOCKER_REPO}:latest\"\nfi"
  },
  {
    "path": "exporter/arg.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/alecthomas/kingpin/v2\"\n\t\"github.com/prometheus/exporter-toolkit/web/kingpinflag\"\n)\n\nvar (\n\t// exporter settings\n\tpgURL             = kingpin.Flag(\"url\", \"postgres target url\").Short('d').Short('u').String()\n\tconfigPath        = kingpin.Flag(\"config\", \"path to config dir or file\").Short('c').String()\n\twebConfig         = kingpinflag.AddFlags(kingpin.CommandLine, \":9630\")\n\tconstLabels       = kingpin.Flag(\"label\", \"constant labels: comma separated list of label=value pair\").Short('l').Default(\"\").Envar(\"PG_EXPORTER_LABEL\").String()\n\tserverTags        = kingpin.Flag(\"tag\", \"tags,comma separated list of server tag\").Default(\"\").Short('t').Envar(\"PG_EXPORTER_TAG\").String()\n\tdisableCache      = kingpin.Flag(\"disable-cache\", \"force not using cache\").Default(\"false\").Short('C').Envar(\"PG_EXPORTER_DISABLE_CACHE\").Bool()\n\tdisableIntro      = kingpin.Flag(\"disable-intro\", \"disable internal/exporter self metrics (only expose query metrics)\").Short('m').Default(\"false\").Envar(\"PG_EXPORTER_DISABLE_INTRO\").Bool()\n\tautoDiscovery     = kingpin.Flag(\"auto-discovery\", \"automatically scrape all database for given server\").Short('a').Default(\"true\").Envar(\"PG_EXPORTER_AUTO_DISCOVERY\").Bool()\n\texcludeDatabase   = kingpin.Flag(\"exclude-database\", \"excluded databases when enabling auto-discovery\").Short('x').Default(\"template0,template1,postgres\").Envar(\"PG_EXPORTER_EXCLUDE_DATABASE\").String()\n\tincludeDatabase   = kingpin.Flag(\"include-database\", \"included databases when enabling auto-discovery\").Short('i').Default(\"\").Envar(\"PG_EXPORTER_INCLUDE_DATABASE\").String()\n\texporterNamespace = kingpin.Flag(\"namespace\", \"prefix of built-in metrics, (pg|pgbouncer) by default\").Short('n').Default(\"\").Envar(\"PG_EXPORTER_NAMESPACE\").String()\n\tfailFast          = kingpin.Flag(\"fail-fast\", \"fail fast instead of waiting during start-up\").Short('f').Envar(\"PG_EXPORTER_FAIL_FAST\").Default(\"false\").Bool()\n\tconnectTimeout    = kingpin.Flag(\"connect-timeout\", \"connect timeout in ms, 100 by default\").Short('T').Envar(\"PG_EXPORTER_CONNECT_TIMEOUT\").Default(\"100\").Int()\n\n\t// prometheus http\n\t// listenAddress = kingpin.Flag(\"web.listen-address\", \"prometheus web server listen address\").Short('L').Default(\":9630\").Envar(\"PG_EXPORTER_LISTEN_ADDRESS\").String()\n\tmetricPath = kingpin.Flag(\"web.telemetry-path\", \"URL path under which to expose metrics.\").Short('P').Default(\"/metrics\").Envar(\"PG_EXPORTER_TELEMETRY_PATH\").String()\n\n\t// action\n\tdryRun      = kingpin.Flag(\"dry-run\", \"dry run and print raw configs\").Default(\"false\").Short('D').Bool()\n\texplainOnly = kingpin.Flag(\"explain\", \"explain server planned queries\").Default(\"false\").Short('E').Bool()\n\n\t// logger setting\n\tlogLevel  = kingpin.Flag(\"log.level\", \"log level: debug|info|warn|error\").Default(\"info\").String()\n\tlogFormat = kingpin.Flag(\"log.format\", \"log format: logfmt|json\").Default(\"logfmt\").String()\n)\n\n// ParseArgs will parse cli args with kingpin. url and config have special treatment\nfunc ParseArgs() {\n\tkingpin.Version(fmt.Sprintf(\"pg_exporter %s (built with %s on %s/%s)\\n\", Version, runtime.Version(), runtime.GOOS, runtime.GOARCH))\n\tkingpin.HelpFlag.Short('h')\n\t// kingpin bool flags don't accept `--flag=false` (only `--no-flag`).\n\t// Normalize common `=true/false` forms to avoid confusing \"unexpected false\" errors.\n\t_ = kingpin.MustParse(kingpin.CommandLine.Parse(normalizeKingpinBoolEqualsArgs(os.Args[1:], kingpin.CommandLine.Model())))\n\tLogger = configureLogger(*logLevel, *logFormat)\n\tlogDebugf(\"init pg_exporter, configPath=%v constLabels=%v disableCache=%v autoDiscovery=%v excludeDatabase=%v includeDatabase=%v connectTimeout=%vms webConfig=%v metricPath=%v\",\n\t\t*configPath, *constLabels, *disableCache, *autoDiscovery, *excludeDatabase, *includeDatabase, *connectTimeout, *webConfig.WebListenAddresses, *metricPath)\n\t*pgURL = GetPGURL()\n\t*configPath = GetConfig()\n}\n"
  },
  {
    "path": "exporter/args_normalize.go",
    "content": "package exporter\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/alecthomas/kingpin/v2\"\n)\n\n// normalizeKingpinBoolEqualsArgs rewrites boolean flags passed as `--flag=false`\n// (or `-f=false`) into kingpin-compatible forms (`--no-flag`).\n//\n// kingpin bool flags are \"presence flags\" and don't accept values, which leads\n// to confusing parse errors like: \"unexpected false, try --help\".\n//\n// This function is intentionally conservative: it only rewrites flags that are\n// known boolean flags in the provided kingpin model.\nfunc normalizeKingpinBoolEqualsArgs(args []string, model *kingpin.ApplicationModel) []string {\n\tif len(args) == 0 || model == nil || model.FlagGroupModel == nil {\n\t\treturn args\n\t}\n\n\tboolFlags := make(map[string]struct{})\n\tshortToLong := make(map[byte]string)\n\tfor _, f := range model.FlagGroupModel.Flags {\n\t\tif f == nil || !f.IsBoolFlag() {\n\t\t\tcontinue\n\t\t}\n\t\tboolFlags[f.Name] = struct{}{}\n\t\tif f.Short != 0 && f.Short <= 0x7f { // only ASCII shorts are relevant to CLI parsing\n\t\t\tshortToLong[byte(f.Short)] = f.Name\n\t\t}\n\t}\n\tif len(boolFlags) == 0 {\n\t\treturn args\n\t}\n\n\tout := make([]string, 0, len(args))\n\tfor _, arg := range args {\n\t\t// Long form: --flag=false\n\t\tif strings.HasPrefix(arg, \"--\") {\n\t\t\tname, val, ok := strings.Cut(arg[2:], \"=\")\n\t\t\tif ok {\n\t\t\t\tif _, isBool := boolFlags[name]; isBool {\n\t\t\t\t\tif b, err := strconv.ParseBool(val); err == nil {\n\t\t\t\t\t\tif b {\n\t\t\t\t\t\t\tout = append(out, \"--\"+name)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tout = append(out, \"--no-\"+name)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tout = append(out, arg)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Short form: -f=false (only single short flag)\n\t\tif strings.HasPrefix(arg, \"-\") && !strings.HasPrefix(arg, \"--\") {\n\t\t\tname, val, ok := strings.Cut(arg[1:], \"=\")\n\t\t\tif ok && len(name) == 1 {\n\t\t\t\tif long, exists := shortToLong[name[0]]; exists {\n\t\t\t\t\tif _, isBool := boolFlags[long]; isBool {\n\t\t\t\t\t\tif b, err := strconv.ParseBool(val); err == nil {\n\t\t\t\t\t\t\tif b {\n\t\t\t\t\t\t\t\tout = append(out, \"-\"+name)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tout = append(out, \"--no-\"+long)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tout = append(out, arg)\n\t\t\tcontinue\n\t\t}\n\n\t\tout = append(out, arg)\n\t}\n\treturn out\n}\n\n"
  },
  {
    "path": "exporter/args_normalize_test.go",
    "content": "package exporter\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/kingpin/v2\"\n)\n\nfunc TestNormalizeKingpinBoolEqualsArgs_Long(t *testing.T) {\n\tapp := kingpin.New(\"test\", \"\")\n\tapp.Flag(\"auto-discovery\", \"\").Short('a').Default(\"true\").Bool()\n\tapp.Flag(\"disable-cache\", \"\").Short('C').Default(\"false\").Bool()\n\tapp.Flag(\"log.level\", \"\").Default(\"info\").String()\n\n\ttests := []struct {\n\t\tin   []string\n\t\twant []string\n\t}{\n\t\t{[]string{\"--auto-discovery=false\"}, []string{\"--no-auto-discovery\"}},\n\t\t{[]string{\"--auto-discovery=true\"}, []string{\"--auto-discovery\"}},\n\t\t{[]string{\"--disable-cache=false\"}, []string{\"--no-disable-cache\"}},\n\t\t{[]string{\"--disable-cache=true\"}, []string{\"--disable-cache\"}},\n\t\t{[]string{\"--log.level=debug\"}, []string{\"--log.level=debug\"}},\n\t\t{[]string{\"--unknown=false\"}, []string{\"--unknown=false\"}},\n\t}\n\n\tfor _, tt := range tests {\n\t\tgot := normalizeKingpinBoolEqualsArgs(tt.in, app.Model())\n\t\tif !reflect.DeepEqual(got, tt.want) {\n\t\t\tt.Fatalf(\"normalize(%v) = %v, want %v\", tt.in, got, tt.want)\n\t\t}\n\t}\n}\n\nfunc TestNormalizeKingpinBoolEqualsArgs_Short(t *testing.T) {\n\tapp := kingpin.New(\"test\", \"\")\n\tapp.Flag(\"auto-discovery\", \"\").Short('a').Default(\"true\").Bool()\n\tapp.Flag(\"disable-cache\", \"\").Short('C').Default(\"false\").Bool()\n\tapp.Flag(\"dry-run\", \"\").Short('D').Default(\"false\").Bool()\n\n\ttests := []struct {\n\t\tin   []string\n\t\twant []string\n\t}{\n\t\t{[]string{\"-a=false\"}, []string{\"--no-auto-discovery\"}},\n\t\t{[]string{\"-a=true\"}, []string{\"-a\"}},\n\t\t{[]string{\"-C=false\"}, []string{\"--no-disable-cache\"}},\n\t\t{[]string{\"-C=true\"}, []string{\"-C\"}},\n\t\t{[]string{\"-D=false\"}, []string{\"--no-dry-run\"}},\n\t\t{[]string{\"-D=true\"}, []string{\"-D\"}},\n\t\t{[]string{\"-x=false\"}, []string{\"-x=false\"}}, // unknown short\n\t}\n\n\tfor _, tt := range tests {\n\t\tgot := normalizeKingpinBoolEqualsArgs(tt.in, app.Model())\n\t\tif !reflect.DeepEqual(got, tt.want) {\n\t\t\tt.Fatalf(\"normalize(%v) = %v, want %v\", tt.in, got, tt.want)\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "exporter/collector.go",
    "content": "package exporter\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\n/* ================ Collector ================ */\n\ntype predicateCacheEntry struct {\n\tat   time.Time\n\tpass bool\n}\n\n// Collector holds runtime information of a Query running on a Server\n// It is deeply coupled with Server. Besides, it can be a collector itself\ntype Collector struct {\n\t*Query\n\tServer *Server // It's a query, but holds a server\n\n\t// runtime information\n\tlock          sync.RWMutex                // scrape lock\n\tresult        []prometheus.Metric         // cached metrics\n\tdescriptors   map[string]*prometheus.Desc // maps column index to descriptor, build on init\n\tcacheHit      bool                        // indicate last scrape was served from cache or real execution\n\tpredicateSkip string                      // if nonempty, predicate query caused skip of this scrape\n\terr           error\n\n\t// predicate cache. Entry i caches PredicateQueries[i] if it has a positive TTL.\n\tpredicateCache []predicateCacheEntry\n\n\t// stats\n\tlastScrape     time.Time     // SERVER's scrape start time (for cache window align)\n\tscrapeBegin    time.Time     // execution begin time\n\tscrapeDone     time.Time     // execution complete time\n\tscrapeDuration time.Duration // last real execution duration\n}\n\n// NewCollector will generate query instance from query, Injecting a server object\nfunc NewCollector(q *Query, s *Server) *Collector {\n\tinstance := &Collector{\n\t\tQuery:  q,\n\t\tServer: s,\n\t\tresult: make([]prometheus.Metric, 0),\n\t}\n\tif len(q.PredicateQueries) > 0 {\n\t\tinstance.predicateCache = make([]predicateCacheEntry, len(q.PredicateQueries))\n\t}\n\tinstance.makeDescMap()\n\treturn instance\n}\n\n// Describe implement prometheus.Collector\nfunc (q *Collector) Describe(ch chan<- *prometheus.Desc) {\n\tq.lock.Lock()\n\tdefer q.lock.Unlock()\n\tq.sendDescriptors(ch)\n}\n\n// Collect implement prometheus.Collector\nfunc (q *Collector) Collect(ch chan<- prometheus.Metric) {\n\tq.lock.Lock()\n\tdefer q.lock.Unlock()\n\tq.scrapeBegin = time.Now()\n\tif q.cacheExpired() || q.Server.DisableCache {\n\t\tq.execute()\n\t\tq.cacheHit = false\n\t\tq.scrapeDone = time.Now()\n\t\tq.scrapeDuration = q.scrapeDone.Sub(q.scrapeBegin)\n\t\tq.lastScrape = q.Server.scrapeBegin\n\t} else { // serve from cache\n\t\tq.cacheHit = true\n\t\tq.scrapeDone = time.Now()\n\t}\n\tq.sendMetrics(ch) // the cache is already reset to zero even execute failed\n}\n\n// ResultSize report last scraped metric count\nfunc (q *Collector) ResultSize() int {\n\treturn len(q.result)\n}\n\n// Error wraps query error (including error in predicate query)\nfunc (q *Collector) Error() error {\n\treturn q.err\n}\n\n// PredicateSkip tells the last scrape skip due to predicate query and if so which predicate query caused the skip?\nfunc (q *Collector) PredicateSkip() (bool, string) {\n\treturn q.predicateSkip != \"\", q.predicateSkip\n}\n\n// Duration returns last scrape duration in float64 seconds\nfunc (q *Collector) Duration() float64 {\n\treturn q.scrapeDone.Sub(q.scrapeBegin).Seconds()\n}\n\n// CacheHit report whether last scrape was serve from cache\nfunc (q *Collector) CacheHit() bool {\n\treturn q.cacheHit\n}\n\n// Run any predicate queries for this query. Return true only if all predicate queries pass.\n// As a side effect sets predicateSkip to the first predicate query that failed, using\n// the predicate query name if specified otherwise the index.\nfunc (q *Collector) executePredicateQueries(ctx context.Context) bool {\n\tfor i, predicateQuery := range q.PredicateQueries {\n\t\tpredicateQueryName := predicateQuery.Name\n\t\tif predicateQueryName == \"\" {\n\t\t\tpredicateQueryName = fmt.Sprintf(\"%d\", i)\n\t\t}\n\t\tq.predicateSkip = predicateQueryName\n\n\t\tmsgPrefix := fmt.Sprintf(\"predicate query [%s] for query [%s] @ server [%s]\", predicateQueryName, q.Name, q.Server.Database)\n\n\t\t// Optional predicate cache (independent of main query cache).\n\t\tif predicateQuery.TTL > 0 && len(q.predicateCache) == len(q.PredicateQueries) {\n\t\t\tentry := q.predicateCache[i]\n\t\t\tif !entry.at.IsZero() {\n\t\t\t\tttl := time.Duration(predicateQuery.TTL * float64(time.Second))\n\t\t\t\tif q.scrapeBegin.Sub(entry.at) < ttl {\n\t\t\t\t\tlogDebugf(\"%s served from predicate cache (ttl=%vs, pass=%v)\", msgPrefix, predicateQuery.TTL, entry.pass)\n\t\t\t\t\tif entry.pass {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// cached skip\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Execute the predicate query.\n\t\tlogDebugf(\"%s executing predicate query\", msgPrefix)\n\t\trows, err := q.Server.QueryContext(ctx, predicateQuery.SQL)\n\t\tif err != nil {\n\t\t\t// If a predicate query fails that's treated as a skip, and the err\n\t\t\t// flag is set so Fatal will be respected if set.\n\t\t\tif errors.Is(err, context.DeadlineExceeded) { // timeout\n\t\t\t\tq.err = fmt.Errorf(\"%s timeout because duration %v exceed limit %v\",\n\t\t\t\t\tmsgPrefix, time.Since(q.scrapeBegin), q.TimeoutDuration())\n\t\t\t} else {\n\t\t\t\tq.err = fmt.Errorf(\"%s failed: %w\", msgPrefix, err)\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\n\t\t// The predicate passes if it returns exactly one row with one column\n\t\t// that is a boolean true.\n\t\tcolTypes, err := rows.ColumnTypes()\n\t\tif err != nil {\n\t\t\tq.err = fmt.Errorf(\"%s failed to get column types: %w\", msgPrefix, err)\n\t\t\t_ = rows.Close()\n\t\t\treturn false\n\t\t}\n\t\tif len(colTypes) != 1 {\n\t\t\tq.err = fmt.Errorf(\"%s failed because it returned %d columns, expected 1\", msgPrefix, len(colTypes))\n\t\t\t_ = rows.Close()\n\t\t\treturn false\n\t\t}\n\t\ttypeName := strings.ToUpper(colTypes[0].DatabaseTypeName())\n\t\tif typeName != \"BOOL\" && typeName != \"BOOLEAN\" {\n\t\t\tq.err = fmt.Errorf(\"%s failed because it returned a column of type %s, expect bool. consider a cast(colname as boolean) or colname::boolean in the query\", msgPrefix, colTypes[0].DatabaseTypeName())\n\t\t\t_ = rows.Close()\n\t\t\treturn false\n\t\t}\n\n\t\tfirstRow := true\n\t\tpredicatePass := sql.NullBool{}\n\t\tfor rows.Next() {\n\t\t\tif !firstRow {\n\t\t\t\tq.err = fmt.Errorf(\"%s failed because it returned more than one row\", msgPrefix)\n\t\t\t\t_ = rows.Close()\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfirstRow = false\n\t\t\terr = rows.Scan(&predicatePass)\n\t\t\tif err != nil {\n\t\t\t\tq.err = fmt.Errorf(\"%s failed scanning in expected 1-row 1-column nullable boolean result: %w\", msgPrefix, err)\n\t\t\t\t_ = rows.Close()\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\tif err = rows.Err(); err != nil {\n\t\t\tq.err = fmt.Errorf(\"%s failed while iterating rows: %w\", msgPrefix, err)\n\t\t\t_ = rows.Close()\n\t\t\treturn false\n\t\t}\n\t\tif err = rows.Close(); err != nil {\n\t\t\tq.err = fmt.Errorf(\"%s failed closing rows: %w\", msgPrefix, err)\n\t\t\treturn false\n\t\t}\n\t\tpass := predicatePass.Valid && predicatePass.Bool\n\t\tif predicateQuery.TTL > 0 && len(q.predicateCache) == len(q.PredicateQueries) {\n\t\t\tq.predicateCache[i] = predicateCacheEntry{at: q.scrapeBegin, pass: pass}\n\t\t}\n\t\tif !pass {\n\t\t\t// successfully executed predicate query requested a skip\n\t\t\tlogDebugf(\"%s returned false, null or zero rows, skipping query\", msgPrefix)\n\t\t\treturn false\n\t\t}\n\t\tlogDebugf(\"%s returned true\", msgPrefix)\n\t}\n\t// If we get here, all predicate queries passed.\n\tq.predicateSkip = \"\"\n\treturn true\n}\n\n// execute will run this query to registered server, result and err are registered\nfunc (q *Collector) execute() {\n\tq.result = q.result[:0] // reset cache\n\tq.err = nil\n\tq.predicateSkip = \"\"\n\tvar rows *sql.Rows\n\tvar err error\n\n\tctx := context.Background()\n\tif q.Timeout != 0 { // if timeout is provided, use context\n\t\tlogDebugf(\"query [%s] @ server [%s] executing begin with time limit: %v\", q.Name, q.Server.Database, q.TimeoutDuration())\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(context.Background(), q.TimeoutDuration())\n\t\tdefer cancel()\n\t} else {\n\t\tlogDebugf(\"query [%s] @ server [%s] executing begin\", q.Name, q.Server.Database)\n\t}\n\n\t// check predicate queries if any\n\tif predicatePass := q.executePredicateQueries(ctx); !predicatePass {\n\t\t// predicateSkip and err if appropriate were set as side effects\n\t\treturn\n\t}\n\n\t// main query execution\n\trows, err = q.Server.QueryContext(ctx, q.SQL)\n\n\t// error handling: if query failed because of timeout or error, record and return\n\tif err != nil {\n\t\tif errors.Is(err, context.DeadlineExceeded) { // timeout\n\t\t\tq.err = fmt.Errorf(\"query [%s] timeout because duration %v exceed limit %v\",\n\t\t\t\tq.Name, time.Since(q.scrapeBegin), q.TimeoutDuration())\n\t\t} else {\n\t\t\tq.err = fmt.Errorf(\"query [%s] failed: %w\", q.Name, err)\n\t\t}\n\t\treturn\n\t}\n\n\t// close rows\n\tdefer func(rows *sql.Rows) { _ = rows.Close() }(rows)\n\n\t// parsing meta:  fetch column metadata for dynamic name lookup\n\tcolumnNames, err := rows.Columns()\n\tif err != nil {\n\t\tq.err = fmt.Errorf(\"query [%s] fail retriving rows meta: %w\", q.Name, err)\n\t\treturn\n\t}\n\tcolumnIndexes := make(map[string]int, len(columnNames)) // column name to index\n\tfor i, n := range columnNames {\n\t\tcolumnIndexes[n] = i\n\t}\n\tnColumn := len(columnNames)\n\tcolData := make([]interface{}, nColumn)\n\tcolArgs := make([]interface{}, nColumn)\n\tfor i := range colData {\n\t\tcolArgs[i] = &colData[i]\n\t}\n\tif len(columnNames) != len(q.Columns) { // warn if column count not match\n\t\tlogWarnf(\"query [%s] column count not match, result %d ≠ config %d\", q.Name, len(columnNames), len(q.Columns))\n\t}\n\n\t// scan loop: for each row, extract labels from all label columns, then generate a new metric for each metric column\n\tfor rows.Next() {\n\t\terr = rows.Scan(colArgs...)\n\t\tif err != nil {\n\t\t\tq.err = fmt.Errorf(\"fail scanning rows: %w\", err)\n\t\t\treturn\n\t\t}\n\n\t\t// get labels, sequence matters, empty string for null or bad labels\n\t\tlabels := make([]string, len(q.LabelNames))\n\t\tfor i, labelName := range q.LabelNames {\n\t\t\tif dataIndex, found := columnIndexes[labelName]; found {\n\t\t\t\tlabels[i] = castString(colData[dataIndex])\n\t\t\t} else {\n\t\t\t\t//if label column is not found in result, we just warn and send a empty string\n\t\t\t\tlogWarnf(\"missing label %s.%s\", q.Name, labelName)\n\t\t\t\tlabels[i] = \"\"\n\t\t\t}\n\t\t}\n\n\t\t// get metrics, warn if column not exist\n\t\tfor _, metricName := range q.MetricNames {\n\t\t\tif dataIndex, found := columnIndexes[metricName]; found { // the metric column is found in result\n\t\t\t\tq.result = append(q.result,\n\t\t\t\t\tprometheus.MustNewConstMetric(\n\t\t\t\t\t\tq.descriptors[metricName], // always find desc & column via name\n\t\t\t\t\t\tq.Columns[metricName].PrometheusValueType(),\n\t\t\t\t\t\tcastFloat64(colData[dataIndex], q.Columns[metricName]),\n\t\t\t\t\t\tlabels...,\n\t\t\t\t\t))\n\t\t\t} else {\n\t\t\t\tlogWarnf(\"missing metric column %s.%s in result\", q.Name, metricName)\n\t\t\t}\n\t\t}\n\t}\n\tif err = rows.Err(); err != nil {\n\t\tq.err = fmt.Errorf(\"query [%s] failed while iterating rows: %w\", q.Name, err)\n\t\treturn\n\t}\n\tq.err = nil\n\tlogDebugf(\"query [%s] executing complete in %v, metrics count: %d\",\n\t\tq.Name, time.Since(q.scrapeBegin), len(q.result))\n}\n\n/* ================ Collector Auxiliary ================ */\n\n// makeDescMap will generate descriptor map from Query\nfunc (q *Collector) makeDescMap() {\n\tdescriptors := make(map[string]*prometheus.Desc)\n\n\t// rename label name if label column have rename option\n\tlabelNames := make([]string, len(q.LabelNames))\n\tfor i, labelName := range q.LabelNames {\n\t\tlabelColumn := q.Columns[labelName]\n\t\tif labelColumn.Rename != \"\" {\n\t\t\tlabelNames[i] = labelColumn.Rename\n\t\t} else {\n\t\t\tlabelNames[i] = labelColumn.Name\n\t\t}\n\t}\n\n\t// rename metric if metric column have a rename option\n\tfor _, metricName := range q.MetricNames {\n\t\tmetricColumn := q.Columns[metricName] // always found\n\t\tmetricName := fmt.Sprintf(\"%s_%s\", q.Name, metricColumn.Name)\n\t\tif metricColumn.Rename != \"\" {\n\t\t\tmetricName = fmt.Sprintf(\"%s_%s\", q.Name, metricColumn.Rename)\n\t\t}\n\t\tdescriptors[metricColumn.Name] = prometheus.NewDesc(\n\t\t\tmetricName, metricColumn.Desc, labelNames, q.Server.labels,\n\t\t)\n\t}\n\tq.descriptors = descriptors\n}\n\nfunc (q *Collector) sendDescriptors(ch chan<- *prometheus.Desc) {\n\tfor _, desc := range q.descriptors {\n\t\tch <- desc\n\t}\n}\n\n// cacheExpired report whether this instance needs actual execution\n// Note you have to use Server.scrapeBegin as \"now\", and set that timestamp as\nfunc (q *Collector) cacheExpired() bool {\n\treturn q.Server.scrapeBegin.Sub(q.lastScrape) > time.Duration(q.TTL*float64(time.Second))\n}\n\nfunc (q *Collector) cacheTTL() float64 {\n\treturn q.TTL - q.Server.scrapeBegin.Sub(q.lastScrape).Seconds()\n}\n\n// sendMetrics will send cached result to ch\nfunc (q *Collector) sendMetrics(ch chan<- prometheus.Metric) {\n\tfor _, metric := range q.result {\n\t\tch <- metric\n\t}\n}\n"
  },
  {
    "path": "exporter/column.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\n/* ================ Column ================ */\n\nconst (\n\tDISCARD   = \"DISCARD\"   // Ignore this column (when SELECT *)\n\tLABEL     = \"LABEL\"     // Use this column as a label\n\tCOUNTER   = \"COUNTER\"   // Use this column as a counter\n\tGAUGE     = \"GAUGE\"     // Use this column as a gauge\n\tHISTOGRAM = \"HISTOGRAM\" // Use this column as a histogram (not implemented yet)\n)\n\n// ColumnUsage determine how to use query result column\nvar ColumnUsage = map[string]bool{\n\tDISCARD: false,\n\tLABEL:   false,\n\tCOUNTER: true,\n\tGAUGE:   true,\n}\n\n// Column holds the metadata of query result\ntype Column struct {\n\tName    string    `yaml:\"name\"`\n\tUsage   string    `yaml:\"usage,omitempty\"`   // column usage\n\tRename  string    `yaml:\"rename,omitempty\"`  // rename column\n\tBucket  []float64 `yaml:\"bucket,omitempty\"`  // histogram bucket\n\tScale   string    `yaml:\"scale,omitempty\"`   // scale factor\n\tDefault string    `yaml:\"default,omitempty\"` // default value\n\tDesc    string    `yaml:\"description,omitempty\"`\n\n\t// Parsed numeric options (filled during config parsing).\n\tscaleFactor  float64\n\thasScale     bool\n\tdefaultValue float64\n\thasDefault   bool\n}\n\nfunc (c *Column) parseNumbers() error {\n\tif c.Scale != \"\" {\n\t\tf, err := strconv.ParseFloat(c.Scale, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid scale %q: %w\", c.Scale, err)\n\t\t}\n\t\tc.scaleFactor = f\n\t\tc.hasScale = true\n\t}\n\tif c.Default != \"\" {\n\t\tf, err := strconv.ParseFloat(c.Default, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid default %q: %w\", c.Default, err)\n\t\t}\n\t\tc.defaultValue = f\n\t\tc.hasDefault = true\n\t}\n\treturn nil\n}\n\n// PrometheusValueType returns column's corresponding prometheus value type\nfunc (c *Column) PrometheusValueType() prometheus.ValueType {\n\tswitch strings.ToUpper(c.Usage) {\n\tcase GAUGE:\n\t\treturn prometheus.GaugeValue\n\tcase COUNTER:\n\t\treturn prometheus.CounterValue\n\tdefault:\n\t\t// it's user's responsibility to make sure this is a value column\n\t\tpanic(fmt.Errorf(\"column %s does not have a valid value type %s\", c.Name, c.Usage))\n\t}\n}\n\n// String turns column into a one-line text representation\nfunc (c *Column) String() string {\n\treturn fmt.Sprintf(\"%-8s %-20s %s\", c.Usage, c.Name, c.Desc)\n}\n\n// MetricDesc will generate MetricDesc from column and additional information\nfunc (c *Column) MetricDesc(prefix string, labels []string) *MetricDesc {\n\tmetricName := fmt.Sprintf(\"%s_%s{%s}\", prefix, c.Name, strings.Join(labels, \",\"))\n\tif c.Rename != \"\" {\n\t\tmetricName = fmt.Sprintf(\"%s_%s{%s}\", prefix, c.Rename, strings.Join(labels, \",\"))\n\t}\n\treturn &MetricDesc{\n\t\tmetricName,\n\t\tlabels,\n\t\tc,\n\t}\n}\n\n// MetricDesc is generated by collector's column definition\ntype MetricDesc struct {\n\tName   string\n\tLabels []string\n\tColumn *Column\n}\n\n// Signature will print metric signature such as pg_db_age{datname}\nfunc (m *MetricDesc) String() string {\n\treturn fmt.Sprintf(\"%s %-8s %s\", m.Name, m.Column.Usage, m.Column.Desc)\n}\n"
  },
  {
    "path": "exporter/concurrency_test.go",
    "content": "package exporter\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc newMockExporter(up bool, recovery bool) *Exporter {\n\ts := &Server{\n\t\tDatabase:  \"postgres\",\n\t\tDatabases: map[string]bool{\"postgres\": true},\n\t\tUP:        up,\n\t\tRecovery:  recovery,\n\t}\n\ts.beforeScrape = func(s *Server) error {\n\t\ts.UP = up\n\t\ts.Recovery = recovery\n\t\treturn nil\n\t}\n\treturn &Exporter{server: s}\n}\n\nfunc TestReloadAndHealthHandlersNoDeadlock(t *testing.T) {\n\toriginalExporter := PgExporter\n\tdefer setCurrentExporter(originalExporter)\n\toriginalLogger := Logger\n\tLogger = configureLogger(\"error\", \"logfmt\")\n\tdefer func() { Logger = originalLogger }()\n\n\te1 := newMockExporter(true, false)\n\te2 := newMockExporter(true, true)\n\tsetCurrentExporter(e1)\n\n\tvar failed atomic.Int32\n\tvar wg sync.WaitGroup\n\n\t// Concurrent simulated reloads.\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor i := 0; i < 400; i++ {\n\t\t\tReloadLock.Lock()\n\t\t\tif i%2 == 0 {\n\t\t\t\tsetCurrentExporter(e2)\n\t\t\t} else {\n\t\t\t\tsetCurrentExporter(e1)\n\t\t\t}\n\t\t\tReloadLock.Unlock()\n\t\t\ttime.Sleep(time.Millisecond)\n\t\t}\n\t}()\n\n\t// Concurrent health/status requests.\n\tfor i := 0; i < 8; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tfor j := 0; j < 200; j++ {\n\t\t\t\treq := httptest.NewRequest(http.MethodGet, \"/up\", nil)\n\n\t\t\t\tw1 := httptest.NewRecorder()\n\t\t\t\te1.UpCheckFunc(w1, req)\n\t\t\t\tif w1.Code != http.StatusOK && w1.Code != http.StatusServiceUnavailable {\n\t\t\t\t\tfailed.Add(1)\n\t\t\t\t}\n\n\t\t\t\tw2 := httptest.NewRecorder()\n\t\t\t\te1.PrimaryCheckFunc(w2, req)\n\t\t\t\tif w2.Code != http.StatusOK && w2.Code != http.StatusNotFound && w2.Code != http.StatusServiceUnavailable {\n\t\t\t\t\tfailed.Add(1)\n\t\t\t\t}\n\n\t\t\t\tw3 := httptest.NewRecorder()\n\t\t\t\te1.ReplicaCheckFunc(w3, req)\n\t\t\t\tif w3.Code != http.StatusOK && w3.Code != http.StatusNotFound && w3.Code != http.StatusServiceUnavailable {\n\t\t\t\t\tfailed.Add(1)\n\t\t\t\t}\n\n\t\t\t\tw4 := httptest.NewRecorder()\n\t\t\t\te1.StatFunc(w4, req)\n\t\t\t\tif w4.Code != http.StatusOK && w4.Code != http.StatusServiceUnavailable {\n\t\t\t\t\tfailed.Add(1)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\tdone := make(chan struct{})\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(done)\n\t}()\n\n\tselect {\n\tcase <-done:\n\tcase <-time.After(10 * time.Second):\n\t\tt.Fatal(\"concurrent reload/health requests timed out, possible deadlock\")\n\t}\n\n\tif failed.Load() > 0 {\n\t\tt.Fatalf(\"unexpected HTTP status count: %d\", failed.Load())\n\t}\n}\n"
  },
  {
    "path": "exporter/config.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"gopkg.in/yaml.v3\"\n)\n\n// GetConfig will try load config from target path\nfunc GetConfig() (res string) {\n\t// priority: cli-args > env  > default settings (check exist)\n\tif res = *configPath; res != \"\" {\n\t\tlogInfof(\"retrieve config path %s from command line\", res)\n\t\treturn res\n\t}\n\tif res = os.Getenv(\"PG_EXPORTER_CONFIG\"); res != \"\" {\n\t\tlogInfof(\"retrieve config path %s from PG_EXPORTER_CONFIG\", res)\n\t\treturn res\n\t}\n\n\tcandidate := []string{\"pg_exporter.yml\", \"/etc/pg_exporter.yml\", \"/etc/pg_exporter\"}\n\tfor _, res = range candidate {\n\t\tif _, err := os.Stat(res); err == nil { // default1 exist\n\t\t\tlogInfof(\"fallback on default config path: %s\", res)\n\t\t\treturn res\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// ParseConfig turn config content into Query struct\nfunc ParseConfig(content []byte) (queries map[string]*Query, err error) {\n\tqueries = make(map[string]*Query)\n\tif err = yaml.Unmarshal(content, &queries); err != nil {\n\t\treturn nil, fmt.Errorf(\"malformed config: %w\", err)\n\t}\n\n\t// parse additional fields\n\tfor branch, query := range queries {\n\t\tif query == nil {\n\t\t\treturn nil, fmt.Errorf(\"query %q is null\", branch)\n\t\t}\n\t\tquery.Branch = branch\n\t\tif query.Name == \"\" {\n\t\t\tquery.Name = branch\n\t\t}\n\t\tif strings.TrimSpace(query.SQL) == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"query %q has empty SQL\", branch)\n\t\t}\n\t\tif query.TTL < 0 {\n\t\t\treturn nil, fmt.Errorf(\"query %q has negative ttl: %v\", branch, query.TTL)\n\t\t}\n\t\tfor i, pq := range query.PredicateQueries {\n\t\t\tif strings.TrimSpace(pq.SQL) == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q has empty predicate_query at index %d\", branch, i)\n\t\t\t}\n\t\t\tif pq.TTL < 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q has negative predicate_queries[%d].ttl: %v\", branch, i, pq.TTL)\n\t\t\t}\n\t\t}\n\t\tif len(query.Metrics) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"query %q has no metrics definition\", branch)\n\t\t}\n\t\t// parse query column info\n\t\tcolumns := make(map[string]*Column, len(query.Metrics))\n\t\tvar allColumns, labelColumns, metricColumns []string\n\t\tfor _, colMap := range query.Metrics {\n\t\t\tif len(colMap) == 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q has an empty metrics entry\", branch)\n\t\t\t}\n\t\t\tif len(colMap) != 1 {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q has invalid metrics entry with %d columns, expect exactly 1\", branch, len(colMap))\n\t\t\t}\n\t\t\tfor colName, column := range colMap { // one-entry map\n\t\t\t\tif column == nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"query %q has null column definition for %q\", branch, colName)\n\t\t\t\t}\n\t\t\t\tif column.Name == \"\" {\n\t\t\t\t\tcolumn.Name = colName\n\t\t\t\t}\n\t\t\t\tusage := strings.ToUpper(strings.TrimSpace(column.Usage))\n\t\t\t\tif usage == \"\" {\n\t\t\t\t\treturn nil, fmt.Errorf(\"query %q column %q has empty usage\", branch, colName)\n\t\t\t\t}\n\t\t\t\tif _, isValid := ColumnUsage[usage]; !isValid {\n\t\t\t\t\treturn nil, fmt.Errorf(\"query %q column %q has unsupported usage: %s\", branch, colName, column.Usage)\n\t\t\t\t}\n\t\t\t\tcolumn.Usage = usage\n\t\t\t\tif err := column.parseNumbers(); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"query %q column %q: %w\", branch, colName, err)\n\t\t\t\t}\n\t\t\t\tswitch column.Usage {\n\t\t\t\tcase LABEL:\n\t\t\t\t\tlabelColumns = append(labelColumns, column.Name)\n\t\t\t\tcase GAUGE, COUNTER:\n\t\t\t\t\tmetricColumns = append(metricColumns, column.Name)\n\t\t\t\t}\n\t\t\t\tallColumns = append(allColumns, column.Name)\n\t\t\t\tif _, exists := columns[column.Name]; exists {\n\t\t\t\t\treturn nil, fmt.Errorf(\"query %q has duplicate column name %q\", branch, column.Name)\n\t\t\t\t}\n\t\t\t\tcolumns[column.Name] = column\n\t\t\t}\n\t\t}\n\t\tif len(metricColumns) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"query %q defines no GAUGE/COUNTER columns\", branch)\n\t\t}\n\t\tquery.Columns, query.ColumnNames, query.LabelNames, query.MetricNames = columns, allColumns, labelColumns, metricColumns\n\n\t\t// Validate prometheus label names and metric names. This prevents panics at scrape time.\n\t\tseenLabels := make(map[string]bool, len(query.LabelNames))\n\t\tfor _, labelColName := range query.LabelNames {\n\t\t\tc := query.Columns[labelColName]\n\t\t\tif c == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q missing label column %q\", branch, labelColName)\n\t\t\t}\n\t\t\tlbl := c.Name\n\t\t\tif c.Rename != \"\" {\n\t\t\t\tlbl = c.Rename\n\t\t\t}\n\t\t\tif err := validatePromLabelName(lbl); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q label %q: %w\", branch, lbl, err)\n\t\t\t}\n\t\t\tif seenLabels[lbl] {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q has duplicate label name %q\", branch, lbl)\n\t\t\t}\n\t\t\tseenLabels[lbl] = true\n\t\t}\n\n\t\tseenMetrics := make(map[string]bool, len(query.MetricNames))\n\t\tfor _, metricColName := range query.MetricNames {\n\t\t\tc := query.Columns[metricColName]\n\t\t\tif c == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q missing metric column %q\", branch, metricColName)\n\t\t\t}\n\t\t\tsuffix := c.Name\n\t\t\tif c.Rename != \"\" {\n\t\t\t\tsuffix = c.Rename\n\t\t\t}\n\t\t\tmetricName := fmt.Sprintf(\"%s_%s\", query.Name, suffix)\n\t\t\tif err := validatePromMetricName(metricName); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q metric %q: %w\", branch, metricName, err)\n\t\t\t}\n\t\t\tif seenMetrics[metricName] {\n\t\t\t\treturn nil, fmt.Errorf(\"query %q has duplicate metric name %q\", branch, metricName)\n\t\t\t}\n\t\t\tseenMetrics[metricName] = true\n\t\t}\n\t}\n\treturn\n}\n\nfunc FinalizeQueries(queries map[string]*Query, source string) error {\n\tfor branch, q := range queries {\n\t\tif q == nil {\n\t\t\treturn fmt.Errorf(\"query %q is null\", branch)\n\t\t}\n\t\tq.Path = source\n\t\t// If timeout is not set, set to 100ms by default.\n\t\t// If timeout is set to a negative number, set to 0 (disabled).\n\t\tif q.Timeout == 0 {\n\t\t\tq.Timeout = 0.1\n\t\t}\n\t\tif q.Timeout < 0 {\n\t\t\tq.Timeout = 0\n\t\t}\n\t}\n\treturn nil\n}\n\n// ParseQuery generate a single query from config string\nfunc ParseQuery(config string) (*Query, error) {\n\tqueries, err := ParseConfig([]byte(config))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(queries) == 0 {\n\t\treturn nil, fmt.Errorf(\"no query definition found\")\n\t}\n\tif len(queries) > 1 {\n\t\treturn nil, fmt.Errorf(\"multiple query definition found\")\n\t}\n\tif err := FinalizeQueries(queries, \"<inline>\"); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, q := range queries {\n\t\treturn q, nil // return the only query instance\n\t}\n\treturn nil, fmt.Errorf(\"no query definition found\")\n}\n\n// LoadConfig will read single conf file or read multiple conf file if a dir is given\n// conf file in a dir will be load in alphabetic order, query with same name will overwrite predecessor\nfunc LoadConfig(configPath string) (queries map[string]*Query, err error) {\n\tstat, err := os.Stat(configPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid config path: %s: %w\", configPath, err)\n\t}\n\tif stat.IsDir() { // iterate conf files (non-recursive) if a dir is given\n\t\tfiles, err := os.ReadDir(configPath)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"fail reading config dir: %s: %w\", configPath, err)\n\t\t}\n\n\t\tlogDebugf(\"load config from dir: %s\", configPath)\n\t\tconfFiles := make([]string, 0)\n\t\tfor _, conf := range files {\n\t\t\tif conf.IsDir() {\n\t\t\t\tcontinue // skip subdirectories\n\t\t\t}\n\t\t\tif !(strings.HasSuffix(conf.Name(), \".yaml\") || strings.HasSuffix(conf.Name(), \".yml\")) {\n\t\t\t\tcontinue // skip non-yaml files\n\t\t\t}\n\t\t\tconfFiles = append(confFiles, filepath.Join(configPath, conf.Name()))\n\t\t}\n\n\t\t// make global config map and assign priority according to config file alphabetic orders\n\t\t// priority is an integer range from 1 to 999, where 1 - 99 is reserved for user\n\t\tqueries = make(map[string]*Query)\n\t\tvar queryCount, configCount int\n\t\tvar firstErr error\n\t\tfor _, confPath := range confFiles {\n\t\t\tif singleQueries, err := LoadConfig(confPath); err != nil {\n\t\t\t\tlogWarnf(\"skip config %s due to error: %s\", confPath, err.Error())\n\t\t\t\tif firstErr == nil {\n\t\t\t\t\tfirstErr = err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconfigCount++\n\t\t\t\tfor name, query := range singleQueries {\n\t\t\t\t\tqueryCount++\n\t\t\t\t\tif query.Priority == 0 { // set to config rank if not manually set\n\t\t\t\t\t\tquery.Priority = 100 + configCount\n\t\t\t\t\t}\n\t\t\t\t\tqueries[name] = query // so the later one will overwrite former one\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif len(confFiles) > 0 && len(queries) == 0 {\n\t\t\tif firstErr != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"no valid queries loaded from config dir %s (%d yaml files), first error: %w\", configPath, len(confFiles), firstErr)\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"no queries loaded from config dir %s (%d yaml files)\", configPath, len(confFiles))\n\t\t}\n\t\tlogDebugf(\"load %d of %d queries from %d config files\", len(queries), queryCount, configCount)\n\t\treturn queries, nil\n\t}\n\n\t// single file case: recursive exit condition\n\tcontent, err := os.ReadFile(configPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fail reading config file %s: %w\", configPath, err)\n\t}\n\tqueries, err = ParseConfig(content)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := FinalizeQueries(queries, stat.Name()); err != nil {\n\t\treturn nil, err\n\t}\n\tlogDebugf(\"load %d queries from %s\", len(queries), configPath)\n\treturn queries, nil\n\n}\n"
  },
  {
    "path": "exporter/config_coverage_pg9_test.go",
    "content": "package exporter\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n)\n\n// Ensure the legacy config (legacy/config) covers PG9.1..PG9.6 without version\n// gaps for collectors that are supposed to work on legacy PG9.x.\nfunc TestConfigCoveragePG9(t *testing.T) {\n\t_, thisFile, _, ok := runtime.Caller(0)\n\tif !ok {\n\t\tt.Fatal(\"runtime.Caller failed\")\n\t}\n\tconfigDir := filepath.Clean(filepath.Join(filepath.Dir(thisFile), \"..\", \"legacy\", \"config\"))\n\tif _, err := os.Stat(configDir); err != nil {\n\t\tt.Skipf(\"legacy config dir not found: %s: %v\", configDir, err)\n\t}\n\n\tqueries, err := LoadConfig(configDir)\n\tif err != nil {\n\t\tt.Fatalf(\"LoadConfig(%s) failed: %v\", configDir, err)\n\t}\n\n\tbyName := make(map[string][]*Query)\n\tfor _, q := range queries {\n\t\tif q.HasTag(\"pgbouncer\") { // PG and pgbouncer versions are in different namespaces.\n\t\t\tcontinue\n\t\t}\n\t\tbyName[q.Name] = append(byName[q.Name], q)\n\t}\n\n\tversions := []int{90100, 90200, 90300, 90400, 90500, 90600} // PG9.1..PG9.6\n\tfor name, qs := range byName {\n\t\tminMin := 0\n\t\tfor i, q := range qs {\n\t\t\tif i == 0 || q.MinVersion < minMin {\n\t\t\t\tminMin = q.MinVersion\n\t\t\t}\n\t\t}\n\n\t\tfor _, v := range versions {\n\t\t\t// Collectors introduced after v are allowed to have gaps for older versions.\n\t\t\tif minMin != 0 && v < minMin {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar appl []*Query\n\t\t\tfor _, q := range qs {\n\t\t\t\tif q.MinVersion != 0 && v < q.MinVersion {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif q.MaxVersion != 0 && v >= q.MaxVersion {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tappl = append(appl, q)\n\t\t\t}\n\n\t\t\tif len(appl) == 0 {\n\t\t\t\tt.Errorf(\"collector %q has no branch for server_version_num=%d\", name, v)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Multiple branches for the same Name are only acceptable when they are\n\t\t\t// mutually exclusive via tags (e.g. primary vs replica).\n\t\t\tif len(appl) > 1 {\n\t\t\t\tif name == \"pg\" && len(appl) == 2 &&\n\t\t\t\t\t((appl[0].HasTag(\"primary\") && appl[1].HasTag(\"replica\")) ||\n\t\t\t\t\t\t(appl[0].HasTag(\"replica\") && appl[1].HasTag(\"primary\"))) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tt.Errorf(\"collector %q has %d overlapping branches for server_version_num=%d: %v\", name, len(appl), v, func() []string {\n\t\t\t\t\tout := make([]string, 0, len(appl))\n\t\t\t\t\tfor _, q := range appl {\n\t\t\t\t\t\tout = append(out, q.Branch)\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t}())\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "exporter/config_coverage_test.go",
    "content": "package exporter\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n)\n\n// Ensure the repo-bundled config/ covers PG10..PG18 without version gaps for\n// collectors that are supposed to work on PG10+. This is a cheap static check\n// (no DB required) to catch off-by-one mistakes on min/max_version splits.\nfunc TestConfigCoveragePG10To18(t *testing.T) {\n\t_, thisFile, _, ok := runtime.Caller(0)\n\tif !ok {\n\t\tt.Fatal(\"runtime.Caller failed\")\n\t}\n\tconfigDir := filepath.Clean(filepath.Join(filepath.Dir(thisFile), \"..\", \"config\"))\n\tif _, err := os.Stat(configDir); err != nil {\n\t\tt.Skipf(\"config dir not found: %s: %v\", configDir, err)\n\t}\n\n\tqueries, err := LoadConfig(configDir)\n\tif err != nil {\n\t\tt.Fatalf(\"LoadConfig(%s) failed: %v\", configDir, err)\n\t}\n\n\tbyName := make(map[string][]*Query)\n\tfor _, q := range queries {\n\t\tif q.HasTag(\"pgbouncer\") { // PG and pgbouncer versions are in different namespaces.\n\t\t\tcontinue\n\t\t}\n\t\tbyName[q.Name] = append(byName[q.Name], q)\n\t}\n\n\tfor name, qs := range byName {\n\t\tminMin := 0\n\t\tfor i, q := range qs {\n\t\t\tif i == 0 || q.MinVersion < minMin {\n\t\t\t\tminMin = q.MinVersion\n\t\t\t}\n\t\t}\n\n\t\t// Collectors introduced after PG10 are allowed to have gaps for PG10-.\n\t\tif minMin > 100000 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor v := 100000; v <= 180000; v += 10000 { // PG10..PG18\n\t\t\tvar appl []*Query\n\t\t\tfor _, q := range qs {\n\t\t\t\tif q.MinVersion != 0 && v < q.MinVersion {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif q.MaxVersion != 0 && v >= q.MaxVersion { // exclude\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tappl = append(appl, q)\n\t\t\t}\n\n\t\t\tif len(appl) == 0 {\n\t\t\t\tt.Errorf(\"collector %q has no branch for server_version_num=%d\", name, v)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Multiple branches for the same Name are only acceptable when they are\n\t\t\t// mutually exclusive via tags (e.g. primary vs replica).\n\t\t\tif len(appl) > 1 {\n\t\t\t\tif name == \"pg\" && len(appl) == 2 &&\n\t\t\t\t\t((appl[0].HasTag(\"primary\") && appl[1].HasTag(\"replica\")) ||\n\t\t\t\t\t\t(appl[0].HasTag(\"replica\") && appl[1].HasTag(\"primary\"))) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tt.Errorf(\"collector %q has %d overlapping branches for server_version_num=%d: %v\", name, len(appl), v, func() []string {\n\t\t\t\t\tout := make([]string, 0, len(appl))\n\t\t\t\t\tfor _, q := range appl {\n\t\t\t\t\t\tout = append(out, q.Branch)\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t}())\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "exporter/config_merged_test.go",
    "content": "package exporter\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"slices\"\n\t\"testing\"\n)\n\nfunc parseConfigDirLikeMerge(t *testing.T, dir string) map[string]*Query {\n\tt.Helper()\n\n\tentries, err := os.ReadDir(dir)\n\tif err != nil {\n\t\tt.Fatalf(\"ReadDir(%s) failed: %v\", dir, err)\n\t}\n\n\tnames := make([]string, 0, len(entries))\n\tfor _, entry := range entries {\n\t\tif entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\text := filepath.Ext(entry.Name())\n\t\tif ext != \".yml\" && ext != \".yaml\" {\n\t\t\tcontinue\n\t\t}\n\t\tnames = append(names, entry.Name())\n\t}\n\tslices.Sort(names)\n\n\tqueries := make(map[string]*Query)\n\tfor _, name := range names {\n\t\tpath := filepath.Join(dir, name)\n\t\tcontent, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"ReadFile(%s) failed: %v\", path, err)\n\t\t}\n\t\tparsed, err := ParseConfig(content)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"ParseConfig(%s) failed: %v\", path, err)\n\t\t}\n\t\tfor branch, q := range parsed {\n\t\t\tqueries[branch] = q\n\t\t}\n\t}\n\treturn queries\n}\n\nfunc TestMergedConfigsMatchSplitDirectories(t *testing.T) {\n\t_, thisFile, _, ok := runtime.Caller(0)\n\tif !ok {\n\t\tt.Fatal(\"runtime.Caller failed\")\n\t}\n\trepoRoot := filepath.Clean(filepath.Join(filepath.Dir(thisFile), \"..\"))\n\n\tcases := []struct {\n\t\tname   string\n\t\tdir    string\n\t\tmerged string\n\t}{\n\t\t{\n\t\t\tname:   \"current\",\n\t\t\tdir:    filepath.Join(repoRoot, \"config\"),\n\t\t\tmerged: filepath.Join(repoRoot, \"pg_exporter.yml\"),\n\t\t},\n\t\t{\n\t\t\tname:   \"legacy\",\n\t\t\tdir:    filepath.Join(repoRoot, \"legacy\", \"config\"),\n\t\t\tmerged: filepath.Join(repoRoot, \"legacy\", \"pg_exporter.yml\"),\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tsplitQueries := parseConfigDirLikeMerge(t, tc.dir)\n\n\t\t\tmergedContent, err := os.ReadFile(tc.merged)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"ReadFile(%s) failed: %v\", tc.merged, err)\n\t\t\t}\n\t\t\tmergedQueries, err := ParseConfig(mergedContent)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"ParseConfig(%s) failed: %v\", tc.merged, err)\n\t\t\t}\n\n\t\t\tif len(splitQueries) != len(mergedQueries) {\n\t\t\t\tt.Fatalf(\"query count mismatch: split=%d merged=%d\", len(splitQueries), len(mergedQueries))\n\t\t\t}\n\n\t\t\tfor branch, splitQuery := range splitQueries {\n\t\t\t\tmergedQuery, ok := mergedQueries[branch]\n\t\t\t\tif !ok {\n\t\t\t\t\tt.Fatalf(\"branch %q missing from merged config %s\", branch, tc.merged)\n\t\t\t\t}\n\t\t\t\tif !reflect.DeepEqual(splitQuery, mergedQuery) {\n\t\t\t\t\tt.Fatalf(\"branch %q differs between split dir %s and merged config %s\", branch, tc.dir, tc.merged)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "exporter/config_style_test.go",
    "content": "package exporter\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n)\n\nvar inlineMetricDescriptionRE = regexp.MustCompile(`^\\s*-\\s*[^:]+:\\s*\\{.*\\bdescription:\\s*(.+)\\}\\s*$`)\n\nfunc TestInlineMetricDescriptionsUseDoubleQuotes(t *testing.T) {\n\t_, thisFile, _, ok := runtime.Caller(0)\n\tif !ok {\n\t\tt.Fatal(\"runtime.Caller failed\")\n\t}\n\trepoRoot := filepath.Clean(filepath.Join(filepath.Dir(thisFile), \"..\"))\n\n\tfor _, rel := range []string{\"config\", filepath.Join(\"legacy\", \"config\")} {\n\t\tdir := filepath.Join(repoRoot, rel)\n\t\tt.Run(rel, func(t *testing.T) {\n\t\t\tentries, err := os.ReadDir(dir)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"ReadDir(%s) failed: %v\", dir, err)\n\t\t\t}\n\t\t\tfor _, entry := range entries {\n\t\t\t\tif entry.IsDir() || filepath.Ext(entry.Name()) != \".yml\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tpath := filepath.Join(dir, entry.Name())\n\t\t\t\tf, err := os.Open(path)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"Open(%s) failed: %v\", path, err)\n\t\t\t\t}\n\n\t\t\t\tscanner := bufio.NewScanner(f)\n\t\t\t\tfor lineNo := 1; scanner.Scan(); lineNo++ {\n\t\t\t\t\tline := scanner.Text()\n\t\t\t\t\tm := inlineMetricDescriptionRE.FindStringSubmatch(line)\n\t\t\t\t\tif m == nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tdesc := strings.TrimSpace(m[1])\n\t\t\t\t\tif len(desc) < 2 || desc[0] != '\"' || desc[len(desc)-1] != '\"' {\n\t\t\t\t\t\tt.Errorf(\"%s:%d inline metric description must use double quotes: %s\", path, lineNo, desc)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err := scanner.Err(); err != nil {\n\t\t\t\t\t_ = f.Close()\n\t\t\t\t\tt.Fatalf(\"Scan(%s) failed: %v\", path, err)\n\t\t\t\t}\n\t\t\t\tif err := f.Close(); err != nil {\n\t\t\t\t\tt.Fatalf(\"Close(%s) failed: %v\", path, err)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestLegacySplitConfigsEndWithTwoBlankLines(t *testing.T) {\n\t_, thisFile, _, ok := runtime.Caller(0)\n\tif !ok {\n\t\tt.Fatal(\"runtime.Caller failed\")\n\t}\n\tdir := filepath.Clean(filepath.Join(filepath.Dir(thisFile), \"..\", \"legacy\", \"config\"))\n\n\tentries, err := os.ReadDir(dir)\n\tif err != nil {\n\t\tt.Fatalf(\"ReadDir(%s) failed: %v\", dir, err)\n\t}\n\n\tfor _, entry := range entries {\n\t\tif entry.IsDir() || filepath.Ext(entry.Name()) != \".yml\" {\n\t\t\tcontinue\n\t\t}\n\t\tpath := filepath.Join(dir, entry.Name())\n\t\tdata, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"ReadFile(%s) failed: %v\", path, err)\n\t\t}\n\t\ttrailingNewlines := len(data) - len(bytes.TrimRight(data, \"\\n\"))\n\t\tif trailingNewlines != 3 {\n\t\t\tt.Errorf(\"%s must end with exactly two blank lines (3 trailing newlines), got %d\", path, trailingNewlines)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "exporter/config_test.go",
    "content": "package exporter\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc TestParseConfigUsageCaseInsensitive(t *testing.T) {\n\tconfig := `\ntest_query:\n  query: SELECT 1 AS metric, 'db' AS datname\n  metrics:\n    - metric:\n        usage: gauge\n        description: metric value\n    - datname:\n        usage: label\n        description: database name\n`\n\n\tqueries, err := ParseConfig([]byte(config))\n\tif err != nil {\n\t\tt.Fatalf(\"ParseConfig returned error: %v\", err)\n\t}\n\n\tquery, ok := queries[\"test_query\"]\n\tif !ok {\n\t\tt.Fatalf(\"query test_query not found\")\n\t}\n\n\tif got := query.Columns[\"metric\"].Usage; got != GAUGE {\n\t\tt.Fatalf(\"metric usage = %s, want %s\", got, GAUGE)\n\t}\n\tif got := query.Columns[\"datname\"].Usage; got != LABEL {\n\t\tt.Fatalf(\"datname usage = %s, want %s\", got, LABEL)\n\t}\n}\n\nfunc TestParseConfigInvalidUsage(t *testing.T) {\n\tconfig := `\nbad_query:\n  query: SELECT 1 AS metric\n  metrics:\n    - metric:\n        usage: bad_usage\n        description: metric value\n`\n\n\tif _, err := ParseConfig([]byte(config)); err == nil {\n\t\tt.Fatal(\"ParseConfig should fail on unsupported usage\")\n\t}\n}\n\nfunc TestParseConfigRejectsMultiColumnMetricsEntry(t *testing.T) {\n\tconfig := `\nbad_query:\n  query: SELECT 1 AS a, 2 AS b\n  metrics:\n    - a:\n        usage: gauge\n      b:\n        usage: gauge\n`\n\tif _, err := ParseConfig([]byte(config)); err == nil {\n\t\tt.Fatal(\"ParseConfig should fail when one metrics entry defines multiple columns\")\n\t}\n}\n\nfunc TestParseQueryErrors(t *testing.T) {\n\tif _, err := ParseQuery(`{}`); err == nil {\n\t\tt.Fatal(\"ParseQuery should fail when no query is defined\")\n\t}\n\n\tmulti := `\nq1:\n  query: SELECT 1 AS metric\n  metrics:\n    - metric:\n        usage: gauge\nq2:\n  query: SELECT 2 AS metric\n  metrics:\n    - metric:\n        usage: gauge\n`\n\tif _, err := ParseQuery(multi); err == nil {\n\t\tt.Fatal(\"ParseQuery should fail when multiple queries are defined\")\n\t}\n}\n\nfunc TestLoadConfigDirectoryPriorityAndOverride(t *testing.T) {\n\tdir := t.TempDir()\n\tf1 := filepath.Join(dir, \"0100-a.yml\")\n\tf2 := filepath.Join(dir, \"0200-b.yml\")\n\n\tcfg1 := `\nq_common:\n  query: SELECT 1 AS metric\n  metrics:\n    - metric:\n        usage: gauge\n`\n\tcfg2 := `\nq_common:\n  query: SELECT 2 AS metric\n  metrics:\n    - metric:\n        usage: gauge\nq_extra:\n  query: SELECT 3 AS metric\n  metrics:\n    - metric:\n        usage: gauge\n`\n\tif err := os.WriteFile(f1, []byte(cfg1), 0o644); err != nil {\n\t\tt.Fatalf(\"write config 1 failed: %v\", err)\n\t}\n\tif err := os.WriteFile(f2, []byte(cfg2), 0o644); err != nil {\n\t\tt.Fatalf(\"write config 2 failed: %v\", err)\n\t}\n\n\tqueries, err := LoadConfig(dir)\n\tif err != nil {\n\t\tt.Fatalf(\"LoadConfig dir failed: %v\", err)\n\t}\n\tif len(queries) != 2 {\n\t\tt.Fatalf(\"LoadConfig query count = %d, want 2\", len(queries))\n\t}\n\tif queries[\"q_common\"].SQL != \"SELECT 2 AS metric\" {\n\t\tt.Fatalf(\"q_common should be overridden by later file, got: %s\", queries[\"q_common\"].SQL)\n\t}\n\t// 2nd config file gets default priority 102.\n\tif queries[\"q_common\"].Priority != 102 {\n\t\tt.Fatalf(\"q_common priority = %d, want 102\", queries[\"q_common\"].Priority)\n\t}\n\tif queries[\"q_extra\"].Priority != 102 {\n\t\tt.Fatalf(\"q_extra priority = %d, want 102\", queries[\"q_extra\"].Priority)\n\t}\n}\n\nfunc TestLoadConfigDirectoryAllInvalidReturnsError(t *testing.T) {\n\tdir := t.TempDir()\n\tbad := `\nq_bad:\n  query: SELECT 1 AS metric\n  metrics:\n    - metric:\n        usage: bad_usage\n`\n\tif err := os.WriteFile(filepath.Join(dir, \"0100-bad.yml\"), []byte(bad), 0o644); err != nil {\n\t\tt.Fatalf(\"write config failed: %v\", err)\n\t}\n\n\tif _, err := LoadConfig(dir); err == nil {\n\t\tt.Fatal(\"LoadConfig should fail when no valid queries are loaded from a config directory\")\n\t}\n}\n\nfunc TestGetConfigPrecedence(t *testing.T) {\n\toriginConfigPath := *configPath\n\tt.Cleanup(func() { *configPath = originConfigPath })\n\n\toriginEnv := os.Getenv(\"PG_EXPORTER_CONFIG\")\n\tt.Cleanup(func() { _ = os.Setenv(\"PG_EXPORTER_CONFIG\", originEnv) })\n\n\t*configPath = \"/tmp/from-cli.yml\"\n\t_ = os.Setenv(\"PG_EXPORTER_CONFIG\", \"/tmp/from-env.yml\")\n\tif got := GetConfig(); got != \"/tmp/from-cli.yml\" {\n\t\tt.Fatalf(\"GetConfig CLI precedence failed: got %s\", got)\n\t}\n\n\t*configPath = \"\"\n\tif got := GetConfig(); got != \"/tmp/from-env.yml\" {\n\t\tt.Fatalf(\"GetConfig env fallback failed: got %s\", got)\n\t}\n}\n"
  },
  {
    "path": "exporter/exporter.go",
    "content": "package exporter\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\n/* ================ Exporter ================ */\n\nconst (\n\thealthStatusUnknown int32 = iota\n\thealthStatusDown\n\thealthStatusStarting\n\thealthStatusPrimary\n\thealthStatusReplica\n)\n\n// Exporter implement prometheus.Collector interface\n// exporter contains one or more (auto-discover-database) servers that can scrape metrics with Query\ntype Exporter struct {\n\t// config params provided from ExporterOpt\n\tdsn             string            // primary dsn\n\tconfigPath      string            // config file path /directory\n\tconfigReader    io.Reader         // reader to a config file, one of configPath or configReader must be set\n\tdisableCache    bool              // always execute query when been scraped\n\tdisableIntro    bool              // disable internal/exporter self metrics (only expose query metrics)\n\tautoDiscovery   bool              // discovery other database on primary server\n\tpgbouncerMode   bool              // is primary server a pgbouncer ?\n\tfailFast        bool              // fail fast instead fof waiting during start-up ?\n\texcludeDatabase map[string]bool   // excluded database for auto discovery\n\tincludeDatabase map[string]bool   // include database for auto discovery\n\tconstLabels     prometheus.Labels // prometheus const k=v labels\n\ttags            []string          // tags passed to this exporter for scheduling purpose\n\tnamespace       string            // metrics prefix ('pg' or 'pgbouncer' by default)\n\tconnectTimeout  int               // timeout in ms when perform server pre-check\n\n\t// internal status\n\tlock    sync.RWMutex       // export lock\n\tserver  *Server            // primary server\n\tsLock   sync.RWMutex       // server map lock\n\tservers map[string]*Server // auto discovered peripheral servers\n\tqueries map[string]*Query  // metrics query definition\n\n\t// internal stats\n\tscrapeBegin time.Time // server level scrape begin\n\tscrapeDone  time.Time // server last scrape done\n\n\t// internal metrics: global, exporter, server, query\n\tup               prometheus.Gauge   // cluster level: primary target server is alive\n\tversion          prometheus.Gauge   // cluster level: postgres main server version num\n\trecovery         prometheus.Gauge   // cluster level: postgres is in recovery ?\n\tbuildInfo        prometheus.Gauge   // exporter level: build information\n\texporterUp       prometheus.Gauge   // exporter level: always set ot 1\n\texporterUptime   prometheus.Gauge   // exporter level: primary target server uptime (exporter itself)\n\tlastScrapeTime   prometheus.Gauge   // exporter level: last scrape timestamp\n\tscrapeDuration   prometheus.Gauge   // exporter level: seconds spend on scrape\n\tscrapeTotalCount prometheus.Counter // exporter level: total scrape count of this server\n\tscrapeErrorCount prometheus.Counter // exporter level: error scrape count\n\n\t// Dynamic series (auto-discovered DBs, config reload) are emitted as const\n\t// metrics on each scrape to avoid GaugeVec Reset() overhead and stale series.\n\tserverScrapeDurationDesc     *prometheus.Desc // {datname} database level: last scrape duration\n\tserverScrapeTotalSecondsDesc *prometheus.Desc // {datname} database level: cumulative scrape seconds\n\tserverScrapeTotalCountDesc   *prometheus.Desc // {datname} database level: total scrape count\n\tserverScrapeErrorCountDesc   *prometheus.Desc // {datname} database level: cumulative fatal scrape error count\n\n\tqueryCacheTTLDesc                 *prometheus.Desc // {datname,query} query cache ttl\n\tqueryScrapeTotalCountDesc         *prometheus.Desc // {datname,query} query level: total executions\n\tqueryScrapeErrorCountDesc         *prometheus.Desc // {datname,query} query level: error count\n\tqueryScrapePredicateSkipCountDesc *prometheus.Desc // {datname,query} query level: predicate skip count\n\tqueryScrapeDurationDesc           *prometheus.Desc // {datname,query} query level: execution duration (seconds)\n\tqueryScrapeMetricCountDesc        *prometheus.Desc // {datname,query} query level: returned metric count\n\tqueryScrapeHitCountDesc           *prometheus.Desc // {datname,query} query level: cache hit count\n\n\t// lock-free health snapshot for high-frequency probes\n\thealthUp       atomic.Bool\n\thealthRecovery atomic.Bool\n\thealthStatus   atomic.Int32\n\n\thealthLoopLock sync.Mutex\n\thealthLoopStop chan struct{}\n\thealthLoopDone chan struct{}\n}\n\n// Up will delegate aliveness check to primary server\nfunc (e *Exporter) Up() bool {\n\treturn e.healthUp.Load()\n}\n\n// Recovery will delegate primary/replica check to primary server\nfunc (e *Exporter) Recovery() bool {\n\treturn e.healthRecovery.Load()\n}\n\n// Status will report available status: primary|replica|starting|down|unknown\nfunc (e *Exporter) Status() string {\n\tswitch e.healthStatus.Load() {\n\tcase healthStatusPrimary:\n\t\treturn `primary`\n\tcase healthStatusReplica:\n\t\treturn `replica`\n\tcase healthStatusStarting:\n\t\treturn `starting`\n\tcase healthStatusDown:\n\t\treturn `down`\n\tdefault:\n\t\treturn `unknown`\n\t}\n}\n\nfunc (e *Exporter) updateHealthState(up, recovery bool) {\n\te.updateHealthStateWithStartup(up, recovery, false)\n}\n\nfunc (e *Exporter) updateHealthStateWithStartup(up, recovery, starting bool) {\n\te.healthUp.Store(up)\n\tif starting {\n\t\te.healthRecovery.Store(false)\n\t\te.healthStatus.Store(healthStatusStarting)\n\t\treturn\n\t}\n\te.healthRecovery.Store(up && recovery)\n\tif !up {\n\t\te.healthStatus.Store(healthStatusDown)\n\t\treturn\n\t}\n\tif recovery {\n\t\te.healthStatus.Store(healthStatusReplica)\n\t\treturn\n\t}\n\te.healthStatus.Store(healthStatusPrimary)\n}\n\nfunc (e *Exporter) updateHealthStateFromServer() {\n\tif e.server == nil {\n\t\te.healthUp.Store(false)\n\t\te.healthRecovery.Store(false)\n\t\te.healthStatus.Store(healthStatusUnknown)\n\t\treturn\n\t}\n\te.server.lock.RLock()\n\tup := e.server.UP\n\trecovery := e.server.Recovery\n\te.server.lock.RUnlock()\n\te.updateHealthState(up, recovery)\n}\n\nfunc (e *Exporter) probeAndUpdateHealthState() error {\n\tif e.server == nil {\n\t\te.healthUp.Store(false)\n\t\te.healthRecovery.Store(false)\n\t\te.healthStatus.Store(healthStatusUnknown)\n\t\treturn errors.New(\"primary server is nil\")\n\t}\n\tup, recovery, starting, err := e.server.ProbeHealth()\n\te.updateHealthStateWithStartup(up, recovery, starting)\n\treturn err\n}\n\nfunc (e *Exporter) startHealthLoop() {\n\te.healthLoopLock.Lock()\n\tif e.healthLoopStop != nil {\n\t\te.healthLoopLock.Unlock()\n\t\treturn\n\t}\n\tstopCh := make(chan struct{})\n\tdoneCh := make(chan struct{})\n\te.healthLoopStop = stopCh\n\te.healthLoopDone = doneCh\n\te.healthLoopLock.Unlock()\n\n\tgo func() {\n\t\tdefer close(doneCh)\n\t\tticker := time.NewTicker(1 * time.Second)\n\t\tdefer ticker.Stop()\n\n\t\t// Health probing is intentionally decoupled from /metrics scraping so that:\n\t\t// - HTTP health handlers never block on network calls\n\t\t// - the exporter can recover health status even when scrapes are failing\n\t\t//\n\t\t// Keep Server.ProbeHealth cheap and log-noise-free: it runs once per second.\n\t\t_ = e.probeAndUpdateHealthState()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-stopCh:\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\t_ = e.probeAndUpdateHealthState()\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (e *Exporter) stopHealthLoop() {\n\te.healthLoopLock.Lock()\n\tstopCh := e.healthLoopStop\n\tdoneCh := e.healthLoopDone\n\te.healthLoopStop = nil\n\te.healthLoopDone = nil\n\te.healthLoopLock.Unlock()\n\n\tif stopCh == nil {\n\t\treturn\n\t}\n\tclose(stopCh)\n\tif doneCh != nil {\n\t\t<-doneCh\n\t}\n}\n\n// Describe implement prometheus.Collector\nfunc (e *Exporter) Describe(ch chan<- *prometheus.Desc) {\n\t// Intentionally leave this exporter \"unchecked\".\n\t//\n\t// Query metrics are dynamic:\n\t// - config reload can add/remove collectors and metrics\n\t// - auto-discovery can add/remove databases\n\t//\n\t// If we emitted any descriptors here, the Prometheus registry would enforce\n\t// that Collect() only returns described metrics, which does not hold for a\n\t// dynamic exporter. Exporter-toolkit and client_golang both support this\n\t// pattern (Describe emits nothing).\n}\n\n// Collect implement prometheus.Collector\nfunc (e *Exporter) Collect(ch chan<- prometheus.Metric) {\n\te.lock.Lock()\n\tdefer e.lock.Unlock()\n\tif !e.disableIntro {\n\t\te.scrapeTotalCount.Add(1)\n\t}\n\n\te.scrapeBegin = time.Now()\n\t// scrape primary server\n\ts := e.server\n\ts.Collect(ch)\n\n\t// scrape extra servers if exists\n\tfor _, srv := range e.IterateServer() {\n\t\tsrv.Collect(ch)\n\t}\n\te.scrapeDone = time.Now()\n\n\tif !e.disableIntro {\n\t\te.lastScrapeTime.Set(float64(e.scrapeDone.Unix()))\n\t\te.scrapeDuration.Set(e.scrapeDone.Sub(e.scrapeBegin).Seconds())\n\t}\n\ts.lock.RLock()\n\tversion := s.Version\n\tup := s.UP\n\trecovery := s.Recovery\n\ts.lock.RUnlock()\n\n\te.updateHealthState(up, recovery)\n\tif !e.disableIntro {\n\t\te.version.Set(float64(version))\n\t\tif up {\n\t\t\te.up.Set(1)\n\t\t\tif recovery {\n\t\t\t\te.recovery.Set(1)\n\t\t\t} else {\n\t\t\t\te.recovery.Set(0)\n\t\t\t}\n\t\t} else {\n\t\t\te.up.Set(0)\n\t\t\te.scrapeErrorCount.Add(1)\n\t\t}\n\t\te.exporterUptime.Set(e.server.Uptime())\n\t\te.collectServerMetrics(ch)\n\t\te.collectInternalMetrics(ch)\n\t}\n}\n\nfunc (e *Exporter) collectServerMetrics(ch chan<- prometheus.Metric) {\n\tservers := e.IterateServer()\n\tif e.server != nil {\n\t\tservers = append(servers, e.server) // append primary server to extra server list\n\t}\n\tfor _, s := range servers {\n\t\tif s == nil {\n\t\t\tcontinue\n\t\t}\n\t\ts.lock.RLock()\n\t\tdatname := s.Database\n\t\tscrapeDur := s.scrapeDone.Sub(s.scrapeBegin).Seconds()\n\t\ttotalSeconds := s.totalTime\n\t\ttotalCount := s.totalCount\n\t\terrorCount := s.errorCount\n\n\t\t// Snapshot query maps (they are replaced as a whole on ResetStats).\n\t\tqueryCacheTTL := s.queryCacheTTL\n\t\tqueryScrapeTotalCount := s.queryScrapeTotalCount\n\t\tqueryScrapeHitCount := s.queryScrapeHitCount\n\t\tqueryScrapeErrorCount := s.queryScrapeErrorCount\n\t\tqueryScrapePredicateSkipCount := s.queryScrapePredicateSkipCount\n\t\tqueryScrapeMetricCount := s.queryScrapeMetricCount\n\t\tqueryScrapeDuration := s.queryScrapeDuration\n\t\ts.lock.RUnlock()\n\n\t\tch <- prometheus.MustNewConstMetric(e.serverScrapeDurationDesc, prometheus.GaugeValue, scrapeDur, datname)\n\t\tch <- prometheus.MustNewConstMetric(e.serverScrapeTotalSecondsDesc, prometheus.GaugeValue, totalSeconds, datname)\n\t\tch <- prometheus.MustNewConstMetric(e.serverScrapeTotalCountDesc, prometheus.GaugeValue, totalCount, datname)\n\t\tch <- prometheus.MustNewConstMetric(e.serverScrapeErrorCountDesc, prometheus.GaugeValue, errorCount, datname)\n\n\t\tfor queryName, v := range queryCacheTTL {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryCacheTTLDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t\tfor queryName, v := range queryScrapeTotalCount {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryScrapeTotalCountDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t\tfor queryName, v := range queryScrapeHitCount {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryScrapeHitCountDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t\tfor queryName, v := range queryScrapeErrorCount {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryScrapeErrorCountDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t\tfor queryName, v := range queryScrapePredicateSkipCount {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryScrapePredicateSkipCountDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t\tfor queryName, v := range queryScrapeMetricCount {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryScrapeMetricCountDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t\tfor queryName, v := range queryScrapeDuration {\n\t\t\tch <- prometheus.MustNewConstMetric(e.queryScrapeDurationDesc, prometheus.GaugeValue, v, datname, queryName)\n\t\t}\n\t}\n}\n\n// Explain is a thin wrapper of server.Explain (plain text).\nfunc (e *Exporter) Explain() string {\n\treturn e.server.Explain()\n}\n\n// Stat is just yet another wrapper of server.Stat\nfunc (e *Exporter) Stat() string {\n\tlogDebugf(\"stats invoked\")\n\treturn e.server.Stat()\n}\n\n// Check will perform an immediate server health check\nfunc (e *Exporter) Check() {\n\tif err := e.probeAndUpdateHealthState(); err != nil {\n\t\tlogErrorf(\"exporter check failure: %s\", err.Error())\n\t} else {\n\t\tlogDebugf(\"exporter check ok\")\n\t}\n}\n\n// Close will close all underlying servers\nfunc (e *Exporter) Close() {\n\te.stopHealthLoop()\n\n\tif e.server != nil {\n\t\tif e.server.DB != nil {\n\t\t\terr := e.server.Close()\n\t\t\tif err != nil {\n\t\t\t\tlogErrorf(\"fail closing server %s: %s\", e.server.Name(), err.Error())\n\t\t\t}\n\t\t}\n\t}\n\t// close peripheral servers (we may skip acquire lock here)\n\tfor _, srv := range e.IterateServer() {\n\t\tif srv != nil {\n\t\t\tif srv.DB != nil {\n\t\t\t\terr := srv.Close()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogErrorf(\"fail closing server %s: %s\", srv.Name(), err.Error())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tlogInfof(\"pg exporter closed\")\n}\n\n// setupInternalMetrics will init internal metrics\nfunc (e *Exporter) setupInternalMetrics() {\n\tif e.namespace == \"\" {\n\t\tif e.pgbouncerMode {\n\t\t\te.namespace = \"pgbouncer\"\n\t\t} else {\n\t\t\te.namespace = \"pg\"\n\t\t}\n\t}\n\n\t// major fact\n\te.up = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tName: \"up\", Help: \"last scrape was able to connect to the server: 1 for yes, 0 for no\",\n\t})\n\te.version = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tName: \"version\", Help: \"server version number\",\n\t})\n\te.recovery = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tName: \"in_recovery\", Help: \"server is in recovery mode? 1 for yes 0 for no\",\n\t})\n\n\t// build info\n\tbuildInfoLabels := prometheus.Labels{\n\t\t\"version\":   Version,\n\t\t\"revision\":  Revision,\n\t\t\"branch\":    Branch,\n\t\t\"builddate\": BuildDate,\n\t\t\"goversion\": GoVersion,\n\t\t\"goos\":      GOOS,\n\t\t\"goarch\":    GOARCH,\n\t}\n\t// Merge with user-provided constant labels\n\tfor k, v := range e.constLabels {\n\t\tbuildInfoLabels[k] = v\n\t}\n\te.buildInfo = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace:   e.namespace,\n\t\tName:        \"exporter_build_info\",\n\t\tHelp:        \"A metric with a constant '1' value labeled with version, revision, branch, goversion, builddate, goos, and goarch from which pg_exporter was built.\",\n\t\tConstLabels: buildInfoLabels,\n\t})\n\t// Set the build info value\n\te.buildInfo.Set(1)\n\n\t// exporter level metrics\n\te.exporterUp = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tSubsystem: \"exporter\", Name: \"up\", Help: \"always be 1 if your could retrieve metrics\",\n\t})\n\te.exporterUptime = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tSubsystem: \"exporter\", Name: \"uptime\", Help: \"seconds since exporter primary server inited\",\n\t})\n\te.scrapeTotalCount = prometheus.NewCounter(prometheus.CounterOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tSubsystem: \"exporter\", Name: \"scrape_total_count\", Help: \"times exporter was scraped for metrics\",\n\t})\n\te.scrapeErrorCount = prometheus.NewCounter(prometheus.CounterOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tSubsystem: \"exporter\", Name: \"scrape_error_count\", Help: \"times exporter was scraped for metrics and failed\",\n\t})\n\te.scrapeDuration = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tSubsystem: \"exporter\", Name: \"scrape_duration\", Help: \"seconds exporter spending on scraping\",\n\t})\n\te.lastScrapeTime = prometheus.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: e.namespace, ConstLabels: e.constLabels,\n\t\tSubsystem: \"exporter\", Name: \"last_scrape_time\", Help: \"last scrape timestamp\",\n\t})\n\n\t// Dynamic per-server/per-query series.\n\t// These are described via *prometheus.Desc and emitted as const metrics on each scrape.\n\te.serverScrapeDurationDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_server\", \"scrape_duration\"),\n\t\t\"seconds exporter server spending on scraping last scrape\",\n\t\t[]string{\"datname\"}, e.constLabels,\n\t)\n\te.serverScrapeTotalSecondsDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_server\", \"scrape_total_seconds\"),\n\t\t\"cumulative total seconds exporter server spending on scraping\",\n\t\t[]string{\"datname\"}, e.constLabels,\n\t)\n\te.serverScrapeTotalCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_server\", \"scrape_total_count\"),\n\t\t\"times exporter server was scraped for metrics\",\n\t\t[]string{\"datname\"}, e.constLabels,\n\t)\n\te.serverScrapeErrorCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_server\", \"scrape_error_count\"),\n\t\t\"cumulative times exporter server scrape failed (fatal scrape failures only)\",\n\t\t[]string{\"datname\"}, e.constLabels,\n\t)\n\n\te.queryCacheTTLDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"cache_ttl\"),\n\t\t\"times to live of query cache\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\te.queryScrapeTotalCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"scrape_total_count\"),\n\t\t\"times exporter server was scraped for metrics\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\te.queryScrapeErrorCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"scrape_error_count\"),\n\t\t\"times the query failed\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\te.queryScrapePredicateSkipCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"scrape_predicate_skip_count\"),\n\t\t\"times the query was skipped due to a predicate returning false\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\te.queryScrapeDurationDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"scrape_duration\"),\n\t\t\"seconds query spending on scraping\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\te.queryScrapeMetricCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"scrape_metric_count\"),\n\t\t\"numbers of metrics been scraped from this query\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\te.queryScrapeHitCountDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(e.namespace, \"exporter_query\", \"scrape_hit_count\"),\n\t\t\"numbers been scraped from this query\",\n\t\t[]string{\"datname\", \"query\"}, e.constLabels,\n\t)\n\n\te.exporterUp.Set(1) // always be true\n\te.healthStatus.Store(healthStatusUnknown)\n}\n\nfunc (e *Exporter) collectInternalMetrics(ch chan<- prometheus.Metric) {\n\tch <- e.up\n\tch <- e.version\n\tch <- e.recovery\n\n\tch <- e.buildInfo\n\tch <- e.exporterUp\n\tch <- e.exporterUptime\n\tch <- e.lastScrapeTime\n\tch <- e.scrapeTotalCount\n\tch <- e.scrapeErrorCount\n\tch <- e.scrapeDuration\n}\n\n/* ================ Exporter Creation ================ */\n\n// NewExporter construct a PG Exporter instance for given dsn\nfunc NewExporter(dsn string, opts ...ExporterOpt) (e *Exporter, err error) {\n\te = &Exporter{dsn: dsn}\n\te.servers = make(map[string]*Server)\n\tfor _, opt := range opts {\n\t\topt(e)\n\t}\n\tif len(e.configPath) > 0 && e.configReader != nil {\n\t\treturn nil, errors.New(\"exporter configPath and configReader options are mutually exclusive\")\n\t}\n\tif len(e.configPath) > 0 {\n\t\tif e.queries, err = LoadConfig(e.configPath); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"fail loading config file %s: %w\", e.configPath, err)\n\t\t}\n\t}\n\tif e.configReader != nil {\n\t\tb, rerr := io.ReadAll(e.configReader)\n\t\tif rerr != nil {\n\t\t\treturn nil, fmt.Errorf(\"fail reading config file: %w\", rerr)\n\t\t}\n\t\tif e.queries, err = ParseConfig(b); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"fail parsing config file: %w\", err)\n\t\t}\n\t\tif err := FinalizeQueries(e.queries, \"<reader>\"); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"fail finalizing config: %w\", err)\n\t\t}\n\t}\n\n\tif err := validateConstLabelConflicts(e.constLabels, e.queries, e.disableIntro); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid constant labels: %w\", err)\n\t}\n\n\tlogDebugf(\"exporter init with %d queries\", len(e.queries))\n\n\t// note here the server is still not connected. it will trigger connecting when being scraped\n\te.server = NewServer(\n\t\tdsn,\n\t\tWithQueries(e.queries),\n\t\tWithConstLabel(e.constLabels),\n\t\tWithCachePolicy(e.disableCache),\n\t\tWithServerTags(e.tags),\n\t\tWithServerConnectTimeout(e.connectTimeout),\n\t)\n\n\t// register db change callback\n\tif e.autoDiscovery {\n\t\tlogInfof(\"auto discovery is enabled, excludeDatabase=%v, includeDatabase=%v\", e.excludeDatabase, e.includeDatabase)\n\t\te.server.onDatabaseChange = e.OnDatabaseChange\n\t}\n\n\tlogDebugf(\"check primary server connectivity\")\n\t// Best-effort check: we don't block the exporter startup if the target is down.\n\t// The actual scrape path will reconnect and re-plan when the target comes back.\n\tif err = e.server.Check(); err != nil {\n\t\tif e.failFast {\n\t\t\treturn nil, fmt.Errorf(\"fail connecting to primary server: %w\", err)\n\t\t}\n\t\tlogErrorf(\"fail connecting to primary server: %s (startup will continue)\", err.Error())\n\t\t// NewExporter has named return values; make sure we don't propagate the\n\t\t// precheck error when failFast is disabled.\n\t\terr = nil\n\t}\n\te.pgbouncerMode = e.server.PgbouncerMode\n\te.setupInternalMetrics()\n\te.updateHealthStateFromServer()\n\t// Always start the health loop so probes can recover once the target becomes reachable.\n\te.startHealthLoop()\n\n\treturn\n}\n\n// OnDatabaseChange will spawn new Server when new database is created\n// and destroy Server if corresponding database is dropped\nfunc (e *Exporter) OnDatabaseChange(change map[string]bool) {\n\tfor dbname, add := range change {\n\t\tverb := \"del\"\n\t\tif add {\n\t\t\tverb = \"add\"\n\t\t}\n\n\t\tif dbname == e.server.Database {\n\t\t\tcontinue // skip primary database change\n\t\t}\n\t\tif _, found := e.excludeDatabase[dbname]; found {\n\t\t\tlogInfof(\"skip database change: %v %v according to in excluded database list\", verb, dbname)\n\t\t\tcontinue // skip exclude databases changes\n\t\t}\n\t\tif len(e.includeDatabase) > 0 {\n\t\t\tif _, found := e.includeDatabase[dbname]; !found {\n\t\t\t\tlogInfof(\"skip database change: %v %v according to not in include database list\", verb, dbname)\n\t\t\t\tcontinue // skip non-include databases changes\n\t\t\t}\n\t\t}\n\t\tif add {\n\t\t\t// spawn new server\n\t\t\te.CreateServer(dbname)\n\t\t} else {\n\t\t\t// close old server\n\t\t\te.RemoveServer(dbname)\n\t\t}\n\t}\n}\n\n// CreateServer will spawn new database server from a database name combined with existing dsn string\n// This happens when a database is newly created\nfunc (e *Exporter) CreateServer(dbname string) {\n\tnewDSN := ReplaceDatname(e.dsn, dbname)\n\tlogInfof(\"spawn new server for database %s : %s\", dbname, ShadowPGURL(newDSN))\n\tnewServer := NewServer(\n\t\tnewDSN,\n\t\tWithQueries(e.queries),\n\t\tWithConstLabel(e.constLabels),\n\t\tWithCachePolicy(e.disableCache),\n\t\tWithServerTags(e.tags),\n\t\tWithServerConnectTimeout(e.connectTimeout),\n\t)\n\tnewServer.Forked = true // important!\n\n\te.sLock.Lock()\n\te.servers[dbname] = newServer\n\tlogInfof(\"database %s is installed due to auto-discovery\", dbname)\n\tdefer e.sLock.Unlock()\n}\n\n// RemoveServer will destroy Server from Exporter according to database name\n// This happens when a database is dropped\nfunc (e *Exporter) RemoveServer(dbname string) {\n\te.sLock.Lock()\n\tsrv, ok := e.servers[dbname]\n\tif ok {\n\t\tdelete(e.servers, dbname)\n\t}\n\te.sLock.Unlock()\n\n\tif ok && srv != nil {\n\t\tif srv.DB != nil {\n\t\t\t// Close asynchronously to avoid blocking the scrape path.\n\t\t\tgo func(dbname string, srv *Server) {\n\t\t\t\tif err := srv.Close(); err != nil {\n\t\t\t\t\tlogErrorf(\"fail closing removed database server %s: %s\", dbname, err.Error())\n\t\t\t\t}\n\t\t\t}(dbname, srv)\n\t\t}\n\t}\n\tlogWarnf(\"database %s is removed due to auto-discovery\", dbname)\n}\n\n// IterateServer will get snapshot of extra servers\nfunc (e *Exporter) IterateServer() (res []*Server) {\n\te.sLock.RLock()\n\tdefer e.sLock.RUnlock()\n\tif len(e.servers) == 0 {\n\t\treturn nil\n\t}\n\tres = make([]*Server, 0, len(e.servers))\n\tfor _, srv := range e.servers {\n\t\tres = append(res, srv)\n\t}\n\treturn\n}\n\n// ExporterOpt configures Exporter\ntype ExporterOpt func(*Exporter)\n\n// WithConfig add config path to Exporter\nfunc WithConfig(configPath string) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.configPath = configPath\n\t}\n}\n\n// WithConfigReader uses a the provided reader to load a configuration for the Exporter\nfunc WithConfigReader(reader io.Reader) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.configReader = reader\n\t}\n}\n\n// WithConstLabels add const label to exporter. 0 length label returns nil\nfunc WithConstLabels(s string) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.constLabels = parseConstLabels(s)\n\t}\n}\n\n// WithCacheDisabled set cache param to exporter\nfunc WithCacheDisabled(disableCache bool) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.disableCache = disableCache\n\t}\n}\n\n// WithIntroDisabled will pass introspection option to server\nfunc WithIntroDisabled(disableIntro bool) ExporterOpt {\n\treturn func(s *Exporter) {\n\t\ts.disableIntro = disableIntro\n\t}\n}\n\n// WithFailFast marks exporter fail instead of waiting during start-up\nfunc WithFailFast(failFast bool) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.failFast = failFast\n\t}\n}\n\n// WithNamespace will specify metric namespace, by default is pg or pgbouncer\nfunc WithNamespace(namespace string) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.namespace = namespace\n\t}\n}\n\n// WithTags will register given tags to Exporter and all belonged servers\nfunc WithTags(tags string) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.tags = parseCSV(tags)\n\t}\n}\n\n// WithAutoDiscovery configures exporter with excluded database\nfunc WithAutoDiscovery(flag bool) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.autoDiscovery = flag\n\t}\n}\n\n// WithExcludeDatabase configures exporter with excluded database\nfunc WithExcludeDatabase(excludeStr string) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\texclMap := make(map[string]bool)\n\t\texclList := parseCSV(excludeStr)\n\t\tfor _, item := range exclList {\n\t\t\texclMap[item] = true\n\t\t}\n\t\te.excludeDatabase = exclMap\n\t}\n}\n\n// WithIncludeDatabase configures exporter with included database\nfunc WithIncludeDatabase(includeStr string) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\tinclMap := make(map[string]bool)\n\t\tinclList := parseCSV(includeStr)\n\t\tfor _, item := range inclList {\n\t\t\tinclMap[item] = true\n\t\t}\n\t\te.includeDatabase = inclMap\n\t}\n}\n\n// WithConnectTimeout will specify timeout for conn pre-check.\n// It's useful to increase this value when monitoring a remote instance (cross DC, cross AZ)\nfunc WithConnectTimeout(timeout int) ExporterOpt {\n\treturn func(e *Exporter) {\n\t\te.connectTimeout = timeout\n\t}\n}\n\n/* ================ Exporter RESTAPI ================ */\n\nfunc currentExporter() *Exporter {\n\tif target := currentExporterPt.Load(); target != nil {\n\t\treturn target\n\t}\n\tReloadLock.RLock()\n\tdefer ReloadLock.RUnlock()\n\treturn PgExporter\n}\n\n// ExplainFunc expose explain document\nfunc (e *Exporter) ExplainFunc(w http.ResponseWriter, r *http.Request) {\n\t// The explain output is plain text. Serving it as text/plain avoids\n\t// browsers interpreting config content as HTML.\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\ttarget := currentExporter()\n\tif target == nil {\n\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t_, _ = w.Write([]byte(\"exporter unavailable\"))\n\t\treturn\n\t}\n\t_, _ = w.Write([]byte(target.Explain()))\n}\n\n// StatFunc exposes plain text runtime statistics.\nfunc (e *Exporter) StatFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=UTF-8\")\n\ttarget := currentExporter()\n\tif target == nil {\n\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t_, _ = w.Write([]byte(\"exporter unavailable\"))\n\t\treturn\n\t}\n\t_, _ = w.Write([]byte(target.Stat()))\n}\n\n// UpCheckFunc tells whether target instance is alive, 200 up 503 down\nfunc (e *Exporter) UpCheckFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\ttarget := currentExporter()\n\tif target == nil {\n\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t_, _ = w.Write([]byte(\"unknown\"))\n\t\treturn\n\t}\n\n\t// Note: /up reports the latest state from the background health loop.\n\t// It does not actively probe the target on each HTTP request.\n\tstatus := target.Status()\n\tif target.Up() {\n\t\tw.WriteHeader(200)\n\t\t_, _ = w.Write([]byte(status))\n\t} else {\n\t\tw.WriteHeader(503)\n\t\t_, _ = w.Write([]byte(status))\n\t}\n}\n\n// PrimaryCheckFunc tells whether target instance is a primary, 200 yes 404 no 503 unknown\nfunc (e *Exporter) PrimaryCheckFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\ttarget := currentExporter()\n\tif target == nil {\n\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t_, _ = w.Write([]byte(\"unknown\"))\n\t\treturn\n\t}\n\n\tstatus := target.Status()\n\tif target.Up() {\n\t\tif target.Recovery() {\n\t\t\tw.WriteHeader(404)\n\t\t\t_, _ = w.Write([]byte(status))\n\t\t} else {\n\t\t\tw.WriteHeader(200)\n\t\t\t_, _ = w.Write([]byte(status))\n\t\t}\n\t} else {\n\t\tw.WriteHeader(503)\n\t\t_, _ = w.Write([]byte(status))\n\t}\n}\n\n// ReplicaCheckFunc tells whether target instance is a replica, 200 yes 404 no 503 unknown\nfunc (e *Exporter) ReplicaCheckFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\ttarget := currentExporter()\n\tif target == nil {\n\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t_, _ = w.Write([]byte(\"unknown\"))\n\t\treturn\n\t}\n\n\tstatus := target.Status()\n\tif target.Up() {\n\t\tif target.Recovery() {\n\t\t\tw.WriteHeader(200)\n\t\t\t_, _ = w.Write([]byte(status))\n\t\t} else {\n\t\t\tw.WriteHeader(404)\n\t\t\t_, _ = w.Write([]byte(status))\n\t\t}\n\t} else {\n\t\tw.WriteHeader(503)\n\t\t_, _ = w.Write([]byte(status))\n\t}\n}\n\n// VersionFunc responding current pg_exporter version\nfunc VersionFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tpayload := fmt.Sprintf(\"pg_exporter version %s\\nrevision: %s\\nbranch: %s\\ngo version: %s\\nbuild date: %s\\ngoos: %s\\ngoarch: %s\",\n\t\tVersion, Revision, Branch, GoVersion, BuildDate, GOOS, GOARCH)\n\t_, _ = w.Write([]byte(payload))\n}\n\n// TitleFunc responding a description message\nfunc TitleFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/html; charset=UTF-8\")\n\t_, _ = w.Write([]byte(`<html><head><title>PG Exporter</title></head><body><h1>PG Exporter</h1><p><a href='` + *metricPath + `'>Metrics</a></p></body></html>`))\n}\n\n// ReloadFunc handles reload request\nfunc ReloadFunc(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tif r.Method != http.MethodPost && r.Method != http.MethodGet {\n\t\tw.Header().Set(\"Allow\", \"GET, POST\")\n\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t_, _ = w.Write([]byte(\"method not allowed\"))\n\t\treturn\n\t}\n\tif err := Reload(); err != nil {\n\t\tw.WriteHeader(500)\n\t\t_, _ = w.Write([]byte(fmt.Sprintf(\"fail to reload: %s\", err.Error())))\n\t} else {\n\t\t_, _ = w.Write([]byte(`server reloaded`))\n\t}\n}\n"
  },
  {
    "path": "exporter/exporter_handlers_opts_test.go",
    "content": "package exporter\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"testing\"\n)\n\nfunc TestExporterOptionHelpers(t *testing.T) {\n\te := &Exporter{}\n\n\tWithConfig(\"/tmp/c.yml\")(e)\n\tWithConstLabels(\"k=v,env=prod\")(e)\n\tWithCacheDisabled(true)(e)\n\tWithIntroDisabled(true)(e)\n\tWithFailFast(true)(e)\n\tWithNamespace(\"custom\")(e)\n\tWithTags(\"a,b\")(e)\n\tWithAutoDiscovery(true)(e)\n\tWithExcludeDatabase(\"template0,template1\")(e)\n\tWithIncludeDatabase(\"app,metrics\")(e)\n\tWithConnectTimeout(500)(e)\n\n\tif e.configPath != \"/tmp/c.yml\" {\n\t\tt.Fatalf(\"configPath = %s\", e.configPath)\n\t}\n\tif e.constLabels[\"k\"] != \"v\" || e.constLabels[\"env\"] != \"prod\" {\n\t\tt.Fatalf(\"constLabels = %v\", e.constLabels)\n\t}\n\tif !e.disableCache || !e.disableIntro || !e.failFast || !e.autoDiscovery {\n\t\tt.Fatalf(\"boolean options not applied: cache=%v intro=%v failFast=%v auto=%v\", e.disableCache, e.disableIntro, e.failFast, e.autoDiscovery)\n\t}\n\tif e.namespace != \"custom\" {\n\t\tt.Fatalf(\"namespace = %s\", e.namespace)\n\t}\n\tif len(e.tags) != 2 || e.tags[0] != \"a\" || e.tags[1] != \"b\" {\n\t\tt.Fatalf(\"tags = %#v\", e.tags)\n\t}\n\tif !e.excludeDatabase[\"template0\"] || !e.excludeDatabase[\"template1\"] {\n\t\tt.Fatalf(\"excludeDatabase = %v\", e.excludeDatabase)\n\t}\n\tif !e.includeDatabase[\"app\"] || !e.includeDatabase[\"metrics\"] {\n\t\tt.Fatalf(\"includeDatabase = %v\", e.includeDatabase)\n\t}\n\tif e.connectTimeout != 500 {\n\t\tt.Fatalf(\"connectTimeout = %d\", e.connectTimeout)\n\t}\n}\n\nfunc TestPublicHandlers(t *testing.T) {\n\treq := httptest.NewRequest(http.MethodGet, \"/\", nil)\n\n\twTitle := httptest.NewRecorder()\n\tTitleFunc(wTitle, req)\n\tif wTitle.Code != http.StatusOK || !strings.Contains(wTitle.Body.String(), \"PG Exporter\") {\n\t\tt.Fatalf(\"TitleFunc unexpected response: code=%d body=%s\", wTitle.Code, wTitle.Body.String())\n\t}\n\n\twVersion := httptest.NewRecorder()\n\tVersionFunc(wVersion, req)\n\tif wVersion.Code != http.StatusOK || !strings.Contains(wVersion.Body.String(), \"pg_exporter version\") {\n\t\tt.Fatalf(\"VersionFunc unexpected response: code=%d body=%s\", wVersion.Code, wVersion.Body.String())\n\t}\n}\n\nfunc TestExplainAndStatHandlersWhenExporterUnavailable(t *testing.T) {\n\torigin := PgExporter\n\tsetCurrentExporter(nil)\n\tdefer setCurrentExporter(origin)\n\n\te := &Exporter{}\n\treq := httptest.NewRequest(http.MethodGet, \"/explain\", nil)\n\n\twExplain := httptest.NewRecorder()\n\te.ExplainFunc(wExplain, req)\n\tif wExplain.Code != http.StatusServiceUnavailable {\n\t\tt.Fatalf(\"ExplainFunc status = %d, want 503\", wExplain.Code)\n\t}\n\n\twStat := httptest.NewRecorder()\n\te.StatFunc(wStat, req)\n\tif wStat.Code != http.StatusServiceUnavailable {\n\t\tt.Fatalf(\"StatFunc status = %d, want 503\", wStat.Code)\n\t}\n}\n\nfunc TestHealthHandlersPassiveModeNoActiveProbe(t *testing.T) {\n\tvar checkCount atomic.Int32\n\ts := &Server{\n\t\tDatabase:  \"postgres\",\n\t\tDatabases: map[string]bool{\"postgres\": true},\n\t}\n\ts.beforeScrape = func(s *Server) error {\n\t\tcheckCount.Add(1)\n\t\ts.UP = false\n\t\ts.Recovery = false\n\t\treturn nil\n\t}\n\n\te := &Exporter{server: s}\n\te.updateHealthState(true, false) // cached primary/up state\n\torigin := PgExporter\n\tsetCurrentExporter(e)\n\tdefer setCurrentExporter(origin)\n\n\treq := httptest.NewRequest(http.MethodGet, \"/up\", nil)\n\tw := httptest.NewRecorder()\n\te.UpCheckFunc(w, req)\n\n\tif w.Code != http.StatusOK {\n\t\tt.Fatalf(\"passive health check should use cached up status, got %d\", w.Code)\n\t}\n\tif checkCount.Load() != 0 {\n\t\tt.Fatalf(\"passive health check should not probe DB, count=%d\", checkCount.Load())\n\t}\n}\n"
  },
  {
    "path": "exporter/global.go",
    "content": "package exporter\n\nimport (\n\t\"log/slog\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\n/* ================ Parameters ================ */\n\n// Version is read by make build procedure\nvar Version = \"1.2.2\"\n\n// Build information. Populated at build-time.\nvar (\n\tBranch    = \"main\"\n\tRevision  = \"HEAD\"\n\tBuildDate = \"20250421212100\" // will be overwritten during release\n\tGoVersion = runtime.Version()\n\tGOOS      = runtime.GOOS\n\tGOARCH    = runtime.GOARCH\n)\n\nvar defaultPGURL = \"postgresql:///?sslmode=disable\"\n\n/* ================ Global Vars ================ */\n\n// PgExporter is the global singleton of Exporter\nvar (\n\tPgExporter        *Exporter\n\tcurrentExporterPt atomic.Pointer[Exporter]\n\tReloadLock        sync.RWMutex\n\tLogger            = slog.Default()\n)\n\nfunc setCurrentExporter(e *Exporter) {\n\tPgExporter = e\n\tcurrentExporterPt.Store(e)\n}\n"
  },
  {
    "path": "exporter/health_state_test.go",
    "content": "package exporter\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/lib/pq\"\n)\n\nfunc TestIsPostgresStartupError(t *testing.T) {\n\tif !isPostgresStartupError(&pq.Error{Code: pq.ErrorCode(pgSQLStateCannotConnectNow)}) {\n\t\tt.Fatal(\"expected SQLSTATE 57P03 to be recognized as startup error\")\n\t}\n\n\twrapped := fmt.Errorf(\"wrapped: %w\", &pq.Error{Code: pq.ErrorCode(pgSQLStateCannotConnectNow)})\n\tif !isPostgresStartupError(wrapped) {\n\t\tt.Fatal(\"expected wrapped SQLSTATE 57P03 to be recognized as startup error\")\n\t}\n\n\tif isPostgresStartupError(errors.New(\"plain error\")) {\n\t\tt.Fatal(\"plain error should not be recognized as startup error\")\n\t}\n\tif isPostgresStartupError(&pq.Error{Code: \"08006\"}) {\n\t\tt.Fatal(\"non-57P03 postgres error should not be recognized as startup error\")\n\t}\n}\n\nfunc TestUpdateHealthStateWithStartup(t *testing.T) {\n\te := &Exporter{}\n\n\te.updateHealthStateWithStartup(false, false, true)\n\tif e.Up() {\n\t\tt.Fatal(\"startup state should not be considered up\")\n\t}\n\tif e.Recovery() {\n\t\tt.Fatal(\"startup state should not expose recovery=true\")\n\t}\n\tif got := e.Status(); got != \"starting\" {\n\t\tt.Fatalf(\"status = %s, want starting\", got)\n\t}\n\n\te.updateHealthStateWithStartup(false, false, false)\n\tif got := e.Status(); got != \"down\" {\n\t\tt.Fatalf(\"status = %s, want down\", got)\n\t}\n\n\te.updateHealthStateWithStartup(true, true, false)\n\tif got := e.Status(); got != \"replica\" {\n\t\tt.Fatalf(\"status = %s, want replica\", got)\n\t}\n\n\te.updateHealthStateWithStartup(true, false, false)\n\tif got := e.Status(); got != \"primary\" {\n\t\tt.Fatalf(\"status = %s, want primary\", got)\n\t}\n}\n"
  },
  {
    "path": "exporter/main.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n\t\"github.com/prometheus/exporter-toolkit/web\"\n)\n\n// DryRun will explain all query fetched from configs\nfunc DryRun() {\n\tconfigs, err := LoadConfig(*configPath)\n\tif err != nil {\n\t\tlogErrorf(\"fail loading config %s, %v\", *configPath, err)\n\t\tos.Exit(1)\n\t}\n\n\tvar queries []*Query\n\tfor _, query := range configs {\n\t\tqueries = append(queries, query)\n\t}\n\tsort.Slice(queries, func(i, j int) bool {\n\t\treturn queries[i].Priority < queries[j].Priority\n\t})\n\tfor _, query := range queries {\n\t\tfmt.Println(query.Explain())\n\t}\n\tfmt.Println()\n\tos.Exit(0)\n\n}\n\n// Reload will launch a new pg exporter instance\nfunc Reload() error {\n\tReloadLock.Lock()\n\tdefer ReloadLock.Unlock()\n\tlogDebugf(\"reload request received, reloading configuration\")\n\n\tif *configPath == \"\" {\n\t\treturn fmt.Errorf(\"no valid config path\")\n\t}\n\tqueries, err := LoadConfig(*configPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fail loading config %s: %w\", *configPath, err)\n\t}\n\n\ttarget := PgExporter\n\tif target == nil {\n\t\treturn fmt.Errorf(\"exporter unavailable\")\n\t}\n\n\tif err := validateConstLabelConflicts(target.constLabels, queries, target.disableIntro); err != nil {\n\t\treturn fmt.Errorf(\"invalid configuration with current constant labels: %w\", err)\n\t}\n\n\t// Block scrapes while we swap the query set and invalidate plans.\n\ttarget.lock.Lock()\n\tdefer target.lock.Unlock()\n\n\ttarget.queries = queries\n\n\t// Update queries for primary + discovered servers, and force re-plan on next scrape.\n\tservers := target.IterateServer()\n\tif target.server != nil {\n\t\tservers = append(servers, target.server)\n\t}\n\tfor _, s := range servers {\n\t\tif s == nil {\n\t\t\tcontinue\n\t\t}\n\t\ts.lock.Lock()\n\t\ts.queries = queries\n\t\ts.Collectors = nil\n\t\ts.Planned = false\n\t\ts.ResetStats()\n\t\ts.lock.Unlock()\n\t}\n\n\tlogInfof(\"server reloaded, %d queries applied\", len(queries))\n\treturn nil\n}\n\n// Run pg_exporter\nfunc Run() {\n\tParseArgs()\n\n\t// Clean up unsupported libpq environment variables that would cause panic\n\t// lib/pq driver does not support these PostgreSQL environment variables\n\t// and will panic if they are set. We clear them to ensure stable operation.\n\t// See: https://github.com/lib/pq/blob/master/conn.go#L2019\n\tunsupportedEnvs := []string{\n\t\t\"PGSYSCONFDIR\",  // PostgreSQL system configuration directory\n\t\t\"PGSERVICEFILE\", // PostgreSQL connection service file\n\t\t\"PGSERVICE\",     // PostgreSQL service name\n\t\t\"PGLOCALEDIR\",   // PostgreSQL locale directory\n\t\t\"PGREALM\",       // Kerberos realm\n\t}\n\n\tfor _, env := range unsupportedEnvs {\n\t\tif val := os.Getenv(env); val != \"\" {\n\t\t\tlogWarnf(\"clearing unsupported environment variable %s=%s (lib/pq limitation)\", env, val)\n\t\t\tos.Unsetenv(env)\n\t\t}\n\t}\n\n\t// explain config only\n\tif *dryRun {\n\t\tDryRun()\n\t}\n\n\tif *configPath == \"\" {\n\t\tLogger.Error(\"no valid config path, exit\")\n\t\tos.Exit(1)\n\t}\n\n\tif len(*webConfig.WebListenAddresses) == 0 {\n\t\tLogger.Error(\"invalid listen address\", \"addresses\", *webConfig.WebListenAddresses)\n\t\tos.Exit(1)\n\t}\n\tlistenAddr := (*webConfig.WebListenAddresses)[0]\n\n\t// Create exporter. It will connect on scrape and keep health probes running in background.\n\tvar err error\n\tnewExporter, err := NewExporter(\n\t\t*pgURL,\n\t\tWithConfig(*configPath),\n\t\tWithConstLabels(*constLabels),\n\t\tWithCacheDisabled(*disableCache),\n\t\tWithIntroDisabled(*disableIntro),\n\t\tWithFailFast(*failFast),\n\t\tWithNamespace(*exporterNamespace),\n\t\tWithAutoDiscovery(*autoDiscovery),\n\t\tWithExcludeDatabase(*excludeDatabase),\n\t\tWithIncludeDatabase(*includeDatabase),\n\t\tWithTags(*serverTags),\n\t\tWithConnectTimeout(*connectTimeout),\n\t)\n\tif err != nil {\n\t\tlogErrorf(\"fail creating pg_exporter: %s\", err.Error())\n\t\tos.Exit(2)\n\t}\n\tsetCurrentExporter(newExporter)\n\n\t// trigger a manual planning before explain\n\tif *explainOnly {\n\t\tPgExporter.server.Plan()\n\t\tfmt.Println(PgExporter.Explain())\n\t\tos.Exit(0)\n\t}\n\n\tprometheus.MustRegister(PgExporter)\n\tdefer PgExporter.Close()\n\n\t// reload conf when receiving configured reload signals (SIGHUP, and SIGUSR1 on non-Windows)\n\tsigs := make(chan os.Signal, 1)\n\tsignal.Notify(sigs, reloadSignals...)\n\tgo func() {\n\t\tfor sig := range sigs {\n\t\t\tlogInfof(\"%v received, reloading\", sig)\n\t\t\tif err := Reload(); err != nil {\n\t\t\t\tlogErrorf(\"reload failed: %s\", err.Error())\n\t\t\t}\n\t\t}\n\t}()\n\n\t/* ================ REST API ================ */\n\t// basic\n\thttp.HandleFunc(\"/\", TitleFunc)\n\thttp.HandleFunc(\"/version\", VersionFunc)\n\t// reload\n\thttp.HandleFunc(\"/reload\", ReloadFunc)\n\t// explain & stat\n\thttp.HandleFunc(\"/stat\", PgExporter.StatFunc)\n\thttp.HandleFunc(\"/explain\", PgExporter.ExplainFunc)\n\t// alive\n\thttp.HandleFunc(\"/up\", PgExporter.UpCheckFunc)\n\thttp.HandleFunc(\"/read\", PgExporter.UpCheckFunc)\n\thttp.HandleFunc(\"/health\", PgExporter.UpCheckFunc)\n\thttp.HandleFunc(\"/liveness\", PgExporter.UpCheckFunc)\n\thttp.HandleFunc(\"/readiness\", PgExporter.UpCheckFunc)\n\t// primary\n\thttp.HandleFunc(\"/primary\", PgExporter.PrimaryCheckFunc)\n\thttp.HandleFunc(\"/leader\", PgExporter.PrimaryCheckFunc)\n\thttp.HandleFunc(\"/master\", PgExporter.PrimaryCheckFunc)\n\thttp.HandleFunc(\"/read-write\", PgExporter.PrimaryCheckFunc)\n\thttp.HandleFunc(\"/rw\", PgExporter.PrimaryCheckFunc)\n\t// replica\n\thttp.HandleFunc(\"/replica\", PgExporter.ReplicaCheckFunc)\n\thttp.HandleFunc(\"/standby\", PgExporter.ReplicaCheckFunc)\n\thttp.HandleFunc(\"/slave\", PgExporter.ReplicaCheckFunc)\n\thttp.HandleFunc(\"/read-only\", PgExporter.ReplicaCheckFunc)\n\thttp.HandleFunc(\"/ro\", PgExporter.ReplicaCheckFunc)\n\n\thttp.Handle(*metricPath, promhttp.Handler())\n\n\tlogInfof(\"pg_exporter for %s start, listen on %s%s\", ShadowPGURL(*pgURL), listenAddr, *metricPath)\n\n\tsrv := &http.Server{\n\t\tReadHeaderTimeout: 5 * time.Second,\n\t\tReadTimeout:       10 * time.Second,\n\t\tWriteTimeout:      30 * time.Second,\n\t\tIdleTimeout:       2 * time.Minute,\n\t}\n\tif err := web.ListenAndServe(srv, webConfig, Logger); err != nil {\n\t\tlogFatalf(\"http server failed: %s\", err.Error())\n\t}\n\n}\n"
  },
  {
    "path": "exporter/metrics_lifecycle_test.go",
    "content": "package exporter\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\nfunc makeCachedCollectorForServer(s *Server, name string, val float64) *Collector {\n\tq := makeGaugeQuery(name, 1)\n\tc := NewCollector(q, s)\n\tc.TTL = 3600\n\tc.lastScrape = time.Now()\n\tmetric := prometheus.MustNewConstMetric(c.descriptors[\"value\"], prometheus.GaugeValue, val, \"db\")\n\tc.result = []prometheus.Metric{metric}\n\tc.err = nil\n\treturn c\n}\n\nfunc TestExporterCollectAndInternalMetrics(t *testing.T) {\n\tprimary := NewServer(\"postgresql://u:p@localhost:5432/postgres\")\n\tprimary.beforeScrape = func(s *Server) error {\n\t\ts.UP = true\n\t\ts.Version = 160000\n\t\ts.Recovery = false\n\t\treturn nil\n\t}\n\tprimary.Planned = true\n\tprimary.Collectors = []*Collector{makeCachedCollectorForServer(primary, \"q_primary\", 1)}\n\tprimary.ResetStats()\n\n\textra := NewServer(\"postgresql://u:p@localhost:5432/otherdb\")\n\textra.Forked = true\n\textra.beforeScrape = func(s *Server) error {\n\t\ts.UP = true\n\t\ts.Version = 160000\n\t\ts.Recovery = false\n\t\treturn nil\n\t}\n\textra.Planned = true\n\textra.Collectors = []*Collector{makeCachedCollectorForServer(extra, \"q_extra\", 2)}\n\textra.ResetStats()\n\n\te := &Exporter{\n\t\tserver:  primary,\n\t\tservers: map[string]*Server{\"otherdb\": extra},\n\t}\n\te.setupInternalMetrics()\n\n\tch := make(chan prometheus.Metric, 256)\n\te.Collect(ch)\n\n\tif !e.Up() {\n\t\tt.Fatal(\"Exporter should be UP after successful collect\")\n\t}\n\tif e.Status() != \"primary\" {\n\t\tt.Fatalf(\"Exporter status = %s, want primary\", e.Status())\n\t}\n}\n\nfunc TestExporterDescribeAndCloseNoPanic(t *testing.T) {\n\ts := NewServer(\"postgresql://u:p@localhost:5432/postgres\")\n\ts.beforeScrape = func(s *Server) error {\n\t\ts.UP = true\n\t\treturn nil\n\t}\n\ts.Planned = true\n\ts.Collectors = []*Collector{makeCachedCollectorForServer(s, \"q\", 1)}\n\ts.ResetStats()\n\n\te := &Exporter{\n\t\tserver:  s,\n\t\tservers: map[string]*Server{},\n\t}\n\te.setupInternalMetrics()\n\n\tdescCh := make(chan *prometheus.Desc, 32)\n\te.Describe(descCh)\n\tif len(descCh) != 0 {\n\t\tt.Fatalf(\"Describe should not emit descriptors for a dynamic/unchecked exporter, got %d\", len(descCh))\n\t}\n\n\t// server DB pointers are nil in this synthetic test; Close should not panic.\n\te.Close()\n}\n\nfunc TestDisableIntroSuppressesInternalMetrics(t *testing.T) {\n\ts := NewServer(\"postgresql://u:p@localhost:5432/postgres\")\n\ts.beforeScrape = func(s *Server) error {\n\t\ts.UP = true\n\t\ts.Version = 160000\n\t\ts.Recovery = false\n\t\treturn nil\n\t}\n\ts.Planned = true\n\ts.Collectors = []*Collector{makeCachedCollectorForServer(s, \"q\", 1)}\n\ts.ResetStats()\n\n\te := &Exporter{\n\t\tserver:       s,\n\t\tservers:      map[string]*Server{},\n\t\tdisableIntro: true,\n\t}\n\te.setupInternalMetrics()\n\n\tr := prometheus.NewRegistry()\n\tif err := r.Register(e); err != nil {\n\t\tt.Fatalf(\"register exporter failed: %v\", err)\n\t}\n\tmfs, err := r.Gather()\n\tif err != nil {\n\t\tt.Fatalf(\"Gather failed: %v\", err)\n\t}\n\n\tfound := map[string]bool{}\n\tfor _, mf := range mfs {\n\t\tfound[mf.GetName()] = true\n\t}\n\tif !found[\"q_value\"] {\n\t\tt.Fatalf(\"expected query metric q_value to be present, got: %#v\", found)\n\t}\n\t// Default internal metrics namespace for postgres is \"pg\".\n\tif found[\"pg_up\"] || found[\"pg_version\"] || found[\"pg_in_recovery\"] || found[\"pg_exporter_build_info\"] || found[\"pg_exporter_up\"] {\n\t\tt.Fatalf(\"disable-intro should suppress internal metrics, got: %#v\", found)\n\t}\n}\n\nfunc TestServerIntrospectionHelpers(t *testing.T) {\n\ts := NewServer(\"postgresql://u:p@localhost:5432/postgres\")\n\tc := makeCachedCollectorForServer(s, \"q\", 1)\n\ts.Collectors = []*Collector{c}\n\ts.ResetStats()\n\n\tif s.Error() != nil {\n\t\tt.Fatalf(\"new server Error should be nil, got %v\", s.Error())\n\t}\n\tif got := s.Duration(); got != 0 {\n\t\tt.Fatalf(\"new server Duration = %v, want 0\", got)\n\t}\n\tif got := s.Uptime(); got < 0 {\n\t\tt.Fatalf(\"Uptime should be non-negative, got %v\", got)\n\t}\n\n\tif got := c.ResultSize(); got != 1 {\n\t\tt.Fatalf(\"collector ResultSize = %d, want 1\", got)\n\t}\n\tif skip, _ := c.PredicateSkip(); skip {\n\t\tt.Fatal(\"collector PredicateSkip should be false by default\")\n\t}\n\tif got := c.Duration(); got != 0 {\n\t\tt.Fatalf(\"collector Duration = %v, want 0\", got)\n\t}\n\n\tif exp := s.Explain(); exp == \"\" {\n\t\tt.Fatal(\"Explain should not be empty\")\n\t}\n\tif html := s.ExplainHTML(); html == \"\" {\n\t\tt.Fatal(\"ExplainHTML should not be empty\")\n\t}\n}\n"
  },
  {
    "path": "exporter/pgurl.go",
    "content": "package exporter\n\nimport (\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n)\n\n// GetPGURL will retrieve, parse, modify postgres connection string\nfunc GetPGURL() string {\n\treturn ProcessPGURL(RetrievePGURL())\n}\n\n// RetrievePGURL retrieve pg target url from multiple sources according to precedence\n// priority: cli-args > env  > env file path\n//  1. Command Line Argument (--url -u -d)\n//  2. Environment PG_EXPORTER_URL\n//  3. From file specified via Environment PG_EXPORTER_URL_FILE\n//  4. Default url\n//\n// The default URL intentionally targets local libpq defaults. This is a\n// local-first behavior for on-host deployments, where pg_exporter usually\n// runs on the same machine as PostgreSQL/PgBouncer.\nfunc RetrievePGURL() (res string) {\n\t// command line args\n\tif *pgURL != \"\" {\n\t\tlogInfof(\"retrieve target url %s from command line\", ShadowPGURL(*pgURL))\n\t\treturn *pgURL\n\t}\n\t// env PG_EXPORTER_URL\n\tif res = os.Getenv(\"PG_EXPORTER_URL\"); res != \"\" {\n\t\tlogInfof(\"retrieve target url %s from PG_EXPORTER_URL\", ShadowPGURL(res))\n\t\treturn res\n\t}\n\t// env PGURL\n\tif res = os.Getenv(\"PGURL\"); res != \"\" {\n\t\tlogInfof(\"retrieve target url %s from PGURL\", ShadowPGURL(res))\n\t\treturn res\n\t}\n\t// file content from file PG_EXPORTER_URL_FILE\n\tif filename := os.Getenv(\"PG_EXPORTER_URL_FILE\"); filename != \"\" {\n\t\tif fileContents, err := os.ReadFile(filename); err != nil {\n\t\t\tlogFatalf(\"PG_EXPORTER_URL_FILE=%s is specified, fail loading url: %s\", filename, err.Error())\n\t\t} else {\n\t\t\tres = strings.TrimSpace(string(fileContents))\n\t\t\tlogInfof(\"retrieve target url %s from PG_EXPORTER_URL_FILE\", ShadowPGURL(res))\n\t\t\treturn res\n\t\t}\n\t}\n\t// DEFAULT\n\tlogWarnf(\"fail retrieving target url, fallback on default url: %s\", defaultPGURL)\n\treturn defaultPGURL\n}\n\n// ProcessPGURL will fix URL with default options.\n//\n// Design decision:\n// If sslmode is omitted, force sslmode=disable. pg_exporter is typically\n// deployed as an on-host/local exporter, where TLS on loopback adds overhead\n// without meaningful security benefit. Users can always override by passing an\n// explicit sslmode in the URL.\nfunc ProcessPGURL(pgurl string) string {\n\tu, err := url.Parse(pgurl)\n\tif err != nil {\n\t\tlogErrorf(\"invalid url format %s\", pgurl)\n\t\treturn \"\"\n\t}\n\n\t// add sslmode = disable if not exists\n\tqs := u.Query()\n\tif sslmode := qs.Get(`sslmode`); sslmode == \"\" {\n\t\tqs.Set(`sslmode`, `disable`)\n\t}\n\tu.RawQuery = qs.Encode()\n\treturn u.String()\n}\n\n// ShadowPGURL will hide password part of dsn\nfunc ShadowPGURL(pgurl string) string {\n\tparsedURL, err := url.Parse(pgurl)\n\t// That means we got a bad connection string. Fail early\n\tif err != nil {\n\t\tlogFatalf(\"Could not parse connection string %s\", err.Error())\n\t}\n\n\t// We need to handle two cases:\n\t// 1. The password is in the format postgresql://localhost:5432/postgres?sslmode=disable&user=<user>&password=<pass>\n\t// 2. The password is in the format postgresql://<user>:<pass>@localhost:5432/postgres?sslmode=disable\n\n\tqs := parsedURL.Query()\n\tfor k, values := range qs {\n\t\tif strings.EqualFold(k, \"password\") {\n\t\t\tfor i := range values {\n\t\t\t\tvalues[i] = \"xxxxx\"\n\t\t\t}\n\t\t\tqs[k] = values\n\t\t}\n\t}\n\tparsedURL.RawQuery = qs.Encode()\n\treturn parsedURL.Redacted()\n}\n\n// ParseDatname extract database name part of a pgurl\nfunc ParseDatname(pgurl string) string {\n\tu, err := url.Parse(pgurl)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tif datname := strings.TrimLeft(u.Path, \"/\"); datname != \"\" {\n\t\treturn datname\n\t}\n\tif datname := strings.TrimSpace(u.Query().Get(\"dbname\")); datname != \"\" {\n\t\treturn datname\n\t}\n\treturn \"\"\n}\n\n// ReplaceDatname will replace pgurl with new database name\nfunc ReplaceDatname(pgurl, datname string) string {\n\tu, err := url.Parse(pgurl)\n\tif err != nil {\n\t\tlogErrorf(\"invalid url format %s\", pgurl)\n\t\treturn \"\"\n\t}\n\tif strings.TrimLeft(u.Path, \"/\") == \"\" {\n\t\tqs := u.Query()\n\t\tif qs.Get(\"dbname\") != \"\" {\n\t\t\tqs.Set(\"dbname\", datname)\n\t\t\tu.RawQuery = qs.Encode()\n\t\t\treturn u.String()\n\t\t}\n\t}\n\tu.Path = \"/\" + datname\n\treturn u.String()\n}\n"
  },
  {
    "path": "exporter/pgurl_test.go",
    "content": "package exporter\n\nimport (\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc TestProcessPGURLKeepsEncodedQueryValues(t *testing.T) {\n\tinput := \"postgresql://user:pass@localhost:5432/postgres?application_name=a%26b&password=p%3Dq\"\n\toutput := ProcessPGURL(input)\n\tif output == \"\" {\n\t\tt.Fatalf(\"ProcessPGURL returned empty output\")\n\t}\n\n\tparsed, err := url.Parse(output)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to parse output URL: %v\", err)\n\t}\n\tqs := parsed.Query()\n\tif got := qs.Get(\"application_name\"); got != \"a&b\" {\n\t\tt.Fatalf(\"application_name = %q, want %q\", got, \"a&b\")\n\t}\n\tif got := qs.Get(\"password\"); got != \"p=q\" {\n\t\tt.Fatalf(\"password = %q, want %q\", got, \"p=q\")\n\t}\n\tif got := qs.Get(\"sslmode\"); got != \"disable\" {\n\t\tt.Fatalf(\"sslmode = %q, want %q\", got, \"disable\")\n\t}\n}\n\nfunc TestShadowPGURLRedactsQueryPassword(t *testing.T) {\n\tinput := \"postgresql://user:pass@localhost:5432/postgres?password=p%26q%3D1&application_name=test\"\n\toutput := ShadowPGURL(input)\n\n\tparsed, err := url.Parse(output)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to parse redacted URL: %v\", err)\n\t}\n\tif got := parsed.Query().Get(\"password\"); got != \"xxxxx\" {\n\t\tt.Fatalf(\"password = %q, want %q\", got, \"xxxxx\")\n\t}\n}\n\nfunc TestParseDatnameAndReplaceDatname(t *testing.T) {\n\tsrc := \"postgresql://user:pass@localhost:5432/postgres?sslmode=disable\"\n\tif got := ParseDatname(src); got != \"postgres\" {\n\t\tt.Fatalf(\"ParseDatname = %q, want %q\", got, \"postgres\")\n\t}\n\n\treplaced := ReplaceDatname(src, \"otherdb\")\n\tif got := ParseDatname(replaced); got != \"otherdb\" {\n\t\tt.Fatalf(\"ParseDatname(replaced) = %q, want %q\", got, \"otherdb\")\n\t}\n\n\tsrcWithDbname := \"postgresql://user:pass@localhost:5432?sslmode=disable&dbname=pgbouncer\"\n\tif got := ParseDatname(srcWithDbname); got != \"pgbouncer\" {\n\t\tt.Fatalf(\"ParseDatname(dbname=) = %q, want %q\", got, \"pgbouncer\")\n\t}\n\n\treplacedDbname := ReplaceDatname(srcWithDbname, \"postgres\")\n\tif got := ParseDatname(replacedDbname); got != \"postgres\" {\n\t\tt.Fatalf(\"ParseDatname(replaced dbname=) = %q, want %q\", got, \"postgres\")\n\t}\n}\n\nfunc TestRetrievePGURLPriority(t *testing.T) {\n\toriginPGURL := *pgURL\n\t*pgURL = \"\"\n\tt.Cleanup(func() { *pgURL = originPGURL })\n\n\toriginExporterURL := os.Getenv(\"PG_EXPORTER_URL\")\n\toriginPGURLenv := os.Getenv(\"PGURL\")\n\toriginFile := os.Getenv(\"PG_EXPORTER_URL_FILE\")\n\tt.Cleanup(func() {\n\t\t_ = os.Setenv(\"PG_EXPORTER_URL\", originExporterURL)\n\t\t_ = os.Setenv(\"PGURL\", originPGURLenv)\n\t\t_ = os.Setenv(\"PG_EXPORTER_URL_FILE\", originFile)\n\t})\n\n\t_ = os.Setenv(\"PG_EXPORTER_URL\", \"postgresql://env-user:env-pass@localhost:5432/envdb\")\n\t_ = os.Setenv(\"PGURL\", \"postgresql://pgurl-user:pgurl-pass@localhost:5432/pgurldb\")\n\t*pgURL = \"postgresql://cli-user:cli-pass@localhost:5432/clidb\"\n\tif got := RetrievePGURL(); got != *pgURL {\n\t\tt.Fatalf(\"RetrievePGURL CLI precedence failed: got %s\", got)\n\t}\n\n\t*pgURL = \"\"\n\tif got := RetrievePGURL(); got != os.Getenv(\"PG_EXPORTER_URL\") {\n\t\tt.Fatalf(\"RetrievePGURL env precedence failed: got %s\", got)\n\t}\n\n\t_ = os.Unsetenv(\"PG_EXPORTER_URL\")\n\tif got := RetrievePGURL(); got != os.Getenv(\"PGURL\") {\n\t\tt.Fatalf(\"RetrievePGURL PGURL fallback failed: got %s\", got)\n\t}\n\n\t_ = os.Unsetenv(\"PGURL\")\n\tfile := filepath.Join(t.TempDir(), \"dsn.txt\")\n\tfileURL := \"postgresql://file-user:file-pass@localhost:5432/filedb\"\n\tif err := os.WriteFile(file, []byte(fileURL), 0o644); err != nil {\n\t\tt.Fatalf(\"write dsn file failed: %v\", err)\n\t}\n\t_ = os.Setenv(\"PG_EXPORTER_URL_FILE\", file)\n\tif got := RetrievePGURL(); got != fileURL {\n\t\tt.Fatalf(\"RetrievePGURL file fallback failed: got %s\", got)\n\t}\n\n\t_ = os.Unsetenv(\"PG_EXPORTER_URL_FILE\")\n\tif got := RetrievePGURL(); got != defaultPGURL {\n\t\tt.Fatalf(\"RetrievePGURL default fallback failed: got %s\", got)\n\t}\n}\n"
  },
  {
    "path": "exporter/predicate_cache_test.go",
    "content": "package exporter\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestPredicateCacheHitSkipsDBQuery(t *testing.T) {\n\tq := &Query{\n\t\tName:   \"q\",\n\t\tBranch: \"q\",\n\t\tPredicateQueries: []PredicateQuery{\n\t\t\t{Name: \"p1\", SQL: \"SELECT true\", TTL: 10},\n\t\t},\n\t}\n\ts := &Server{Database: \"postgres\"} // DB is nil; any QueryContext call would panic.\n\tc := NewCollector(q, s)\n\n\tnow := time.Now()\n\tc.scrapeBegin = now\n\n\t// Cache hit: pass=true should continue and ultimately return true without touching DB.\n\tc.predicateCache[0] = predicateCacheEntry{at: now.Add(-time.Second), pass: true}\n\tif ok := c.executePredicateQueries(context.Background()); !ok {\n\t\tt.Fatal(\"expected cached pass=true to allow query execution\")\n\t}\n\n\t// Cache hit: pass=false should return false without touching DB.\n\tc.scrapeBegin = now\n\tc.predicateCache[0] = predicateCacheEntry{at: now.Add(-time.Second), pass: false}\n\tif ok := c.executePredicateQueries(context.Background()); ok {\n\t\tt.Fatal(\"expected cached pass=false to skip query execution\")\n\t}\n}\n\nfunc TestPredicateCacheMissTriggersDBQuery(t *testing.T) {\n\tq := &Query{\n\t\tName:   \"q\",\n\t\tBranch: \"q\",\n\t\tPredicateQueries: []PredicateQuery{\n\t\t\t{Name: \"p1\", SQL: \"SELECT true\", TTL: 10},\n\t\t},\n\t}\n\ts := &Server{Database: \"postgres\"} // DB is nil; QueryContext must panic if called.\n\tc := NewCollector(q, s)\n\tc.scrapeBegin = time.Now()\n\n\tdefer func() {\n\t\tif r := recover(); r == nil {\n\t\t\tt.Fatal(\"expected panic due to DB access on predicate cache miss\")\n\t\t}\n\t}()\n\t_ = c.executePredicateQueries(context.Background())\n}\n\nfunc TestPredicateCacheDisabledByTTLZero(t *testing.T) {\n\tq := &Query{\n\t\tName:   \"q\",\n\t\tBranch: \"q\",\n\t\tPredicateQueries: []PredicateQuery{\n\t\t\t{Name: \"p1\", SQL: \"SELECT true\", TTL: 0},\n\t\t},\n\t}\n\ts := &Server{Database: \"postgres\"} // DB is nil; QueryContext must panic if called.\n\tc := NewCollector(q, s)\n\tc.scrapeBegin = time.Now()\n\tc.predicateCache[0] = predicateCacheEntry{at: time.Now(), pass: true}\n\n\tdefer func() {\n\t\tif r := recover(); r == nil {\n\t\t\tt.Fatal(\"expected panic due to DB access when predicate TTL is 0 (cache disabled)\")\n\t\t}\n\t}()\n\t_ = c.executePredicateQueries(context.Background())\n}\n"
  },
  {
    "path": "exporter/probehealth_pgbouncer_test.go",
    "content": "package exporter\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"errors\"\n\t\"io\"\n\t\"testing\"\n)\n\nvar errProbeHealthTestPingCalled = errors.New(\"ping called\")\n\n// probeHealthTestDriver is a tiny database/sql driver used to verify that\n// ProbeHealth in pgbouncer mode does not use db.PingContext (lib/pq Ping uses\n// a \";\" query which PgBouncer rejects). If Ping is called we return a sentinel\n// error to fail the test.\ntype probeHealthTestDriver struct{}\n\nfunc (d probeHealthTestDriver) Open(name string) (driver.Conn, error) {\n\treturn &probeHealthTestConn{}, nil\n}\n\ntype probeHealthTestConn struct{}\n\nfunc (c *probeHealthTestConn) Prepare(query string) (driver.Stmt, error) {\n\treturn nil, errors.New(\"prepare not supported\")\n}\nfunc (c *probeHealthTestConn) Close() error              { return nil }\nfunc (c *probeHealthTestConn) Begin() (driver.Tx, error) { return nil, errors.New(\"tx not supported\") }\n\nfunc (c *probeHealthTestConn) Ping(ctx context.Context) error { return errProbeHealthTestPingCalled }\n\nfunc (c *probeHealthTestConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {\n\t// Return an empty resultset; database/sql will surface this as sql.ErrNoRows\n\t// to QueryRowContext, which ProbeHealth should treat as a successful probe\n\t// for PgBouncer (SHOW VERSION may return via NOTICE only).\n\treturn &probeHealthTestRows{}, nil\n}\n\ntype probeHealthTestRows struct{}\n\nfunc (r *probeHealthTestRows) Columns() []string { return []string{\"version\"} }\nfunc (r *probeHealthTestRows) Close() error      { return nil }\nfunc (r *probeHealthTestRows) Next(dest []driver.Value) error {\n\treturn io.EOF\n}\n\nfunc init() {\n\tsql.Register(\"probehealth_test\", probeHealthTestDriver{})\n}\n\nfunc TestProbeHealthPgbouncerDoesNotPingAndTreatsNoRowsAsUp(t *testing.T) {\n\tdb, err := sql.Open(\"probehealth_test\", \"\")\n\tif err != nil {\n\t\tt.Fatalf(\"sql.Open: %v\", err)\n\t}\n\tdefer db.Close()\n\n\ts := &Server{\n\t\tDB:             db,\n\t\tPgbouncerMode:  true,\n\t\tConnectTimeout: 500,\n\t}\n\n\tup, recovery, starting, err := s.ProbeHealth()\n\tif err != nil {\n\t\tt.Fatalf(\"ProbeHealth error = %v\", err)\n\t}\n\tif !up {\n\t\tt.Fatalf(\"up = %v, want true\", up)\n\t}\n\tif recovery {\n\t\tt.Fatalf(\"recovery = %v, want false\", recovery)\n\t}\n\tif starting {\n\t\tt.Fatalf(\"starting = %v, want false\", starting)\n\t}\n}\n"
  },
  {
    "path": "exporter/prom_validate.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/prometheus/common/model\"\n)\n\nfunc validatePromLabelName(name string) error {\n\tif name == \"\" {\n\t\treturn fmt.Errorf(\"empty label name\")\n\t}\n\tif strings.HasPrefix(name, model.ReservedLabelPrefix) {\n\t\treturn fmt.Errorf(\"label name %q uses reserved prefix %q\", name, model.ReservedLabelPrefix)\n\t}\n\tif !model.LegacyValidation.IsValidLabelName(name) {\n\t\treturn fmt.Errorf(\"invalid label name %q\", name)\n\t}\n\treturn nil\n}\n\nfunc validatePromMetricName(name string) error {\n\tif name == \"\" {\n\t\treturn fmt.Errorf(\"empty metric name\")\n\t}\n\tif !model.LegacyValidation.IsValidMetricName(name) {\n\t\treturn fmt.Errorf(\"invalid metric name %q\", name)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "exporter/query.go",
    "content": "package exporter\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\thtmltmpl \"html/template\"\n\t\"slices\"\n\ttexttmpl \"text/template\"\n\t\"time\"\n\n\t\"gopkg.in/yaml.v3\"\n)\n\n/* ================ Query ================ */\n\n// Query hold the information of how to fetch metric and parse them\ntype Query struct {\n\tName             string           `yaml:\"name,omitempty\"`              // actual query name, used as metric prefix\n\tDesc             string           `yaml:\"desc,omitempty\"`              // description of this metric query\n\tSQL              string           `yaml:\"query\"`                       // SQL command to fetch metrics\n\tPredicateQueries []PredicateQuery `yaml:\"predicate_queries,omitempty\"` // SQL command to filter metrics\n\tBranch           string           `yaml:\"-\"`                           // branch name, top layer key of config file\n\n\t// control query behaviour\n\tTags       []string `yaml:\"tags,omitempty\"`        // tags are used for execution control\n\tTTL        float64  `yaml:\"ttl,omitempty\"`         // caching ttl in seconds\n\tTimeout    float64  `yaml:\"timeout,omitempty\"`     // query execution timeout in seconds\n\tPriority   int      `yaml:\"priority,omitempty\"`    // execution priority, from 1 to 999\n\tMinVersion int      `yaml:\"min_version,omitempty\"` // minimal supported version, include\n\tMaxVersion int      `yaml:\"max_version,omitempty\"` // maximal supported version, not include\n\tFatal      bool     `yaml:\"fatal,omitempty\"`       // if query marked fatal fail, entire scrape will fail\n\tSkip       bool     `yaml:\"skip,omitempty\"`        // if query marked skip, it will be omit while loading\n\n\tMetrics []map[string]*Column `yaml:\"metrics\"` // metric definition list\n\n\t// metrics parsing auxiliaries\n\tPath        string             `yaml:\"-\"` // where am I from ?\n\tColumns     map[string]*Column `yaml:\"-\"` // column map\n\tColumnNames []string           `yaml:\"-\"` // column names in origin orders\n\tLabelNames  []string           `yaml:\"-\"` // column (name) that used as label, sequences matters\n\tMetricNames []string           `yaml:\"-\"` // column (name) that used as metric\n}\n\n// A PredicateQuery is a query that returns a 1-column resultset that's used to decide whether\n// to run the main query.\ntype PredicateQuery struct {\n\tName string  `yaml:\"name,omitempty\"`  // predicate query name, only used for logging\n\tSQL  string  `yaml:\"predicate_query\"` // SQL command to return a predicate\n\tTTL  float64 `yaml:\"ttl,omitempty\"`   // How long to cache results for\n}\n\nvar queryTemplate, _ = texttmpl.New(\"Query\").Parse(`##\n# SYNOPSIS\n#       {{ .Name }}{{ if ne .Name .Branch }}.{{ .Branch }}{{ end }}_*\n#\n# DESCRIPTION\n#       {{ with .Desc }}{{ . }}{{ else }}N/A{{ end }}\n#\n# OPTIONS\n#       Tags       [{{ range $i, $e := .Tags }}{{ if $i }}, {{ end }}{{ $e }}{{ end }}]\n#       TTL        {{ .TTL }}\n#       Priority   {{ .Priority }}\n#       Timeout    {{ .TimeoutDuration }}\n#       Fatal      {{ .Fatal }}\n#       Version    {{ if ne .MinVersion 0 }}{{ .MinVersion }}{{ else }}lower{{ end }} ~ {{ if ne .MaxVersion 0 }}{{ .MaxVersion }}{{ else }}higher{{ end }}\n#       Source     {{ .Path }}\n#\n# METRICS\n{{- range .ColumnList }}\n#       {{ .Name }} ({{ .Usage }})\n#           {{ with .Desc }}{{ . }}{{ else }}N/A{{ end }}{{ end }}\n#\n{{.MarshalYAML -}}\n`)\n\nvar htmlTemplate, _ = htmltmpl.New(\"Query\").Parse(`\n<div style=\"border-style: solid; padding-left: 20px; padding-bottom: 10px;\">\n\n<h2>{{ .Name }}</h2>\n<p>{{ .Desc }}</p>\n{{ if len .PredicateQueries }}\n<h4>Predicate queries</h4>\n<table style=\"border-style: dotted;\">\n<thead><tr><th>Name</th> <th>SQL</th> <th>Cache TTL</th></tr></thead>\n<tbody>\n{{ range .PredicateQueries }}\n<tr><td>{{ .Name }}</td><td><code>{{ .SQL }}</code></td><td>{{if ne .TTL 0}}{{ .TTL }}s{{else}}<i>not cached</i>{{end}}</td></tr>\n{{ end }}\n</tbody></table>\n{{ end }}\n<h4>Query</h4>\n<code><pre>{{ .SQL }}</pre></code>\n\n<h4>Attribution</h4>\n<code><table style=\"border-style: dotted;\"><tbody>\n<tr><td>Branch   </td> <td> {{ .Branch }} </td></tr>\n<tr><td>TTL      </td> <td> {{ .TTL }} </td></tr>\n<tr><td>Priority </td> <td> {{ .Priority }} </td></tr>\n<tr><td>Timeout  </td> <td> {{ .TimeoutDuration }} </td></tr>\n<tr><td>Fatal    </td> <td> {{ .Fatal }} </td></tr>\n<tr><td>Version  </td> <td> {{if ne .MinVersion 0}}{{ .MinVersion }}{{else}}lower{{end}} ~ {{if ne .MaxVersion 0}}{{ .MaxVersion }}{{else}}higher{{end}} </td></tr>\n<tr><td>Tags     </td> <td> {{ .Tags }} </td></tr>\n<tr><td>Source   </td> <td> {{ .Path }} </td></tr>\n</tbody></table></code>\n\n<h4>Columns</h4>\n<code><table align=\"left\" style=\"border-style: dotted;\"><thead><tr><th>Name</th> <th>Usage</th> <th>Rename</th> <th>Bucket</th> <th>Scale</th> <th>Default</th> <th>Description</th></tr></thead>\n<tbody>{{ range .ColumnList }}<tr><td>{{ .Name }}</td><td>{{ .Usage }}</td><td>{{ .Rename }}</td><td>{{ .Bucket }}</td><td>{{ .Scale }}</td><td>{{ .Default }}</td><td>{{ .Desc }}</td></tr>{{ end }}\n</tbody></table></code>\n\n<h4>Metrics</h4>\n<code><table align=\"left\" style=\"border-style: dotted;\"><thead><tr><th>Name</th> <th>Usage</th> <th>Desc</th></tr></thead><tbody>\n{{ range .MetricList }}<tr><td>{{ .Name }}</td><td>{{ .Column.Usage }}</td><td>{{ .Column.Desc }}</td></tr>{{ end }}\n</tbody></table></code>\n</div>\n`)\n\n// MarshalYAML will turn query into YAML format\nfunc (q *Query) MarshalYAML() string {\n\t// buf := new(bytes.Buffer)\n\tv := make(map[string]Query, 1)\n\tv[q.Branch] = *q\n\tbuf, err := yaml.Marshal(v)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"fail to marshall query yaml: %s\", err.Error())\n\t\tlogError(msg)\n\t\treturn msg\n\t}\n\treturn string(buf)\n}\n\n// Explain will turn query into text format\nfunc (q *Query) Explain() string {\n\tbuf := new(bytes.Buffer)\n\terr := queryTemplate.Execute(buf, q)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"fail to explain query: %s\", err.Error())\n\t\tlogError(msg)\n\t\treturn msg\n\t}\n\treturn buf.String()\n}\n\n// HTML will turn Query into HTML format\nfunc (q *Query) HTML() string {\n\tbuf := new(bytes.Buffer)\n\terr := htmlTemplate.Execute(buf, q)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"fail to generate query html: %s\", err.Error())\n\t\tlogError(msg)\n\t\treturn msg\n\t}\n\treturn buf.String()\n}\n\n// HasTag tells whether this query have specific tag\n// since only few tags is provided, we don't really need a map here\nfunc (q *Query) HasTag(tag string) bool {\n\treturn slices.Contains(q.Tags, tag)\n}\n\n// ColumnList return ordered column list\nfunc (q *Query) ColumnList() (res []*Column) {\n\tres = make([]*Column, len(q.ColumnNames))\n\tfor i, colName := range q.ColumnNames {\n\t\tres[i] = q.Columns[colName]\n\t}\n\treturn\n}\n\n// LabelList returns a list of label column names\nfunc (q *Query) LabelList() []string {\n\tlabelNames := make([]string, len(q.LabelNames))\n\tfor i, labelName := range q.LabelNames {\n\t\tlabelColumn := q.Columns[labelName]\n\t\tif labelColumn.Rename != \"\" {\n\t\t\tlabelNames[i] = labelColumn.Rename\n\t\t} else {\n\t\t\tlabelNames[i] = labelColumn.Name\n\t\t}\n\t}\n\treturn labelNames\n}\n\n// MetricList returns a list of MetricDesc generated by this query\nfunc (q *Query) MetricList() (res []*MetricDesc) {\n\tres = make([]*MetricDesc, len(q.MetricNames))\n\tfor i, metricName := range q.MetricNames {\n\t\tcolumn := q.Columns[metricName]\n\t\tres[i] = column.MetricDesc(q.Name, q.LabelList())\n\t}\n\treturn\n}\n\n// TimeoutDuration will turn timeout settings into time.Duration\nfunc (q *Query) TimeoutDuration() time.Duration {\n\treturn time.Duration(float64(time.Second) * q.Timeout)\n}\n"
  },
  {
    "path": "exporter/query_column_test.go",
    "content": "package exporter\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\nfunc makeSampleQuery() *Query {\n\treturn &Query{\n\t\tName:    \"sample\",\n\t\tBranch:  \"sample_branch\",\n\t\tDesc:    \"sample query\",\n\t\tTags:    []string{\"tag1\", \"tag2\"},\n\t\tTimeout: 1.5,\n\t\tColumns: map[string]*Column{\n\t\t\t\"datname\": {\n\t\t\t\tName:   \"datname\",\n\t\t\t\tUsage:  LABEL,\n\t\t\t\tRename: \"db\",\n\t\t\t\tDesc:   \"database name\",\n\t\t\t},\n\t\t\t\"value\": {\n\t\t\t\tName:   \"value\",\n\t\t\t\tUsage:  GAUGE,\n\t\t\t\tRename: \"val\",\n\t\t\t\tDesc:   \"metric value\",\n\t\t\t},\n\t\t},\n\t\tColumnNames: []string{\"datname\", \"value\"},\n\t\tLabelNames:  []string{\"datname\"},\n\t\tMetricNames: []string{\"value\"},\n\t\tMetrics: []map[string]*Column{\n\t\t\t{\"datname\": {Name: \"datname\", Usage: LABEL, Rename: \"db\", Desc: \"database name\"}},\n\t\t\t{\"value\": {Name: \"value\", Usage: GAUGE, Rename: \"val\", Desc: \"metric value\"}},\n\t\t},\n\t}\n}\n\nfunc TestColumnPrometheusValueType(t *testing.T) {\n\tcGauge := &Column{Name: \"g\", Usage: GAUGE}\n\tif got := cGauge.PrometheusValueType(); got != prometheus.GaugeValue {\n\t\tt.Fatalf(\"gauge type = %v, want GaugeValue\", got)\n\t}\n\n\tcCounter := &Column{Name: \"c\", Usage: COUNTER}\n\tif got := cCounter.PrometheusValueType(); got != prometheus.CounterValue {\n\t\tt.Fatalf(\"counter type = %v, want CounterValue\", got)\n\t}\n\n\tdefer func() {\n\t\tif r := recover(); r == nil {\n\t\t\tt.Fatal(\"PrometheusValueType should panic for non-value usage\")\n\t\t}\n\t}()\n\t_ = (&Column{Name: \"x\", Usage: LABEL}).PrometheusValueType()\n}\n\nfunc TestColumnAndMetricDescString(t *testing.T) {\n\tc := &Column{Name: \"value\", Usage: GAUGE, Desc: \"desc\"}\n\tif !strings.Contains(c.String(), \"value\") {\n\t\tt.Fatalf(\"column string does not contain name: %s\", c.String())\n\t}\n\n\tmd := c.MetricDesc(\"sample\", []string{\"db\"})\n\tif !strings.Contains(md.Name, \"sample_value\") {\n\t\tt.Fatalf(\"metric desc name = %s\", md.Name)\n\t}\n\tif !strings.Contains(md.Name, \"{db}\") {\n\t\tt.Fatalf(\"metric desc should contain labels signature, got %s\", md.Name)\n\t}\n\tif !strings.Contains(md.String(), \"desc\") {\n\t\tt.Fatalf(\"metric desc string = %s\", md.String())\n\t}\n}\n\nfunc TestQueryHelpersAndRender(t *testing.T) {\n\tq := makeSampleQuery()\n\n\tif !q.HasTag(\"tag1\") || q.HasTag(\"missing\") {\n\t\tt.Fatalf(\"HasTag result unexpected for tags %v\", q.Tags)\n\t}\n\n\tcols := q.ColumnList()\n\tif len(cols) != 2 || cols[0].Name != \"datname\" || cols[1].Name != \"value\" {\n\t\tt.Fatalf(\"ColumnList order unexpected: %#v\", cols)\n\t}\n\n\tlabels := q.LabelList()\n\tif len(labels) != 1 || labels[0] != \"db\" {\n\t\tt.Fatalf(\"LabelList = %#v, want [db]\", labels)\n\t}\n\n\tmetrics := q.MetricList()\n\tif len(metrics) != 1 {\n\t\tt.Fatalf(\"MetricList len = %d, want 1\", len(metrics))\n\t}\n\tif !strings.Contains(metrics[0].Name, \"sample_val\") {\n\t\tt.Fatalf(\"MetricList name = %s\", metrics[0].Name)\n\t}\n\n\tif got := q.TimeoutDuration(); got != 1500*time.Millisecond {\n\t\tt.Fatalf(\"TimeoutDuration = %v, want 1500ms\", got)\n\t}\n\n\tyaml := q.MarshalYAML()\n\tif !strings.Contains(yaml, \"sample_branch:\") {\n\t\tt.Fatalf(\"MarshalYAML missing branch key: %s\", yaml)\n\t}\n\n\texplain := q.Explain()\n\tif !strings.Contains(explain, \"SYNOPSIS\") {\n\t\tt.Fatalf(\"Explain output unexpected: %s\", explain)\n\t}\n\n\thtml := q.HTML()\n\tif !strings.Contains(html, \"<h2>sample</h2>\") {\n\t\tt.Fatalf(\"HTML output unexpected: %s\", html)\n\t}\n}\n"
  },
  {
    "path": "exporter/reload_signals_unix.go",
    "content": "//go:build !windows\n\npackage exporter\n\nimport (\n\t\"os\"\n\t\"syscall\"\n)\n\nvar reloadSignals = []os.Signal{syscall.SIGHUP, syscall.SIGUSR1}\n"
  },
  {
    "path": "exporter/reload_signals_windows.go",
    "content": "//go:build windows\n\npackage exporter\n\nimport (\n\t\"os\"\n\t\"syscall\"\n)\n\nvar reloadSignals = []os.Signal{syscall.SIGHUP}\n"
  },
  {
    "path": "exporter/reload_test.go",
    "content": "package exporter\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc TestReloadUpdatesQueriesInPlace(t *testing.T) {\n\toriginExporter := PgExporter\n\tt.Cleanup(func() { setCurrentExporter(originExporter) })\n\n\toriginConfigPath := *configPath\n\tt.Cleanup(func() { *configPath = originConfigPath })\n\n\t// Seed exporter with an initial query set and a planned server.\n\ts := NewServer(\"postgresql://u:p@localhost:5432/postgres\")\n\ts.beforeScrape = func(s *Server) error { return nil }\n\ts.Planned = true\n\ts.queries = map[string]*Query{\"old\": makeGaugeQuery(\"old\", 1)}\n\ts.Collectors = []*Collector{NewCollector(makeGaugeQuery(\"old\", 1), s)}\n\ts.ResetStats()\n\n\te := &Exporter{\n\t\tserver:  s,\n\t\tservers: map[string]*Server{},\n\t\tqueries: s.queries,\n\t}\n\tsetCurrentExporter(e)\n\n\t// Write a new config and reload it.\n\tdir := t.TempDir()\n\tcfgPath := filepath.Join(dir, \"pg_exporter.yml\")\n\tcfg := `\nq_new:\n  query: SELECT 1 AS value, 'db' AS datname\n  metrics:\n    - datname:\n        usage: label\n        description: db\n    - value:\n        usage: gauge\n        description: value\n`\n\tif err := os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil {\n\t\tt.Fatalf(\"write config failed: %v\", err)\n\t}\n\t*configPath = cfgPath\n\n\tif err := Reload(); err != nil {\n\t\tt.Fatalf(\"Reload failed: %v\", err)\n\t}\n\n\tif _, ok := e.queries[\"q_new\"]; !ok {\n\t\tt.Fatalf(\"expected new query to be loaded, got: %#v\", e.queries)\n\t}\n\tif e.server.queries == nil || e.server.queries[\"q_new\"] == nil {\n\t\tt.Fatalf(\"server queries not updated, got: %#v\", e.server.queries)\n\t}\n\tif e.server.Planned {\n\t\tt.Fatalf(\"server should be marked unplanned after reload\")\n\t}\n\tif e.server.Collectors != nil {\n\t\tt.Fatalf(\"server collectors should be cleared after reload\")\n\t}\n}\n"
  },
  {
    "path": "exporter/server.go",
    "content": "package exporter\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/lib/pq\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\n/* ================ Const ================ */\nconst connMaxLifeTime = 1 * time.Minute // close connection after 1 minute to avoid conn leak\n\nconst pgSQLStateCannotConnectNow = \"57P03\"\n\n/* ================ Server ================ */\n\nvar semverRe = regexp.MustCompile(`(\\d+)\\.(\\d+)\\.(\\d+)`)\n\n// Server represent a postgres connection, with additional fact, conf, runtime info\ntype Server struct {\n\t*sql.DB              // database instance (do not close this due to the stupid implementation in database/sql)\n\tdsn     string       // data source name\n\tlock    sync.RWMutex // server scrape lock\n\terr     error        // last error\n\n\t// notice handling (primarily for pgbouncer, where SHOW VERSION may return via NOTICE)\n\tnoticeMu   sync.Mutex\n\tlastNotice string\n\n\t// hooks\n\tbeforeScrape     func(s *Server) error        // hook: execute before scrape\n\tonDatabaseChange func(change map[string]bool) // hook: invoke when database list is changed\n\n\t// postgres fact gather from server\n\tUP       bool   // indicate whether target server is connectable\n\tRecovery bool   // is server in recovering\n\tVersion  int    // pg server version num\n\tDatabase string // database name of current server connection\n\tUsername string // current username\n\n\tDatabases  map[string]bool // all available database in target cluster\n\tdblistLock sync.Mutex      // lock when access Databases map\n\n\tNamespaces map[string]bool // all available schema in target cluster\n\tExtensions map[string]bool // all available extension in target cluster\n\n\tTags            []string // server tags set by cli arg --tag\n\tPgbouncerMode   bool     // indicate it is a pgbouncer server\n\tDisableCache    bool     // force executing, ignoring caching policy\n\tExcludeDbnames  []string // if ExcludeDbnames is provided, Auto Database Discovery is enabled\n\tForked          bool     // is this a forked server ? (does not run cluster level query)\n\tPlanned         bool     // if false, server will trigger a plan before collect\n\tMaxConn         int      // max connection for this server\n\tConnectTimeout  int      // connect timeout for this server in ms\n\tConnMaxLifetime int      // connection max lifetime for this server in seconds\n\n\t// query\n\tCollectors []*Collector      // query collector instance (installed query)\n\tqueries    map[string]*Query // queries map, keys are config file top layer key\n\tlabels     prometheus.Labels // constant labels\n\n\t// internal stats\n\tserverInit  time.Time // server init timestamp\n\tscrapeBegin time.Time // server last scrape begin time\n\tscrapeDone  time.Time // server last scrape done time\n\terrorCount  float64   // total scrape error count on this server (fatal scrape failures only)\n\ttotalCount  float64   // total scrape count on this server\n\ttotalTime   float64   // total time spend on scraping\n\n\tqueryCacheTTL                 map[string]float64 // internal query metrics: cache time to live\n\tqueryScrapeTotalCount         map[string]float64 // internal query metrics: total executed\n\tqueryScrapeHitCount           map[string]float64 // internal query metrics: times serving from hit cache\n\tqueryScrapeErrorCount         map[string]float64 // internal query metrics: times failed\n\tqueryScrapePredicateSkipCount map[string]float64 // internal query metrics: times skipped due to predicate\n\tqueryScrapeMetricCount        map[string]float64 // internal query metrics: number of metrics scraped\n\tqueryScrapeDuration           map[string]float64 // internal query metrics: time spend on executing\n}\n\nfunc (s *Server) GetConnectTimeout() time.Duration {\n\tif s.ConnectTimeout <= 0 {\n\t\treturn 100 * time.Millisecond\n\t}\n\treturn time.Duration(s.ConnectTimeout) * time.Millisecond\n}\n\n// Name is coalesce(s.Database, dsn)\nfunc (s *Server) Name() string {\n\tif s.Database != \"\" {\n\t\treturn s.Database\n\t}\n\treturn ShadowPGURL(s.dsn)\n}\n\nfunc (s *Server) Error() error {\n\treturn s.err\n}\n\n// Check will issue a connection and executing precheck hook function\nfunc (s *Server) Check() error {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\treturn s.beforeScrape(s)\n}\n\n// ProbeHealth performs a lightweight probe for exporter health checks.\n// It returns whether the database is reachable, whether it's in recovery,\n// and whether PostgreSQL is still starting up (SQLSTATE 57P03).\nfunc (s *Server) ProbeHealth() (up, recovery, starting bool, err error) {\n\t// Snapshot pointers/flags quickly under lock to avoid races with first-time DB init.\n\ts.lock.RLock()\n\tdb := s.DB\n\tpgbouncerMode := s.PgbouncerMode\n\ttimeout := s.GetConnectTimeout()\n\ts.lock.RUnlock()\n\n\tif db == nil {\n\t\treturn false, false, false, errors.New(\"database connection is not initialized\")\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tdefer cancel()\n\n\tif pgbouncerMode {\n\t\t// IMPORTANT: do NOT use db.PingContext() for PgBouncer.\n\t\t//\n\t\t// lib/pq implements Ping() by sending a simpleQuery(\";\") (empty command).\n\t\t// PostgreSQL tolerates that, but PgBouncer rejects it with:\n\t\t//   invalid command ';', use SHOW HELP;\n\t\t// This becomes a log-spam regression once ProbeHealth is run periodically.\n\t\t//\n\t\t// For health probes we only need a cheap PgBouncer admin command.\n\t\t// Some PgBouncer versions return SHOW VERSION via NOTICE (no result rows),\n\t\t// so treat sql.ErrNoRows as success.\n\t\tvar dummy string\n\t\tqerr := db.QueryRowContext(ctx, `SHOW VERSION;`).Scan(&dummy)\n\t\tif qerr != nil && !errors.Is(qerr, sql.ErrNoRows) {\n\t\t\treturn false, false, false, qerr\n\t\t}\n\t\treturn true, false, false, nil\n\t}\n\n\tif err = db.QueryRowContext(ctx, `SELECT pg_catalog.pg_is_in_recovery();`).Scan(&recovery); err != nil {\n\t\tstarting = isPostgresStartupError(err)\n\t\treturn false, false, starting, err\n\t}\n\n\treturn true, recovery, false, nil\n}\n\nfunc isPostgresStartupError(err error) bool {\n\tvar pgErr *pq.Error\n\treturn errors.As(err, &pgErr) && string(pgErr.Code) == pgSQLStateCannotConnectNow\n}\n\n// PgbouncerPrecheck checks pgbouncer connection before scrape\nfunc PgbouncerPrecheck(s *Server) (err error) {\n\tif s.DB == nil { // if db is not initialized, create a new DB with a NOTICE handler\n\t\tbase, cerr := pq.NewConnector(s.dsn)\n\t\tif cerr != nil {\n\t\t\ts.UP = false\n\t\t\treturn cerr\n\t\t}\n\t\tconnector := pq.ConnectorWithNoticeHandler(base, func(notice *pq.Error) {\n\t\t\ts.noticeMu.Lock()\n\t\t\ts.lastNotice = notice.Message\n\t\t\ts.noticeMu.Unlock()\n\t\t})\n\t\ts.DB = sql.OpenDB(connector)\n\t\ts.DB.SetMaxIdleConns(1)\n\t\ts.DB.SetMaxOpenConns(1)\n\t\ts.DB.SetConnMaxLifetime(connMaxLifeTime)\n\t}\n\n\t// Clear last notice before issuing SHOW VERSION so we can reliably parse it.\n\ts.noticeMu.Lock()\n\ts.lastNotice = \"\"\n\ts.noticeMu.Unlock()\n\n\tctx, cancel := context.WithTimeout(context.Background(), s.GetConnectTimeout())\n\tdefer cancel()\n\n\tvar versionStr string\n\tqerr := s.DB.QueryRowContext(ctx, `SHOW VERSION;`).Scan(&versionStr)\n\tif qerr != nil && !errors.Is(qerr, sql.ErrNoRows) {\n\t\t// Connection/auth errors should fail precheck (and thus scrape).\n\t\ts.UP = false\n\t\treturn fmt.Errorf(\"fail fetching pgbouncer version: %w\", qerr)\n\t}\n\n\ts.UP = true\n\n\t// Version may come from:\n\t// 1) a normal 1-row resultset (older versions / some builds), or\n\t// 2) a server NOTICE message (pgbouncer 1.12+).\n\tnewVer := 0\n\tif qerr == nil {\n\t\tnewVer = ParseSemver(versionStr)\n\t}\n\tif newVer == 0 {\n\t\ts.noticeMu.Lock()\n\t\tnotice := s.lastNotice\n\t\ts.noticeMu.Unlock()\n\t\tif notice != \"\" {\n\t\t\tnewVer = ParseSemver(notice)\n\t\t}\n\t}\n\n\tif newVer != 0 {\n\t\tif s.Version != newVer {\n\t\t\tlogInfof(\"server [%s] pgbouncer version changed: from [%d] to [%d]\", s.Name(), s.Version, newVer)\n\t\t\ts.Planned = false\n\t\t}\n\t\ts.Version = newVer\n\t} else if qerr == nil || errors.Is(qerr, sql.ErrNoRows) {\n\t\t// Connected, but couldn't parse version string.\n\t\tlogWarnf(\"server [%s] connected but failed to parse pgbouncer version (row=%q)\", s.Name(), versionStr)\n\t}\n\n\treturn nil\n}\n\n// ParseSemver will turn semantic version string into integer\nfunc ParseSemver(semverStr string) int {\n\tsemver := semverRe.FindStringSubmatch(semverStr)\n\tlogDebugf(\"parse pgbouncer semver string %s\", semverStr)\n\tif len(semver) != 4 {\n\t\treturn 0\n\t}\n\tverNum := 0\n\tif major, err := strconv.Atoi(semver[1]); err != nil {\n\t\treturn 0\n\t} else {\n\t\tverNum += major * 10000\n\t}\n\tif minor, err := strconv.Atoi(semver[2]); err != nil {\n\t\treturn 0\n\t} else {\n\t\tverNum += minor * 100\n\t}\n\tif release, err := strconv.Atoi(semver[3]); err != nil {\n\t\treturn 0\n\t} else {\n\t\tverNum += release\n\t}\n\treturn verNum\n}\n\n// PostgresPrecheck checks postgres connection and gathering facts\n// if any important fact changed, it will trigger a plan before next scrape\nfunc PostgresPrecheck(s *Server) (err error) {\n\tif s.DB == nil { // if db is not initialized, create a new DB\n\t\tif s.DB, err = sql.Open(\"postgres\", s.dsn); err != nil {\n\t\t\ts.UP = false\n\t\t\treturn\n\t\t}\n\t\tif s.Forked {\n\t\t\ts.MaxConn = 1\n\t\t\ts.DB.SetMaxIdleConns(1)\n\t\t\ts.DB.SetMaxOpenConns(1)\n\t\t\ts.DB.SetConnMaxLifetime(connMaxLifeTime)\n\t\t} else {\n\t\t\ts.MaxConn = 3\n\t\t\ts.DB.SetMaxIdleConns(3)\n\t\t\ts.DB.SetMaxOpenConns(3)\n\t\t\ts.DB.SetConnMaxLifetime(1 * time.Minute)\n\t\t}\n\t}\n\n\t// retrieve version info\n\tvar version int\n\tctx, cancel := context.WithTimeout(context.Background(), s.GetConnectTimeout())\n\tdefer cancel()\n\tif err = s.DB.QueryRowContext(ctx, `SHOW server_version_num;`).Scan(&version); err != nil {\n\t\ts.UP = false\n\t\treturn fmt.Errorf(\"fail fetching server version: %w\", err)\n\t}\n\ts.UP = true\n\t// fact change triggers a new planning\n\tif s.Version != version {\n\t\tlogInfof(\"server [%s] version changed: from [%d] to [%d]\", s.Name(), s.Version, version)\n\t\ts.Planned = false\n\t}\n\ts.Version = version\n\n\tctxSet, cancelSet := context.WithTimeout(context.Background(), s.GetConnectTimeout())\n\tdefer cancelSet()\n\tif _, err = s.DB.ExecContext(ctxSet, `SET application_name = pg_exporter;`); err != nil {\n\t\ts.UP = false\n\t\treturn fmt.Errorf(\"fail setting application name: %w\", err)\n\t}\n\n\t// get important metadata\n\tvar recovery bool\n\tvar datname, username string\n\tvar databases, namespaces, extensions []string\n\tprecheckSQL := `SELECT current_catalog, current_user, pg_catalog.pg_is_in_recovery(),\n\t(SELECT pg_catalog.array_agg(d.datname)::text[] AS databases FROM pg_catalog.pg_database d WHERE d.datallowconn AND NOT d.datistemplate),\n\t(SELECT pg_catalog.array_agg(n.nspname)::text[] AS namespaces FROM pg_catalog.pg_namespace n),\n\t(SELECT pg_catalog.array_agg(e.extname)::text[] AS extensions FROM pg_catalog.pg_extension e);`\n\tctx2, cancel2 := context.WithTimeout(context.Background(), s.GetConnectTimeout())\n\tdefer cancel2()\n\tif err = s.DB.QueryRowContext(ctx2, precheckSQL).Scan(&datname, &username, &recovery, pq.Array(&databases), pq.Array(&namespaces), pq.Array(&extensions)); err != nil {\n\t\ts.UP = false\n\t\treturn fmt.Errorf(\"fail fetching server version: %w\", err)\n\t}\n\tif s.Recovery != recovery {\n\t\tlogInfof(\"server [%s] recovery status changed: from [%v] to [%v]\", s.Name(), s.Recovery, recovery)\n\t\ts.Planned = false\n\t}\n\ts.Recovery = recovery\n\ts.Username = username\n\tif s.Database != datname {\n\t\tlogInfof(\"server [%s] datname changed: from [%s] to [%s]\", s.Name(), s.Database, datname)\n\t\ts.Planned = false\n\t}\n\ts.Database = datname\n\ts.Databases[datname] = true\n\n\t// update schema & extension list\n\ts.Namespaces = make(map[string]bool, len(namespaces))\n\tfor _, nsname := range namespaces {\n\t\ts.Namespaces[nsname] = true\n\t}\n\ts.Extensions = make(map[string]bool, len(extensions))\n\tfor _, extname := range extensions {\n\t\ts.Extensions[extname] = true\n\t}\n\n\t// detect db change\n\ts.dblistLock.Lock()\n\tdefer s.dblistLock.Unlock()\n\tnewDBList := make(map[string]bool, len(databases))\n\tchanges := make(map[string]bool)\n\t// if new db is not found in old db list, add a change entry [NewDBName:true]\n\tfor _, dbname := range databases {\n\t\tnewDBList[dbname] = true\n\t\tif _, found := s.Databases[dbname]; !found {\n\t\t\tlogDebugf(\"server [%s] found new database %s\", s.Name(), dbname)\n\t\t\tchanges[dbname] = true\n\t\t}\n\t}\n\t// if old db is not found in new db list, add a change entry [OldDBName:false]\n\tfor dbname := range s.Databases {\n\t\tif _, found := newDBList[dbname]; !found {\n\t\t\tlogDebugf(\"server [%s] found vanished database %s\", s.Name(), dbname)\n\t\t\tchanges[dbname] = false\n\t\t}\n\t}\n\t// invoke hook if there are changes on database list\n\tif len(changes) > 0 && s.onDatabaseChange != nil {\n\t\tlogDebugf(\"server [%s] auto discovery database list change : %v\", s.Name(), changes)\n\t\ts.onDatabaseChange(changes) // if doing something long, launch another goroutine\n\t}\n\ts.Databases = newDBList\n\treturn nil\n}\n\n// Plan will install queries that compatible with server fact (version, level, recovery, plugin, tags,...)\nfunc (s *Server) Plan(queries ...*Query) {\n\t// if queries are explicitly given, use it instead of server.queries\n\tif len(queries) > 0 {\n\t\tnewQueries := make(map[string]*Query)\n\t\tfor _, q := range queries {\n\t\t\tnewQueries[q.Name] = q\n\t\t}\n\t\ts.queries = newQueries\n\t}\n\n\t// check query compatibility\n\tinstances := make([]*Collector, 0)\n\tvar installedNames, discardedNames []string\n\tfor name, query := range s.queries {\n\t\tif ok, reason := s.Compatible(query); ok {\n\t\t\tinstances = append(instances, NewCollector(query, s))\n\t\t\tinstalledNames = append(installedNames, query.Branch)\n\t\t} else {\n\t\t\tdiscardedNames = append(discardedNames, query.Branch)\n\t\t\tlogDebugf(\"query [%s].%s discarded because of %s\", query.Name, name, reason)\n\t\t}\n\t}\n\n\t// sort by priority\n\tsort.Slice(instances, func(i, j int) bool {\n\t\treturn instances[i].Priority < instances[j].Priority\n\t})\n\ts.Collectors = instances\n\n\t// reset statistics after planning\n\ts.ResetStats()\n\ts.Planned = true\n\tlogInfof(\"server [%s] planned with %d queries, %d installed, %d discarded, installed: %s , discarded: %s\",\n\t\ts.Name(), len(s.queries), len(installedNames), len(discardedNames), strings.Join(installedNames, \", \"), strings.Join(discardedNames, \", \"))\n}\n\n// ResetStats will clear all statistic info\nfunc (s *Server) ResetStats() {\n\tn := len(s.Collectors)\n\ts.queryCacheTTL = make(map[string]float64, n)\n\ts.queryScrapeTotalCount = make(map[string]float64, n)\n\ts.queryScrapeHitCount = make(map[string]float64, n)\n\ts.queryScrapeErrorCount = make(map[string]float64, n)\n\ts.queryScrapePredicateSkipCount = make(map[string]float64, n)\n\ts.queryScrapeMetricCount = make(map[string]float64, n)\n\ts.queryScrapeDuration = make(map[string]float64, n)\n\n\tfor _, query := range s.Collectors {\n\t\ts.queryCacheTTL[query.Name] = 0\n\t\ts.queryScrapeTotalCount[query.Name] = 0\n\t\ts.queryScrapeHitCount[query.Name] = 0\n\t\ts.queryScrapeErrorCount[query.Name] = 0\n\t\tif len(query.PredicateQueries) > 0 {\n\t\t\ts.queryScrapePredicateSkipCount[query.Name] = 0\n\t\t}\n\t\ts.queryScrapeMetricCount[query.Name] = 0\n\t\ts.queryScrapeDuration[query.Name] = 0\n\t}\n}\n\n// Compatible tells whether a query is compatible with current server\nfunc (s *Server) Compatible(query *Query) (res bool, reason string) {\n\t// check skip flag\n\tif query.Skip {\n\t\treturn false, fmt.Sprintf(\"query %s is marked skip\", query.Name)\n\t}\n\n\t// check mode\n\tif pgbouncerQuery := query.HasTag(\"pgbouncer\"); pgbouncerQuery != s.PgbouncerMode {\n\t\tif s.PgbouncerMode {\n\t\t\treturn false, fmt.Sprintf(\"pgbouncer server doese not match with normal postgres query %s\", query.Name)\n\t\t}\n\t\treturn false, fmt.Sprintf(\"pgbouncer query %s does not match with normal postgres server\", query.Name)\n\t}\n\n\t// check version\n\tif s.Version != 0 { // if version is not determined yet, just let it go\n\t\tif query.MinVersion != 0 && s.Version < query.MinVersion {\n\t\t\treturn false, fmt.Sprintf(\"server version %v lower than query min version %v\", s.Version, query.MinVersion)\n\t\t}\n\t\tif query.MaxVersion != 0 && s.Version >= query.MaxVersion { // exclude\n\t\t\treturn false, fmt.Sprintf(\"server version %v higher than query max version %v\", s.Version, query.MaxVersion)\n\t\t}\n\t}\n\n\t// check query side tags\n\tfor _, tag := range query.Tags {\n\t\t// check extension is installed on target database\n\t\tif strings.HasPrefix(tag, \"extension:\") {\n\t\t\tif _, found := s.Extensions[strings.TrimPrefix(tag, \"extension:\")]; !found {\n\t\t\t\treturn false, fmt.Sprintf(\"server [%s] does not have extension %s\", s.Name(), tag)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// check schema exist on target database\n\t\tif strings.HasPrefix(tag, \"schema:\") {\n\t\t\tif _, found := s.Namespaces[strings.TrimPrefix(tag, \"schema:\")]; !found {\n\t\t\t\treturn false, fmt.Sprintf(\"server [%s] does not have schema %s\", s.Name(), tag)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// check if dbname prefix tag match server.Database\n\t\tif strings.HasPrefix(tag, \"dbname:\") {\n\t\t\tif s.Database != strings.TrimPrefix(tag, \"dbname:\") {\n\t\t\t\treturn false, fmt.Sprintf(\"server [%s] dbname does %s not match with query tag %s\", s.Name(), s.Database, tag)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// check if username prefix tag match server.Username\n\t\tif strings.HasPrefix(tag, \"username:\") {\n\t\t\tif s.Username != strings.TrimPrefix(tag, \"username:\") {\n\t\t\t\treturn false, fmt.Sprintf(\"server [%s] username [%s] does not match %s\", s.Name(), s.Username, tag)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// check server does not have given tag\n\t\tif strings.HasPrefix(tag, \"not:\") {\n\t\t\tif negTag := strings.TrimPrefix(tag, \"not:\"); s.HasTag(negTag) {\n\t\t\t\treturn false, fmt.Sprintf(\"server [%s] has tag %s that query %s forbid\", s.Name(), negTag, query.Name)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// check 3 default tags: cluster, primary, standby|replica\n\t\tswitch tag {\n\t\tcase \"cluster\":\n\t\t\tif s.Forked {\n\t\t\t\treturn false, fmt.Sprintf(\"cluster level query %s will not run on forked server %v\", query.Name, s.Name())\n\t\t\t}\n\t\t\tcontinue\n\t\tcase \"primary\", \"master\", \"leader\":\n\t\t\tif s.Recovery {\n\t\t\t\treturn false, fmt.Sprintf(\"primary-only query %s will not run on standby server %v\", query.Name, s.Name())\n\t\t\t}\n\t\t\tcontinue\n\t\tcase \"standby\", \"replica\", \"slave\":\n\t\t\tif !s.Recovery {\n\t\t\t\treturn false, fmt.Sprintf(\"standby-only query %s will not run on primary server %v\", query.Name, s.Name())\n\t\t\t}\n\t\t\tcontinue\n\t\tcase \"pgbouncer\":\n\t\t\tcontinue\n\t\tdefault:\n\t\t\t// if this tag is nether a pre-defined tag nor a prefixed pattern tag, check whether server have that tag\n\t\t\tif !s.HasTag(tag) {\n\t\t\t\treturn false, fmt.Sprintf(\"server [%s] does not have tag %s that query %s require\", s.Name(), tag, query.Name)\n\t\t\t}\n\t\t}\n\t}\n\treturn true, \"\"\n}\n\n// Explain will print all queries that registered to server\nfunc (s *Server) Explain() string {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\tvar res []string\n\tfor _, i := range s.Collectors {\n\t\tres = append(res, i.Explain())\n\t}\n\treturn strings.Join(res, \"\\n\")\n}\n\n// Stat will turn Server internal stats into HTML\nfunc (s *Server) Stat() string {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\tbuf := new(bytes.Buffer)\n\t//err := statsTemplate.Execute(buf, s)\n\t//if err != nil {\n\t//\tlogErrorf(\"fail to generate server stats html\")\n\t//\treturn fmt.Sprintf(\"fail to generate server stat html, %s\", err.Error())\n\t//}\n\tbuf.WriteString(fmt.Sprintf(\"%-24s %-10s %-10s %-10s %-10s %-10s %-6s %-10s\\n\", \"name\", \"total\", \"hit\", \"error\", \"skip\", \"metric\", \"ttl/s\", \"duration/ms\"))\n\tfor _, query := range s.Collectors {\n\t\tbuf.WriteString(fmt.Sprintf(\"%-24s %-10d %-10d %-10d %-10d %-10d %-6d %-10f\\n\",\n\t\t\tquery.Name,\n\t\t\tint(s.queryScrapeTotalCount[query.Name]),\n\t\t\tint(s.queryScrapeHitCount[query.Name]),\n\t\t\tint(s.queryScrapeErrorCount[query.Name]),\n\t\t\tint(s.queryScrapePredicateSkipCount[query.Name]),\n\t\t\tint(s.queryScrapeMetricCount[query.Name]),\n\t\t\tint(s.queryCacheTTL[query.Name]),\n\t\t\ts.queryScrapeDuration[query.Name]*1000,\n\t\t))\n\t}\n\treturn buf.String()\n}\n\n// ExplainHTML will print server stats in HTML format\nfunc (s *Server) ExplainHTML() string {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\tvar res []string\n\tfor _, i := range s.Collectors {\n\t\tres = append(res, i.HTML())\n\t}\n\treturn strings.Join(res, \"</br></br>\")\n}\n\n// Describe implement prometheus.Collector\nfunc (s *Server) Describe(ch chan<- *prometheus.Desc) {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\tfor _, instance := range s.Collectors {\n\t\tinstance.Describe(ch)\n\t}\n}\n\n// Collect implement prometheus.Collector interface\nfunc (s *Server) Collect(ch chan<- prometheus.Metric) {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\ts.scrapeBegin = time.Now() // This ts is used for cache expiration check\n\n\t// check server conn, gathering fact\n\tif s.err = s.beforeScrape(s); s.err != nil {\n\t\tlogDebugf(\"fail establishing connection to %s: %s\", s.Name(), s.err.Error())\n\t\tgoto final\n\t}\n\n\t// fact change (including first time) will incur a plan procedure\n\tif !s.Planned {\n\t\ts.Plan()\n\t}\n\n\t// First pass: execute all queries with Fatal flag\n\tif err := s.collectFatalQueries(ch); err != nil {\n\t\ts.err = err\n\t\tgoto final\n\t}\n\n\t// Second pass: execute remaining non-Fatal queries\n\ts.collectNonFatalQueries(ch)\n\nfinal:\n\ts.scrapeDone = time.Now() // This ts is used for cache expiration check\n\ts.totalTime += s.scrapeDone.Sub(s.scrapeBegin).Seconds()\n\ts.totalCount++\n\tif s.err != nil {\n\t\ts.UP = false\n\t\ts.errorCount++\n\t\tlogErrorf(\"fail scraping server [%s]: %s\", s.Name(), s.err.Error())\n\t} else {\n\t\ts.UP = true\n\t\tlogDebugf(\"server [%s] scraped in %v\",\n\t\t\ts.Name(), s.scrapeDone.Sub(s.scrapeBegin).Seconds())\n\t}\n}\n\n// collectFatalQueries executes all queries with Fatal flag and returns on first error\nfunc (s *Server) collectFatalQueries(ch chan<- prometheus.Metric) error {\n\tfor _, query := range s.Collectors {\n\t\tif !query.Fatal {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := s.executeQuery(query, ch); err != nil {\n\t\t\tlogErrorf(\"query [%s] error: %s\", query.Name, err)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// collectNonFatalQueries executes all non-Fatal queries and logs errors without stopping\nfunc (s *Server) collectNonFatalQueries(ch chan<- prometheus.Metric) {\n\tfor _, query := range s.Collectors {\n\t\tif query.Fatal {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := s.executeQuery(query, ch); err != nil {\n\t\t\tlogWarnf(\"query [%s] error skipped: %s\", query.Name, err)\n\t\t}\n\t}\n}\n\n// executeQuery runs a single query and updates its metrics\nfunc (s *Server) executeQuery(query *Collector, ch chan<- prometheus.Metric) error {\n\tquery.Collect(ch)\n\ts.queryCacheTTL[query.Name] = query.cacheTTL()\n\ts.queryScrapeTotalCount[query.Name]++\n\ts.queryScrapeMetricCount[query.Name] = float64(query.ResultSize())\n\ts.queryScrapeDuration[query.Name] = query.scrapeDuration.Seconds()\n\n\tif query.Error() != nil {\n\t\ts.queryScrapeErrorCount[query.Name]++\n\t\treturn query.Error()\n\t}\n\n\tif query.CacheHit() {\n\t\ts.queryScrapeHitCount[query.Name]++\n\t}\n\n\t// Update predicate skip count if applicable\n\tif len(query.PredicateQueries) > 0 {\n\t\tskipped, _ := query.PredicateSkip()\n\t\tif skipped {\n\t\t\ts.queryScrapePredicateSkipCount[query.Name]++\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// HasTag tells whether this server have specific tag\nfunc (s *Server) HasTag(tag string) bool {\n\tfor _, t := range s.Tags {\n\t\tif t == tag {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Duration returns last scrape duration in float64 seconds\nfunc (s *Server) Duration() float64 {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\tsec := s.scrapeDone.Sub(s.scrapeBegin).Seconds()\n\treturn sec\n}\n\n// Uptime returns servers's uptime\nfunc (s *Server) Uptime() float64 {\n\treturn time.Since(s.serverInit).Seconds()\n}\n\n/* ================ Server Creation ================ */\n\n// NewServer will check dsn, but not trying to connect\nfunc NewServer(dsn string, opts ...ServerOpt) *Server {\n\ts := &Server{dsn: dsn}\n\tfor _, opt := range opts {\n\t\topt(s)\n\t}\n\ts.Database = ParseDatname(dsn)\n\tif s.Database != \"pgbouncer\" {\n\t\ts.PgbouncerMode = false\n\t\ts.beforeScrape = PostgresPrecheck\n\t} else {\n\t\tlogInfof(\"datname pgbouncer detected, enabling pgbouncer mode\")\n\t\ts.PgbouncerMode = true\n\t\ts.beforeScrape = PgbouncerPrecheck\n\t}\n\ts.MaxConn = 1\n\ts.Databases = make(map[string]bool, 1)\n\ts.serverInit = time.Now()\n\treturn s\n}\n\n// ServerOpt configures Server\ntype ServerOpt func(*Server)\n\n// WithConstLabel copy constant label map to server\nfunc WithConstLabel(labels prometheus.Labels) ServerOpt {\n\treturn func(s *Server) {\n\t\tif labels == nil {\n\t\t\ts.labels = nil\n\t\t} else {\n\t\t\ts.labels = make(prometheus.Labels, len(labels))\n\t\t\tfor k, v := range labels {\n\t\t\t\ts.labels[k] = v\n\t\t\t}\n\t\t}\n\t}\n}\n\n// WithCachePolicy will pass cache option to server\nfunc WithCachePolicy(disableCache bool) ServerOpt {\n\treturn func(s *Server) {\n\t\ts.DisableCache = disableCache\n\t}\n}\n\n// WithQueries set server's default query set\nfunc WithQueries(queries map[string]*Query) ServerOpt {\n\treturn func(s *Server) {\n\t\ts.queries = queries\n\t}\n}\n\n// WithServerTags will mark server only execute query without cluster tag\nfunc WithServerTags(tags []string) ServerOpt {\n\treturn func(s *Server) {\n\t\ts.Tags = tags\n\t}\n}\n\n// WithServerConnectTimeout will set a connect timeout for server precheck queries\n// otherwise, a default value 100ms will be used.\n// Increase this value if you are monitoring a remote (cross-DC, cross-AZ) instance\nfunc WithServerConnectTimeout(timeout int) ServerOpt {\n\treturn func(s *Server) {\n\t\ts.ConnectTimeout = timeout\n\t}\n}\n"
  },
  {
    "path": "exporter/server_exporter_test.go",
    "content": "package exporter\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\nfunc makeGaugeQuery(name string, priority int, tags ...string) *Query {\n\treturn &Query{\n\t\tName:     name,\n\t\tBranch:   name,\n\t\tSQL:      \"SELECT 'db' AS datname, 1 AS value\",\n\t\tTags:     tags,\n\t\tPriority: priority,\n\t\tColumns: map[string]*Column{\n\t\t\t\"datname\": {Name: \"datname\", Usage: LABEL, Desc: \"database\"},\n\t\t\t\"value\":   {Name: \"value\", Usage: GAUGE, Desc: \"value\"},\n\t\t},\n\t\tColumnNames: []string{\"datname\", \"value\"},\n\t\tLabelNames:  []string{\"datname\"},\n\t\tMetricNames: []string{\"value\"},\n\t}\n}\n\nfunc TestParseSemver(t *testing.T) {\n\tif got := ParseSemver(\"1.2.3\"); got != 10203 {\n\t\tt.Fatalf(\"ParseSemver 1.2.3 = %d, want 10203\", got)\n\t}\n\tif got := ParseSemver(\"PgBouncer 1.22.1\"); got != 12201 {\n\t\tt.Fatalf(\"ParseSemver pgbouncer string = %d, want 12201\", got)\n\t}\n\tif got := ParseSemver(\"invalid\"); got != 0 {\n\t\tt.Fatalf(\"ParseSemver invalid = %d, want 0\", got)\n\t}\n}\n\nfunc TestNewServerAndBasics(t *testing.T) {\n\tlabels := prometheus.Labels{\"k\": \"v\"}\n\tq := map[string]*Query{\"q\": makeGaugeQuery(\"q\", 1)}\n\n\ts := NewServer(\n\t\t\"postgresql://user:pass@localhost:5432/postgres?sslmode=disable\",\n\t\tWithConstLabel(labels),\n\t\tWithCachePolicy(true),\n\t\tWithQueries(q),\n\t\tWithServerTags([]string{\"tag1\"}),\n\t\tWithServerConnectTimeout(250),\n\t)\n\n\tif s.PgbouncerMode {\n\t\tt.Fatal(\"postgres database should not trigger pgbouncer mode\")\n\t}\n\tif !s.DisableCache {\n\t\tt.Fatal(\"WithCachePolicy(true) not applied\")\n\t}\n\tif s.ConnectTimeout != 250 {\n\t\tt.Fatalf(\"ConnectTimeout = %d, want 250\", s.ConnectTimeout)\n\t}\n\tif !s.HasTag(\"tag1\") {\n\t\tt.Fatal(\"WithServerTags not applied\")\n\t}\n\tif got := s.GetConnectTimeout(); got != 250*time.Millisecond {\n\t\tt.Fatalf(\"GetConnectTimeout = %v, want 250ms\", got)\n\t}\n\tif got := s.Name(); got != \"postgres\" {\n\t\tt.Fatalf(\"Name = %s, want postgres\", got)\n\t}\n\n\ts.Database = \"\"\n\tif got := s.Name(); !strings.Contains(got, \"postgresql://\") {\n\t\tt.Fatalf(\"Name with empty database should return redacted dsn, got: %s\", got)\n\t}\n\n\ts2 := NewServer(\"postgresql://user:pass@localhost:5432/pgbouncer\")\n\tif !s2.PgbouncerMode {\n\t\tt.Fatal(\"pgbouncer database should trigger pgbouncer mode\")\n\t}\n}\n\nfunc TestServerCompatible(t *testing.T) {\n\ts := NewServer(\"postgresql://user:pass@localhost:5432/postgres\")\n\ts.Version = 160000\n\ts.Recovery = false\n\ts.Database = \"postgres\"\n\ts.Username = \"monitor\"\n\ts.Extensions = map[string]bool{\"pg_stat_statements\": true}\n\ts.Namespaces = map[string]bool{\"public\": true}\n\ts.Tags = []string{\"foo\"}\n\n\ttests := []struct {\n\t\tname string\n\t\tq    *Query\n\t\tok   bool\n\t}{\n\t\t{name: \"skip\", q: &Query{Name: \"q\", Skip: true}, ok: false},\n\t\t{name: \"pgbouncer tag mismatch\", q: &Query{Name: \"q\", Tags: []string{\"pgbouncer\"}}, ok: false},\n\t\t{name: \"min version\", q: &Query{Name: \"q\", MinVersion: 170000}, ok: false},\n\t\t{name: \"max version\", q: &Query{Name: \"q\", MaxVersion: 160000}, ok: false},\n\t\t{name: \"extension exists\", q: &Query{Name: \"q\", Tags: []string{\"extension:pg_stat_statements\"}}, ok: true},\n\t\t{name: \"extension missing\", q: &Query{Name: \"q\", Tags: []string{\"extension:missing\"}}, ok: false},\n\t\t{name: \"schema exists\", q: &Query{Name: \"q\", Tags: []string{\"schema:public\"}}, ok: true},\n\t\t{name: \"schema missing\", q: &Query{Name: \"q\", Tags: []string{\"schema:private\"}}, ok: false},\n\t\t{name: \"dbname mismatch\", q: &Query{Name: \"q\", Tags: []string{\"dbname:other\"}}, ok: false},\n\t\t{name: \"username match\", q: &Query{Name: \"q\", Tags: []string{\"username:monitor\"}}, ok: true},\n\t\t{name: \"username mismatch\", q: &Query{Name: \"q\", Tags: []string{\"username:other\"}}, ok: false},\n\t\t{name: \"forbidden not tag\", q: &Query{Name: \"q\", Tags: []string{\"not:foo\"}}, ok: false},\n\t\t{name: \"server tag match\", q: &Query{Name: \"q\", Tags: []string{\"foo\"}}, ok: true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tgot, _ := s.Compatible(tt.q)\n\t\tif got != tt.ok {\n\t\t\tt.Fatalf(\"%s compatible = %v, want %v\", tt.name, got, tt.ok)\n\t\t}\n\t}\n\n\ts.Forked = true\n\tif ok, _ := s.Compatible(&Query{Name: \"q\", Tags: []string{\"cluster\"}}); ok {\n\t\tt.Fatal(\"cluster query should not run on forked server\")\n\t}\n\ts.Forked = false\n\n\ts.Recovery = true\n\tif ok, _ := s.Compatible(&Query{Name: \"q\", Tags: []string{\"primary\"}}); ok {\n\t\tt.Fatal(\"primary query should not run on recovery server\")\n\t}\n\tif ok, _ := s.Compatible(&Query{Name: \"q\", Tags: []string{\"replica\"}}); !ok {\n\t\tt.Fatal(\"replica query should run on recovery server\")\n\t}\n}\n\nfunc TestPlanResetAndCollectCached(t *testing.T) {\n\ts := NewServer(\"postgresql://user:pass@localhost:5432/postgres\")\n\ts.Version = 160000\n\ts.Database = \"postgres\"\n\ts.Username = \"monitor\"\n\ts.Namespaces = map[string]bool{\"public\": true}\n\ts.Extensions = map[string]bool{}\n\n\tq1 := makeGaugeQuery(\"q1\", 20)\n\tq2 := makeGaugeQuery(\"q2\", 10)\n\ts.queries = map[string]*Query{\"q1\": q1, \"q2\": q2}\n\n\ts.Plan()\n\tif !s.Planned {\n\t\tt.Fatal(\"Plan should mark server planned\")\n\t}\n\tif len(s.Collectors) != 2 {\n\t\tt.Fatalf(\"collector count = %d, want 2\", len(s.Collectors))\n\t}\n\tif s.Collectors[0].Name != \"q2\" || s.Collectors[1].Name != \"q1\" {\n\t\tt.Fatalf(\"collectors should be sorted by priority, got %s then %s\", s.Collectors[0].Name, s.Collectors[1].Name)\n\t}\n\n\t// Build one cached metric for q2, so Collect path does not need DB.\n\tc := s.Collectors[0]\n\tmetric := prometheus.MustNewConstMetric(c.descriptors[\"value\"], prometheus.GaugeValue, 1, \"db\")\n\tc.result = []prometheus.Metric{metric}\n\tc.TTL = 3600\n\tc.lastScrape = time.Now()\n\tc.err = nil\n\n\ts.beforeScrape = func(s *Server) error {\n\t\ts.UP = true\n\t\treturn nil\n\t}\n\ts.Collectors = []*Collector{c}\n\ts.ResetStats()\n\ts.Planned = true\n\n\tch := make(chan prometheus.Metric, 10)\n\ts.Collect(ch)\n\n\tif !s.UP {\n\t\tt.Fatal(\"Collect should keep server UP for successful cached query\")\n\t}\n\tif s.totalCount != 1 {\n\t\tt.Fatalf(\"totalCount = %v, want 1\", s.totalCount)\n\t}\n\tif s.queryScrapeTotalCount[c.Name] != 1 {\n\t\tt.Fatalf(\"queryScrapeTotalCount = %v, want 1\", s.queryScrapeTotalCount[c.Name])\n\t}\n\tif s.queryScrapeMetricCount[c.Name] != 1 {\n\t\tt.Fatalf(\"queryScrapeMetricCount = %v, want 1\", s.queryScrapeMetricCount[c.Name])\n\t}\n\tif s.queryScrapeHitCount[c.Name] != 1 {\n\t\tt.Fatalf(\"queryScrapeHitCount = %v, want 1\", s.queryScrapeHitCount[c.Name])\n\t}\n}\n\nfunc TestExporterServerLifecycleHelpers(t *testing.T) {\n\te := &Exporter{\n\t\tdsn:     \"postgresql://user:pass@localhost:5432/postgres?sslmode=disable\",\n\t\tservers: map[string]*Server{},\n\t\tqueries: map[string]*Query{\"q\": makeGaugeQuery(\"q\", 1)},\n\t}\n\n\te.CreateServer(\"db1\")\n\tif len(e.servers) != 1 {\n\t\tt.Fatalf(\"CreateServer count = %d, want 1\", len(e.servers))\n\t}\n\tsnapshot := e.IterateServer()\n\tif len(snapshot) != 1 || snapshot[0] == nil {\n\t\tt.Fatalf(\"IterateServer snapshot invalid: %#v\", snapshot)\n\t}\n\tif !snapshot[0].Forked {\n\t\tt.Fatal(\"CreateServer should mark new server as Forked\")\n\t}\n\n\te.RemoveServer(\"db1\")\n\tif len(e.servers) != 0 {\n\t\tt.Fatalf(\"RemoveServer count = %d, want 0\", len(e.servers))\n\t}\n}\n"
  },
  {
    "path": "exporter/testmain_test.go",
    "content": "package exporter\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestMain(m *testing.M) {\n\tLogger = configureLogger(\"error\", \"logfmt\")\n\tos.Exit(m.Run())\n}\n"
  },
  {
    "path": "exporter/utils.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"log/slog\"\n\t\"math\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\n/* ================ Logger ================ */\n\nfunc configureLogger(levelStr, formatStr string) *slog.Logger {\n\tvar level slog.Level\n\tswitch strings.ToLower(levelStr) {\n\tcase \"debug\":\n\t\tlevel = slog.LevelDebug\n\tcase \"info\":\n\t\tlevel = slog.LevelInfo\n\tcase \"warn\":\n\t\tlevel = slog.LevelWarn\n\tcase \"error\":\n\t\tlevel = slog.LevelError\n\tdefault:\n\t\tlevel = slog.LevelInfo // fallback to default info level\n\t}\n\n\topts := &slog.HandlerOptions{\n\t\tLevel: level,\n\t}\n\n\tvar handler slog.Handler\n\tswitch strings.ToLower(formatStr) {\n\tcase \"json\":\n\t\thandler = slog.NewJSONHandler(os.Stderr, opts)\n\tcase \"logfmt\", \"\":\n\t\thandler = slog.NewTextHandler(os.Stderr, opts)\n\tdefault:\n\t\t// Be resilient to misconfiguration: fall back to logfmt.\n\t\thandler = slog.NewTextHandler(os.Stderr, opts)\n\t}\n\n\treturn slog.New(handler)\n}\n\nfunc loggerOrDefault() *slog.Logger {\n\tif Logger != nil {\n\t\treturn Logger\n\t}\n\treturn slog.Default()\n}\n\n// logDebugf will log debug message\nfunc logDebugf(format string, v ...interface{}) {\n\tloggerOrDefault().Debug(fmt.Sprintf(format, v...))\n}\n\n// logInfof will log info message\nfunc logInfof(format string, v ...interface{}) {\n\tloggerOrDefault().Info(fmt.Sprintf(format, v...))\n}\n\n// logWarnf will log warning message\nfunc logWarnf(format string, v ...interface{}) {\n\tloggerOrDefault().Warn(fmt.Sprintf(format, v...))\n}\n\n// logErrorf will log error message\nfunc logErrorf(format string, v ...interface{}) {\n\tloggerOrDefault().Error(fmt.Sprintf(format, v...))\n}\n\n// logError will print error message directly\nfunc logError(msg string) {\n\tloggerOrDefault().Error(msg)\n}\n\n// logFatalf will log error message\nfunc logFatalf(format string, v ...interface{}) {\n\tloggerOrDefault().Error(fmt.Sprintf(format, v...))\n\tos.Exit(1)\n}\n\n/* ================ Auxiliaries ================ */\n\n// castFloat64 will cast datum into float64 with Column scale & default value.\n// Column.Scale/Column.Default are parsed when loading config, so this is hot-path safe.\nfunc castFloat64(t interface{}, c *Column) float64 {\n\tscale := 1.0\n\tif c != nil && c.hasScale {\n\t\tscale = c.scaleFactor\n\t}\n\n\tswitch v := t.(type) {\n\tcase int64:\n\t\treturn float64(v) * scale\n\tcase float64:\n\t\treturn v * scale\n\tcase time.Time:\n\t\treturn float64(v.Unix())\n\tcase []byte:\n\t\tstrV := string(v)\n\t\tresult, err := strconv.ParseFloat(strV, 64)\n\t\tif err != nil {\n\t\t\tlogWarnf(\"fail casting []byte to float64: %v\", t)\n\t\t\treturn math.NaN()\n\t\t}\n\t\treturn result * scale\n\tcase string:\n\t\tresult, err := strconv.ParseFloat(v, 64)\n\t\tif err != nil {\n\t\t\tlogWarnf(\"fail casting string to float64: %v\", t)\n\t\t\treturn math.NaN()\n\t\t}\n\t\treturn result * scale\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1.0\n\t\t}\n\t\treturn 0.0\n\tcase nil:\n\t\tif c != nil && c.hasDefault {\n\t\t\treturn c.defaultValue * scale\n\t\t}\n\t\treturn math.NaN()\n\tdefault:\n\t\tlogWarnf(\"fail casting unknown to float64: %v\", t)\n\t\treturn math.NaN()\n\t}\n}\n\n// castString will force interface{} into string\nfunc castString(t interface{}) string {\n\tswitch v := t.(type) {\n\tcase int64:\n\t\treturn fmt.Sprintf(\"%v\", v)\n\tcase float64:\n\t\treturn fmt.Sprintf(\"%v\", v)\n\tcase time.Time:\n\t\treturn fmt.Sprintf(\"%v\", v.Unix())\n\tcase nil:\n\t\treturn \"\"\n\tcase []byte:\n\t\t// Try and convert to string\n\t\treturn string(v)\n\tcase string:\n\t\treturn v\n\tcase bool:\n\t\tif v {\n\t\t\treturn \"true\"\n\t\t}\n\t\treturn \"false\"\n\tdefault:\n\t\tlogWarnf(\"fail casting unknown to string: %v\", t)\n\t\treturn \"\"\n\t}\n}\n\n// parseConstLabels turn param string into prometheus.Labels\nfunc parseConstLabels(s string) prometheus.Labels {\n\tlabels := make(prometheus.Labels)\n\ts = strings.TrimSpace(s)\n\tif len(s) == 0 {\n\t\treturn nil\n\t}\n\n\tparts := strings.Split(s, \",\")\n\tfor _, p := range parts {\n\t\tkeyValue := strings.SplitN(strings.TrimSpace(p), \"=\", 2)\n\t\tif len(keyValue) != 2 {\n\t\t\tlogErrorf(`malformed labels format %q, should be \"key=value\"`, p)\n\t\t\tcontinue\n\t\t}\n\t\tkey := strings.TrimSpace(keyValue[0])\n\t\tvalue := strings.TrimSpace(keyValue[1])\n\t\tif key == \"\" || value == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif err := validatePromLabelName(key); err != nil {\n\t\t\tlogWarnf(\"skip invalid const label name %q: %v\", key, err)\n\t\t\tcontinue\n\t\t}\n\t\tlabels[key] = value\n\t}\n\tif len(labels) == 0 {\n\t\treturn nil\n\t}\n\n\treturn labels\n}\n\n// parseCSV will turn a comma separated string into a []string\nfunc parseCSV(s string) (tags []string) {\n\ts = strings.TrimSpace(s)\n\tif len(s) == 0 {\n\t\treturn nil\n\t}\n\n\tparts := strings.Split(s, \",\")\n\tfor _, p := range parts {\n\t\tif tag := strings.TrimSpace(p); len(tag) > 0 {\n\t\t\ttags = append(tags, tag)\n\t\t}\n\t}\n\n\tif len(tags) == 0 {\n\t\treturn nil\n\t}\n\treturn\n}\n"
  },
  {
    "path": "exporter/utils_test.go",
    "content": "package exporter\n\nimport (\n\t\"math\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestParseCSV(t *testing.T) {\n\tif got := parseCSV(\"\"); got != nil {\n\t\tt.Fatalf(\"parseCSV empty = %v, want nil\", got)\n\t}\n\n\tgot := parseCSV(\" a, b,, c , \")\n\twant := []string{\"a\", \"b\", \"c\"}\n\tif !reflect.DeepEqual(got, want) {\n\t\tt.Fatalf(\"parseCSV result = %#v, want %#v\", got, want)\n\t}\n}\n\nfunc TestParseConstLabels(t *testing.T) {\n\tif got := parseConstLabels(\"\"); got != nil {\n\t\tt.Fatalf(\"parseConstLabels empty = %v, want nil\", got)\n\t}\n\n\tlabels := parseConstLabels(\"env=prod,region=us-east-1\")\n\tif labels[\"env\"] != \"prod\" || labels[\"region\"] != \"us-east-1\" {\n\t\tt.Fatalf(\"parseConstLabels valid result = %v\", labels)\n\t}\n\n\tlabels = parseConstLabels(\"token=a=b=c\")\n\tif labels[\"token\"] != \"a=b=c\" {\n\t\tt.Fatalf(\"parseConstLabels should preserve '=' in value, got %q\", labels[\"token\"])\n\t}\n\n\tlabels = parseConstLabels(\"bad,noeq=,=noval,ok=1\")\n\tif len(labels) != 1 || labels[\"ok\"] != \"1\" {\n\t\tt.Fatalf(\"parseConstLabels malformed handling = %v\", labels)\n\t}\n}\n\nfunc TestCastFloat64(t *testing.T) {\n\tnow := time.Unix(1700000000, 0)\n\n\twithScale := func(scale, def string) *Column {\n\t\tc := &Column{Scale: scale, Default: def}\n\t\tif err := c.parseNumbers(); err != nil {\n\t\t\tt.Fatalf(\"parseNumbers failed for scale=%q default=%q: %v\", scale, def, err)\n\t\t}\n\t\treturn c\n\t}\n\n\tif got := castFloat64(int64(3), withScale(\"2\", \"\")); got != 6 {\n\t\tt.Fatalf(\"int64 scale cast = %v, want 6\", got)\n\t}\n\tif got := castFloat64(float64(1.5), withScale(\"2\", \"\")); got != 3 {\n\t\tt.Fatalf(\"float64 scale cast = %v, want 3\", got)\n\t}\n\tif got := castFloat64(now, nil); got != float64(now.Unix()) {\n\t\tt.Fatalf(\"time cast = %v, want %v\", got, now.Unix())\n\t}\n\tif got := castFloat64([]byte(\"3.25\"), withScale(\"10\", \"\")); got != 32.5 {\n\t\tt.Fatalf(\"[]byte cast = %v, want 32.5\", got)\n\t}\n\tif got := castFloat64(\"2.5\", withScale(\"4\", \"\")); got != 10 {\n\t\tt.Fatalf(\"string cast = %v, want 10\", got)\n\t}\n\tif got := castFloat64(true, nil); got != 1 {\n\t\tt.Fatalf(\"bool true cast = %v, want 1\", got)\n\t}\n\tif got := castFloat64(false, nil); got != 0 {\n\t\tt.Fatalf(\"bool false cast = %v, want 0\", got)\n\t}\n\tif got := castFloat64(nil, withScale(\"\", \"2.5\")); got != 2.5 {\n\t\tt.Fatalf(\"nil default cast = %v, want 2.5\", got)\n\t}\n\tif got := castFloat64(nil, withScale(\"10\", \"2.5\")); got != 25 {\n\t\tt.Fatalf(\"nil default cast should apply scale: %v, want 25\", got)\n\t}\n\n\tif got := castFloat64(\"abc\", nil); !math.IsNaN(got) {\n\t\tt.Fatalf(\"invalid string cast = %v, want NaN\", got)\n\t}\n\tif got := castFloat64(struct{}{}, nil); !math.IsNaN(got) {\n\t\tt.Fatalf(\"unknown type cast = %v, want NaN\", got)\n\t}\n\n\t// Invalid numeric options should be rejected at parse time.\n\tif err := (&Column{Scale: \"bad\"}).parseNumbers(); err == nil {\n\t\tt.Fatal(\"parseNumbers should fail for invalid scale\")\n\t}\n\tif err := (&Column{Default: \"bad\"}).parseNumbers(); err == nil {\n\t\tt.Fatal(\"parseNumbers should fail for invalid default\")\n\t}\n}\n\nfunc TestCastString(t *testing.T) {\n\tnow := time.Unix(1700000000, 0)\n\tif got := castString(int64(3)); got != \"3\" {\n\t\tt.Fatalf(\"int64 cast = %q, want 3\", got)\n\t}\n\tif got := castString(float64(1.5)); got != \"1.5\" {\n\t\tt.Fatalf(\"float64 cast = %q, want 1.5\", got)\n\t}\n\tif got := castString(now); got != \"1700000000\" {\n\t\tt.Fatalf(\"time cast = %q, want 1700000000\", got)\n\t}\n\tif got := castString([]byte(\"abc\")); got != \"abc\" {\n\t\tt.Fatalf(\"[]byte cast = %q, want abc\", got)\n\t}\n\tif got := castString(true); got != \"true\" {\n\t\tt.Fatalf(\"bool true cast = %q, want true\", got)\n\t}\n\tif got := castString(nil); got != \"\" {\n\t\tt.Fatalf(\"nil cast = %q, want empty\", got)\n\t}\n}\n\nfunc TestConfigureLogger(t *testing.T) {\n\tif l := configureLogger(\"debug\", \"json\"); l == nil {\n\t\tt.Fatal(\"configureLogger returned nil for valid json format\")\n\t}\n\tif l := configureLogger(\"bad-level\", \"logfmt\"); l == nil {\n\t\tt.Fatal(\"configureLogger returned nil for fallback level\")\n\t}\n\tif l := configureLogger(\"info\", \"unknown-format\"); l == nil {\n\t\tt.Fatal(\"configureLogger returned nil for unknown format fallback\")\n\t}\n}\n\nfunc TestLogHelpersWithNilLogger(t *testing.T) {\n\torigin := Logger\n\tLogger = nil\n\tt.Cleanup(func() { Logger = origin })\n\n\tlogDebugf(\"debug %d\", 1)\n\tlogInfof(\"info %d\", 1)\n\tlogWarnf(\"warn %d\", 1)\n\tlogErrorf(\"error %d\", 1)\n\tlogError(\"plain error\")\n}\n"
  },
  {
    "path": "exporter/validate_labels.go",
    "content": "package exporter\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\n// validateConstLabelConflicts rejects constant label keys that would cause a\n// Prometheus panic due to duplicate label names between const and variable labels.\n//\n// This can happen when a user passes `--label key=value` (or PG_EXPORTER_LABEL)\n// where `key` equals one of a query's metric label names (after rename).\n//\n// When intro metrics are enabled, it also rejects keys that collide with the\n// exporter internal dynamic metric labels (currently: datname, query).\nfunc validateConstLabelConflicts(constLabels prometheus.Labels, queries map[string]*Query, disableIntro bool) error {\n\tif len(constLabels) == 0 {\n\t\treturn nil\n\t}\n\n\t// Exporter internal dynamic metrics use these variable labels.\n\tif !disableIntro {\n\t\tfor _, reserved := range []string{\"datname\", \"query\"} {\n\t\t\tif _, exists := constLabels[reserved]; exists {\n\t\t\t\treturn fmt.Errorf(\"const label %q conflicts with built-in exporter metric label %q\", reserved, reserved)\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(queries) == 0 {\n\t\treturn nil\n\t}\n\n\t// Stable iteration order for deterministic error messages.\n\tbranches := make([]string, 0, len(queries))\n\tfor b := range queries {\n\t\tbranches = append(branches, b)\n\t}\n\tsort.Strings(branches)\n\n\tfor _, branch := range branches {\n\t\tq := queries[branch]\n\t\tif q == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, lbl := range q.LabelList() {\n\t\t\tif _, exists := constLabels[lbl]; exists {\n\t\t\t\treturn fmt.Errorf(\"const label %q conflicts with query %q (name=%q) label %q\", lbl, branch, q.Name, lbl)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "exporter/validate_labels_test.go",
    "content": "package exporter\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestValidateConstLabelConflicts_QueryLabelOverlap(t *testing.T) {\n\tcfg := `\nq1:\n  query: SELECT 1 AS value, 'x' AS datname\n  metrics:\n    - datname:\n        usage: LABEL\n        rename: db\n        description: database\n    - value:\n        usage: GAUGE\n        description: value\n`\n\tqueries, err := ParseConfig([]byte(cfg))\n\tif err != nil {\n\t\tt.Fatalf(\"ParseConfig failed: %v\", err)\n\t}\n\n\tlabels := parseConstLabels(\"db=foo\")\n\tif err := validateConstLabelConflicts(labels, queries, false); err == nil {\n\t\tt.Fatal(\"expected const label conflict error, got nil\")\n\t}\n}\n\nfunc TestValidateConstLabelConflicts_InternalReservedLabels(t *testing.T) {\n\tlabels := parseConstLabels(\"datname=foo\")\n\tif err := validateConstLabelConflicts(labels, nil, false); err == nil {\n\t\tt.Fatal(\"expected reserved label conflict with intro metrics enabled, got nil\")\n\t}\n\t// When intro metrics are disabled, internal dynamic series are not emitted.\n\tif err := validateConstLabelConflicts(labels, nil, true); err != nil {\n\t\tt.Fatalf(\"expected no error with intro metrics disabled, got %v\", err)\n\t}\n}\n\nfunc TestNewExporterRejectsConstLabelConflict(t *testing.T) {\n\tcfg := `\nq1:\n  query: SELECT 1 AS value, 'x' AS datname\n  metrics:\n    - datname:\n        usage: LABEL\n        rename: db\n    - value:\n        usage: GAUGE\n`\n\t_, err := NewExporter(\n\t\t\"postgresql://u:p@localhost:5432/postgres?sslmode=disable\",\n\t\tWithConfigReader(strings.NewReader(cfg)),\n\t\tWithConstLabels(\"db=foo\"),\n\t)\n\tif err == nil {\n\t\tt.Fatal(\"expected NewExporter to fail on const label conflict, got nil\")\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module pg_exporter\n\ngo 1.26.2\n\nrequire (\n\tgithub.com/alecthomas/kingpin/v2 v2.4.0\n\tgithub.com/lib/pq v1.12.3\n\tgithub.com/prometheus/client_golang v1.23.2\n\tgithub.com/prometheus/common v0.67.5\n\tgithub.com/prometheus/exporter-toolkit v0.16.0\n\tgopkg.in/yaml.v3 v3.0.1\n)\n\nrequire (\n\tgithub.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/coreos/go-systemd/v22 v22.7.0 // indirect\n\tgithub.com/golang-jwt/jwt/v5 v5.3.1 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/jpillora/backoff v1.0.0 // indirect\n\tgithub.com/klauspost/compress v1.18.5 // indirect\n\tgithub.com/mdlayher/socket v0.6.0 // indirect\n\tgithub.com/mdlayher/vsock v1.2.1 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect\n\tgithub.com/prometheus/client_model v0.6.2 // indirect\n\tgithub.com/prometheus/procfs v0.20.1 // indirect\n\tgithub.com/rogpeppe/go-internal v1.14.1 // indirect\n\tgithub.com/xhit/go-str2duration/v2 v2.1.0 // indirect\n\tgo.yaml.in/yaml/v2 v2.4.4 // indirect\n\tgolang.org/x/crypto v0.50.0 // indirect\n\tgolang.org/x/net v0.53.0 // indirect\n\tgolang.org/x/oauth2 v0.36.0 // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/sys v0.43.0 // indirect\n\tgolang.org/x/text v0.36.0 // indirect\n\tgolang.org/x/time v0.15.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=\ngithub.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=\ngithub.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=\ngithub.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=\ngithub.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=\ngithub.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=\ngithub.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/lib/pq v1.12.0 h1:mC1zeiNamwKBecjHarAr26c/+d8V5w/u4J0I/yASbJo=\ngithub.com/lib/pq v1.12.0/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=\ngithub.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=\ngithub.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=\ngithub.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=\ngithub.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=\ngithub.com/mdlayher/socket v0.6.0 h1:ScZPaAGyO1icQnbFrhPM8mnXyMu9qukC1K4ZoM2IQKU=\ngithub.com/mdlayher/socket v0.6.0/go.mod h1:q7vozUAnxSqnjHc12Fik5yUKIzfZ8ITCfMkhOtE9z18=\ngithub.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=\ngithub.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=\ngithub.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=\ngithub.com/prometheus/exporter-toolkit v0.15.1 h1:XrGGr/qWl8Gd+pqJqTkNLww9eG8vR/CoRk0FubOKfLE=\ngithub.com/prometheus/exporter-toolkit v0.15.1/go.mod h1:P/NR9qFRGbCFgpklyhix9F6v6fFr/VQB/CVsrMDGKo4=\ngithub.com/prometheus/exporter-toolkit v0.16.0 h1:xT/j7L2XKF+VJd6B4fpUw6xWabHrSmsUf6mYmFqyu0s=\ngithub.com/prometheus/exporter-toolkit v0.16.0/go.mod h1:d1EL8Z9674xQe/iWhwP2wDyCEoBPbXVeqDbqAUsgJWY=\ngithub.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=\ngithub.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=\ngithub.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=\ngo.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=\ngolang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=\ngolang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=\ngolang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=\ngolang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=\ngolang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=\ngolang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=\ngolang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=\ngolang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=\ngolang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=\ngolang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=\ngolang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "hugo.yaml",
    "content": "baseURL: 'https://exp.pgsty.com/'\nlanguageCode: 'en'\ntitle: 'PG Exporter - Advanced PostgreSQL & pgBouncer Metrics Exporter'\n\nenableRobotsTXT: true\n# Parse Git commit\nenableGitInfo: true\n# enableEmoji: false\nhasCJKLanguage: true\n\nservices:\n  googleAnalytics:\n    ID: G-Y7HMTRQ6P7\n\ncontentDir: docs\n\noutputs:\n  home: [HTML]\n  page: [HTML]\n  section: [HTML, RSS]\n\nmodule:\n  imports:\n    - path: github.com/imfing/hextra\n\ndefaultContentLanguage: en\nlanguages:\n  en:\n    languageName: English\n    languageCode: en\n    weight: 1\n    title: PG Exporter\n    menu:\n      main:\n        - name: Pigsty\n          weight: 1\n          url: \"https://pigsty.io\"\n        - name: GitHub\n          weight: 2\n          url: \"https://github.com/pgsty/pg_exporter\"\n          params:\n            icon: github\n        - name: Search\n          weight: 3\n          params:\n            type: search\n      sidebar:\n        - identifier: more\n          name: Links\n          params:\n            type: separator\n          weight: 6\n        - identifier: pigsty\n          name: \"Pigsty ↗\"\n          url: \"https://pigsty.io\"\n          weight: 7\n        - identifier: pig-cli\n          name: \"PIG CLI ↗\"\n          url: \"https://pigsty.io/docs/pig\"\n          weight: 8\n        - identifier: pgext\n          name: \"PG Extensions ↗\"\n          url: \"https://pgext.cloud\"\n          weight: 10\n        - identifier: github-repo\n          name: \"GitHub repo ↗\"\n          url: \"https://github.com/pgsty/pg_exporter\"\n          weight: 11\n        - identifier: demo\n          name: \"Public Demo ↗\"\n          url: \"https://demo.pigsty.io\"\n          weight: 12\n        - identifier: vonng\n          name: \"Author: Vonng ↗\"\n          url: \"https://vonng.com/en/\"\n          weight: 13\n\nmarkup:\n  highlight:\n    noClasses: false\n  goldmark:\n    renderer:\n      unsafe: true\n    extensions:\n      passthrough:\n        delimiters:\n          block: [['\\[', '\\]'], ['$$', '$$']]\n          inline: [['\\(', '\\)']]\n        enable: true\n\nparams:\n  description: PG Exporter is an advanced PostgreSQL and pgBouncer metrics exporter for Prometheus, providing 600+ metrics with declarative YAML configuration.\n\n  sidebar:\n    autoCollapse: false\n\n  navbar:\n    displayTitle: true\n    displayLogo: true\n    logo:\n      path: /logo.png\n      dark: /logo.png\n    width: wide\n\n  page:\n    # full (100%), wide (90rem), normal (80rem)\n    width: full\n\n  theme:\n    # light | dark | system\n    default: system\n    displayToggle: true\n\n  footer:\n    enable: false\n    displayCopyright: true\n    displayPoweredBy: true\n    width: normal\n\n  # Display the last modification date\n  displayUpdatedDate: true\n  dateFormat: \"2006-01-02\"\n\n  # Search\n  # flexsearch is enabled by default\n  search:\n    enable: true\n    type: flexsearch\n\n    flexsearch:\n      # index page by: content | summary | heading | title\n      index: content\n      # full | forward | reverse | strict\n      # https://github.com/nextapps-de/flexsearch/#tokenizer-prefix-search\n      tokenize: forward\n\n  editURL:\n    enable: true\n    base: \"https://github.com/pgsty/pg_exporter/edit/main/content\"\n\n  toc:\n    displayTags: true\n\n  highlight:\n    copy:\n      enable: true\n      display: hover\n\n  comments:\n    enable: true\n    type: giscus\n\n    # https://giscus.app/\n    giscus:\n      repo: \"pgsty/pg_exporter\"\n      repoId: \"MDEwOlJlcG9zaXRvcnkyMjYyNzkxOTc\"\n      category: \"Announcements\"\n      categoryId: \"DIC_kwDODXy_Hc4Ct5Xv\"\n      mapping: pathname\n      strict: 0\n      reactionsEnabled: 1\n      emitMetadata: 0\n      inputPosition: bottom\n      lang: en\n      theme: transparent_dark\n\n"
  },
  {
    "path": "legacy/README.md",
    "content": "# Legacy Config Bundle (for PG 9.1 - 9.6)\n\nThis directory contains the **legacy pg_exporter config bundle** for **PostgreSQL 9.1 - 9.6** (EOL).\n\n- `pg_exporter.yml`: merged legacy config (ready to use)\n- `config/`: separated collector definitions (source of truth)\n\n## Generate / Update\n\nFrom the repository root:\n\n```bash\nmake conf9\n```\n\n## Usage\n\nUse the merged legacy config file:\n\n```bash\nPG_EXPORTER_CONFIG=legacy/pg_exporter.yml \\\nPG_EXPORTER_URL='postgres://user:pass@host:5432/postgres' \\\npg_exporter --auto-discovery --exclude-database=template0,template1\n```\n\nOr load separated collectors directly (directory mode):\n\n```bash\nPG_EXPORTER_CONFIG=legacy/config \\\nPG_EXPORTER_URL='postgres://user:pass@host:5432/postgres' \\\npg_exporter --auto-discovery --exclude-database=template0,template1\n```\n\n## Notes\n\n- PostgreSQL **9.0 is not supported**.\n- For PostgreSQL **10+**, use the default config in repo root: `pg_exporter.yml`.\n"
  },
  {
    "path": "legacy/config/0000-doc.yml",
    "content": "#==============================================================#\n# Desc      :   pg_exporter metrics collector definition (Legacy)\n# Ver       :   PostgreSQL 9.1 ~ 9.6 and pgbouncer 1.9~1.25+\n# Ctime     :   2019-12-09\n# Mtime     :   2026-02-07\n# Homepage  :   https://pigsty.io\n# Author    :   Ruohang Feng (rh@vonng.com)\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\n\n\n#==============================================================#\n# 1. Config File\n#==============================================================#\n# The configuration file for pg_exporter is a YAML file.\n# Default configurations are retrieved via following precedence:\n#     1. command line args:      --config=<config path>\n#     2. environment variables:  PG_EXPORTER_CONFIG=<config path>\n#     3. pg_exporter.yml        (Current directory)\n#     4. /etc/pg_exporter.yml   (config file)\n#     5. /etc/pg_exporter       (config dir)\n\n#==============================================================#\n# 2. Config Format\n#==============================================================#\n# pg_exporter config could be a single YAML file, or a directory containing a series of separated YAML files.\n# Each YAML config file consists of one or more metrics Collector definition, which are top-level objects.\n# If a directory is provided, all YAML in that directory will be merged in alphabetic order.\n\n#==============================================================#\n# 3. Version Compatibility\n#==============================================================#\n# Each collector has two optional version compatibility parameters: `min_version` and `max_version`.\n# These two parameters specify the version compatibility of the collector. If target postgres/pgbouncer's\n# version is less than `min_version`, or higher than `max_version`, the collector will not be installed.\n#\n# These two parameters are using PostgreSQL server version number format, which is a 6-digit integer\n# format as <major:2 digit><minor:2 digit>:<release: 2 digit>.\n#\n# For example:\n#   - 90100  stands for 9.1\n#   - 90600  stands for 9.6\n#   - 100000 stands for 10.0\n#\n# Version compatibility range is left-inclusive right-exclusive: [min, max)\n\n\n"
  },
  {
    "path": "legacy/config/0110-pg.yml",
    "content": "#==============================================================#\n# 0110 pg\n#==============================================================#\npg_primary_only:\n  name: pg\n  desc: PostgreSQL basic information (on primary)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      (('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n      (('x' || lpad(split_part(pg_current_xlog_insert_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_insert_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS insert_lsn,\n      (('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n      (('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n      NULL::BIGINT                                           AS receive_lsn,\n      NULL::BIGINT                                           AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      NULL::FLOAT                                            AS last_replay_time,\n      0::FLOAT                                               AS lag,\n      pg_is_in_recovery()                                    AS is_in_recovery,\n      FALSE                                                  AS is_wal_replay_paused;\n  tags: [ cluster, primary ]\n  ttl: 1\n  min_version: 90100\n  max_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\npg_replica_only:\n  name: pg\n  desc: PostgreSQL basic information (on replica, 9.1+)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      (('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n      NULL::BIGINT                                           AS insert_lsn,\n      NULL::BIGINT                                           AS write_lsn,\n      NULL::BIGINT                                           AS flush_lsn,\n      (('x' || lpad(split_part(pg_last_xlog_receive_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_last_xlog_receive_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS receive_lsn,\n      (('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      extract(EPOCH FROM pg_last_xact_replay_timestamp())    AS last_replay_time,\n      CASE WHEN pg_last_xlog_receive_location() = pg_last_xlog_replay_location() THEN 0\n          ELSE EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp()) END AS lag,\n      pg_is_in_recovery() AS is_in_recovery,\n      pg_is_xlog_replay_paused() AS is_wal_replay_paused;\n\n  tags: [ cluster, replica ]\n  ttl: 1\n  min_version: 90100\n  max_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\n\n"
  },
  {
    "path": "legacy/config/0120-pg_meta.yml",
    "content": "#==============================================================#\n# 0120 pg_meta\n#==============================================================#\npg_meta_96:\n  name: pg_meta\n  desc: PostgreSQL meta info for pg 9.6 (with pg_control_system)\n  query: |\n    SELECT\n      (SELECT system_identifier FROM pg_control_system())          AS cluster_id,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'cluster_name'), 'N/A') AS cluster_name,\n      (SELECT setting FROM pg_settings WHERE name = 'port')        AS listen_port,\n      (SELECT setting FROM pg_settings WHERE name = 'data_directory') AS data_dir,\n      (SELECT setting FROM pg_settings WHERE name = 'config_file') AS conf_path,\n      (SELECT setting FROM pg_settings WHERE name = 'hba_file')    AS hba_path,\n      (SELECT setting FROM pg_settings WHERE name = 'wal_level')   AS wal_level,\n      (SELECT setting FROM pg_settings WHERE name = 'server_encoding') AS encoding,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version') AS version,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version_num') AS ver_num,\n      version()                                                   AS ver_str,\n      (SELECT setting FROM pg_settings WHERE name = 'shared_preload_libraries') AS extensions,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'primary_conninfo'), 'N/A') AS primary_conninfo,\n      1                                                           AS info;\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\npg_meta_91:\n  name: pg_meta\n  desc: PostgreSQL meta info for pg 9.1 - 9.5\n  query: |\n    SELECT\n      'N/A'                                                      AS cluster_id,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'cluster_name'), 'N/A') AS cluster_name,\n      (SELECT setting FROM pg_settings WHERE name = 'port')       AS listen_port,\n      (SELECT setting FROM pg_settings WHERE name = 'data_directory') AS data_dir,\n      (SELECT setting FROM pg_settings WHERE name = 'config_file') AS conf_path,\n      (SELECT setting FROM pg_settings WHERE name = 'hba_file')   AS hba_path,\n      (SELECT setting FROM pg_settings WHERE name = 'wal_level')  AS wal_level,\n      (SELECT setting FROM pg_settings WHERE name = 'server_encoding') AS encoding,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version') AS version,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version_num') AS ver_num,\n      version()                                                  AS ver_str,\n      (SELECT setting FROM pg_settings WHERE name = 'shared_preload_libraries') AS extensions,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'primary_conninfo'), 'N/A') AS primary_conninfo,\n      1                                                          AS info;\n  ttl: 10\n  min_version: 90100\n  max_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\n\n"
  },
  {
    "path": "legacy/config/0130-pg_setting.yml",
    "content": "#==============================================================#\n# 0130 pg_setting\n#==============================================================#\n# Key PostgreSQL configuration parameters for PostgreSQL 9.1 - 9.6\n# Use scalar subquery on pg_settings for \"missing_ok\" semantics (return NULL if not exist)\npg_setting:\n  name: pg_setting\n  desc: PostgreSQL shared configuration parameters (legacy 9.1-9.6)\n  query: |\n    SELECT\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_connections')                   AS max_connections,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_prepared_transactions')         AS max_prepared_transactions,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_locks_per_transaction')         AS max_locks_per_transaction,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_worker_processes')              AS max_worker_processes,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_parallel_workers')              AS max_parallel_workers,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_parallel_workers_per_gather')   AS max_parallel_workers_per_gather,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_parallel_maintenance_workers')  AS max_parallel_maintenance_workers,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_replication_slots')             AS max_replication_slots,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_wal_senders')                   AS max_wal_senders,\n      (SELECT setting::int FROM pg_settings WHERE name = 'block_size')                        AS block_size,\n      (SELECT setting::int FROM pg_settings WHERE name = 'wal_block_size')                    AS wal_block_size,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'segment_size')                                        AS segment_size,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'wal_segment_size')                                    AS wal_segment_size,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'data_checksums') AS data_checksums,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'wal_log_hints')  AS wal_log_hints,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'fsync')          AS fsync,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'full_page_writes') AS full_page_writes,\n      (SELECT CASE setting WHEN 'minimal' THEN 1 WHEN 'archive' THEN 2 WHEN 'hot_standby' THEN 3 ELSE 0 END FROM pg_settings WHERE name = 'wal_level') AS wal_level,\n      (SELECT setting::int FROM pg_settings WHERE name = 'checkpoint_segments')               AS checkpoint_segments,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'min_wal_size')                                        AS min_wal_size,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'max_wal_size')                                        AS max_wal_size,\n      (SELECT setting::int FROM pg_settings WHERE name = 'wal_keep_segments')                 AS wal_keep_segments,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'shared_buffers')                                      AS shared_buffers,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'work_mem')                                            AS work_mem,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'maintenance_work_mem')                                AS maintenance_work_mem,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'effective_cache_size')                                AS effective_cache_size,\n      (SELECT CASE setting WHEN 'off' THEN 0 WHEN 'on' THEN 1 WHEN 'always' THEN 2 ELSE -1 END FROM pg_settings WHERE name = 'archive_mode') AS archive_mode,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'autovacuum') AS autovacuum,\n      (SELECT setting::int FROM pg_settings WHERE name = 'autovacuum_max_workers')            AS autovacuum_max_workers,\n      (SELECT setting::int FROM pg_settings WHERE name = 'checkpoint_timeout')                AS checkpoint_timeout,\n      (SELECT setting::float FROM pg_settings WHERE name = 'checkpoint_completion_target')    AS checkpoint_completion_target,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'hot_standby') AS hot_standby,\n      (SELECT CASE setting\n        WHEN 'off' THEN 0 WHEN 'local' THEN 1 WHEN 'remote_write' THEN 2\n        WHEN 'on' THEN 3 WHEN 'remote_apply' THEN 4 ELSE -1 END\n        FROM pg_settings WHERE name = 'synchronous_commit')                                   AS synchronous_commit;\n\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - max_connections:                  { usage: GAUGE ,description: \"maximum number of concurrent connections to the database server\" }\n    - max_prepared_transactions:        { usage: GAUGE ,description: \"maximum number of transactions that can be in the prepared state simultaneously\" }\n    - max_locks_per_transaction:        { usage: GAUGE ,description: \"maximum number of locks per transaction\" }\n    - max_worker_processes:             { usage: GAUGE ,description: \"maximum number of background processes (9.4+)\" }\n    - max_parallel_workers:             { usage: GAUGE ,description: \"maximum number of parallel workers that can be active at one time (9.6+)\" }\n    - max_parallel_workers_per_gather:  { usage: GAUGE ,description: \"maximum number of parallel workers per Gather node (9.6+)\" }\n    - max_parallel_maintenance_workers: { usage: GAUGE ,description: \"maximum number of parallel maintenance workers (NULL on 9.x)\" }\n    - max_replication_slots:            { usage: GAUGE ,description: \"maximum number of replication slots (9.4+)\" }\n    - max_wal_senders:                  { usage: GAUGE ,description: \"maximum number of concurrent WAL sender connections\" }\n    - block_size:                       { usage: GAUGE ,description: \"database block size in bytes (default 8192)\" }\n    - wal_block_size:                   { usage: GAUGE ,description: \"WAL block size in bytes\" }\n    - segment_size:                     { usage: GAUGE ,description: \"database file segment size in bytes\" }\n    - wal_segment_size:                 { usage: GAUGE ,description: \"WAL segment size in bytes\" }\n    - data_checksums:                   { usage: GAUGE ,description: \"data checksums enabled, 1=on 0=off (9.3+)\" }\n    - wal_log_hints:                    { usage: GAUGE ,description: \"WAL log hints enabled, 1=on 0=off (9.4+)\" }\n    - fsync:                            { usage: GAUGE ,description: \"fsync enabled (CRITICAL for data safety), 1=on 0=off\" }\n    - full_page_writes:                 { usage: GAUGE ,description: \"full page writes enabled, 1=on 0=off\" }\n    - wal_level:                        { usage: GAUGE ,description: \"WAL level, 1=minimal 2=archive 3=hot_standby\" }\n    - checkpoint_segments:              { usage: GAUGE ,description: \"number of checkpoint segments (pre-9.5)\" }\n    - min_wal_size:                     { usage: GAUGE ,description: \"minimum WAL size in bytes (9.5+)\" }\n    - max_wal_size:                     { usage: GAUGE ,description: \"maximum WAL size in bytes (9.5+)\" }\n    - wal_keep_segments:                { usage: GAUGE ,description: \"WAL segments kept for standby replication (pg_basebackup/streaming)\" }\n    - shared_buffers:                   { usage: GAUGE ,description: \"shared buffer size in bytes\" }\n    - work_mem:                         { usage: GAUGE ,description: \"work memory size in bytes\" }\n    - maintenance_work_mem:             { usage: GAUGE ,description: \"maintenance work memory size in bytes\" }\n    - effective_cache_size:             { usage: GAUGE ,description: \"planner's assumption about effective OS cache size in bytes\" }\n    - archive_mode:                     { usage: GAUGE ,description: \"archive mode, 0=off 1=on 2=always\" }\n    - autovacuum:                       { usage: GAUGE ,description: \"autovacuum enabled, 1=on 0=off\" }\n    - autovacuum_max_workers:           { usage: GAUGE ,description: \"maximum number of autovacuum worker processes\" }\n    - checkpoint_timeout:               { usage: GAUGE ,description: \"checkpoint timeout in seconds\" }\n    - checkpoint_completion_target:     { usage: GAUGE ,description: \"checkpoint completion target (0.0-1.0)\" }\n    - hot_standby:                      { usage: GAUGE ,description: \"hot standby mode enabled, 1=on 0=off\" }\n    - synchronous_commit:               { usage: GAUGE ,description: \"synchronous commit level, 0=off 1=local 2=remote_write 3=on 4=remote_apply\" }\n\n\n"
  },
  {
    "path": "legacy/config/0210-pg_repl.yml",
    "content": "#==============================================================#\n# 0210 pg_repl\n#==============================================================#\npg_repl_94:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 9.4 - 9.6 (with backend_xmin)\n  query: |-\n    SELECT appname, usename, address, pid, client_port, state, sync_state, sync_priority, backend_xmin, lsn,\n           lsn - sent_lsn  AS sent_diff, lsn - write_lsn AS write_diff, lsn - flush_lsn AS flush_diff, lsn - replay_lsn AS replay_diff,\n           sent_lsn, write_lsn, flush_lsn, replay_lsn,\n           0::FLOAT AS write_lag, 0::FLOAT AS flush_lag, 0::FLOAT AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM (\n      SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n             CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n             CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n             sync_priority, backend_xmin::TEXT::BIGINT AS backend_xmin,\n             (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n             (('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS sent_lsn,\n             (('x' || lpad(split_part(write_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(write_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n             (('x' || lpad(split_part(flush_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(flush_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n             (('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n             backend_start\n      FROM pg_stat_replication,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90400\n  max_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback.\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (N/A on 9.x)\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (N/A on 9.x)\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it (N/A on 9.x)\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\npg_repl_92:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 9.2 - 9.3\n  query: |-\n    SELECT appname, usename, address, pid, client_port, state, sync_state, sync_priority, backend_xmin, lsn,\n           lsn - sent_lsn  AS sent_diff, lsn - write_lsn AS write_diff, lsn - flush_lsn AS flush_diff, lsn - replay_lsn AS replay_diff,\n           sent_lsn, write_lsn, flush_lsn, replay_lsn,\n           0::FLOAT AS write_lag, 0::FLOAT AS flush_lag, 0::FLOAT AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM (\n      SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n             CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n             CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n             sync_priority, 0::BIGINT AS backend_xmin,\n             (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n             (('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS sent_lsn,\n             (('x' || lpad(split_part(write_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(write_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n             (('x' || lpad(split_part(flush_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(flush_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n             (('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n             backend_start\n      FROM pg_stat_replication,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90200\n  max_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback (N/A before 9.4)\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (N/A on 9.x)\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (N/A on 9.x)\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it (N/A on 9.x)\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\npg_repl_91:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 9.1 (procpid, no state/sync columns)\n  query: |-\n    SELECT appname, usename, address, pid, client_port, state, sync_state, sync_priority, backend_xmin, lsn,\n           lsn - sent_lsn  AS sent_diff, lsn - write_lsn AS write_diff, lsn - flush_lsn AS flush_diff, lsn - replay_lsn AS replay_diff,\n           sent_lsn, write_lsn, flush_lsn, replay_lsn,\n           0::FLOAT AS write_lag, 0::FLOAT AS flush_lag, 0::FLOAT AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM (\n      SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, procpid::TEXT AS pid, client_port,\n             0::INT AS state, 0::INT AS sync_state, 0::INT AS sync_priority, 0::BIGINT AS backend_xmin,\n             (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n             (('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS sent_lsn,\n             (('x' || lpad(split_part(write_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(write_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n             (('x' || lpad(split_part(flush_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(flush_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n             (('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n             backend_start\n      FROM pg_stat_replication,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback (N/A before 9.4)\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (N/A on 9.x)\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (N/A on 9.x)\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it (N/A on 9.x)\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\n\n"
  },
  {
    "path": "legacy/config/0220-pg_sync_standby.yml",
    "content": "#==============================================================#\n# 0220 pg_sync_standby\n#==============================================================#\npg_sync_standby:\n  name: pg_sync_standby\n  desc: PostgreSQL synchronous standby status and names\n  query: |-\n    SELECT\n      CASE WHEN names <> '' THEN names ELSE '<null>' END AS names,\n      CASE WHEN names <> '' THEN 1 ELSE 0 END           AS enabled\n    FROM (SELECT current_setting('synchronous_standby_names') AS names) n;\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - names:   { usage: LABEL ,description: \"List of standby servers that can support synchronous replication\" }\n    - enabled: { usage: GAUGE ,description: \"Synchronous commit enabled, 1 if enabled, 0 if disabled\" }\n\n\n"
  },
  {
    "path": "legacy/config/0230-pg_downstream.yml",
    "content": "#==============================================================#\n# 0230 pg_downstream\n#==============================================================#\npg_downstream:\n  name: pg_downstream\n  desc: PostgreSQL replication client count (no state column on 9.1)\n  query: |-\n    SELECT 'connected' AS state, count(*) AS count FROM pg_stat_replication;\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - state: { usage: LABEL ,description: \"Replication client state\" }\n    - count: { usage: GAUGE ,description: \"Count of replication clients by state\" }\n\npg_downstream_92:\n  name: pg_downstream\n  desc: PostgreSQL replication client count (group by state)\n  query: |-\n    SELECT state, count(*) AS count FROM pg_stat_replication GROUP BY state;\n  ttl: 10\n  min_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - state: { usage: LABEL ,description: \"Replication client state\" }\n    - count: { usage: GAUGE ,description: \"Count of replication clients by state\" }\n\n\n"
  },
  {
    "path": "legacy/config/0240-pg_slot.yml",
    "content": "#==============================================================#\n# 0240 pg_slot\n#==============================================================#\npg_slot_96:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 9.6 (with active_pid, confirmed_flush_lsn)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname, datoid, active_pid,\n      active, FALSE AS temporary,\n      xmin::TEXT::BIGINT AS xmin, catalog_xmin::TEXT::BIGINT AS catalog_xmin,\n      restart_lsn, confirm_lsn, current_lsn - restart_lsn AS retained_bytes\n    FROM (\n      SELECT slot_name, slot_type, plugin, database, datoid, active_pid, active, xmin, catalog_xmin,\n        (('x' || lpad(split_part(restart_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(restart_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS restart_lsn,\n        (('x' || lpad(split_part(confirmed_flush_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(confirmed_flush_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS confirm_lsn,\n        (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS current_lsn\n      FROM pg_replication_slots,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90600\n  max_version: 100000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:      { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:      { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:         { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:        { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:         { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:     { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:         { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:      { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot (N/A on 9.x, always 0)\" }\n    - xmin:           { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:   { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:    { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:    { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes: { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\npg_slot_95:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 9.5 (no confirmed_flush_lsn)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname, datoid, active_pid,\n      active, FALSE AS temporary,\n      xmin::TEXT::BIGINT AS xmin, catalog_xmin::TEXT::BIGINT AS catalog_xmin,\n      restart_lsn, confirm_lsn, current_lsn - restart_lsn AS retained_bytes\n    FROM (\n      SELECT slot_name, slot_type, plugin, database, datoid, active_pid, active, xmin, catalog_xmin,\n        (('x' || lpad(split_part(restart_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(restart_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS restart_lsn,\n        0::BIGINT AS confirm_lsn,\n        (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS current_lsn\n      FROM pg_replication_slots,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90500\n  max_version: 90600\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:      { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:      { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:         { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:        { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:         { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:     { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:         { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:      { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot (N/A on 9.x, always 0)\" }\n    - xmin:           { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:   { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:    { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:    { usage: COUNTER  ,description: \"Confirmed flush lsn (N/A before 9.6, always 0)\" }\n    - retained_bytes: { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\npg_slot_94:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 9.4 (no active_pid, confirmed_flush_lsn)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname, datoid, active_pid,\n      active, FALSE AS temporary,\n      xmin::TEXT::BIGINT AS xmin, catalog_xmin::TEXT::BIGINT AS catalog_xmin,\n      restart_lsn, confirm_lsn, current_lsn - restart_lsn AS retained_bytes\n    FROM (\n      SELECT slot_name, slot_type, plugin, database, datoid, NULL::INT AS active_pid, active, xmin, catalog_xmin,\n        (('x' || lpad(split_part(restart_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(restart_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS restart_lsn,\n        0::BIGINT AS confirm_lsn,\n        (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS current_lsn\n      FROM pg_replication_slots,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90400\n  max_version: 90500\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:      { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:      { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:         { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:        { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:         { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:     { usage: GAUGE    ,description: \"Process ID is not available before 9.5 (NULL)\" }\n    - active:         { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:      { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot (N/A on 9.x, always 0)\" }\n    - xmin:           { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:   { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:    { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:    { usage: COUNTER  ,description: \"Confirmed flush lsn (N/A before 9.6, always 0)\" }\n    - retained_bytes: { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\n\n"
  },
  {
    "path": "legacy/config/0250-pg_recv.yml",
    "content": "#==============================================================#\n# 0250 pg_recv\n#==============================================================#\npg_recv_96:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics (9.6 - 12)\n  query: |-\n    SELECT \n      (regexp_match(conninfo, '.*host=(\\S+).*'))[1] AS sender_host,\n      (regexp_match(conninfo, '.*port=(\\S+).*'))[1] AS sender_port,\n      coalesce(slot_name, 'NULL')                    AS slot_name,\n      pid,\n      CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      (('x' || lpad(split_part(receive_start_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(receive_start_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS init_lsn,\n      receive_start_tli AS init_tli,\n      (('x' || lpad(split_part(received_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(received_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)      AS flush_lsn,\n      received_tli       AS flush_tli,\n      (('x' || lpad(split_part(latest_end_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(latest_end_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)    AS reported_lsn,\n      last_msg_send_time    AS msg_send_time,\n      last_msg_receipt_time AS msg_recv_time,\n      latest_end_time       AS reported_time,\n      now()                 AS time\n    FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  min_version: 90600\n  max_version: 130000\n  tags: [ cluster, replica ]\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\n\n"
  },
  {
    "path": "legacy/config/0270-pg_origin.yml",
    "content": "#==============================================================#\n# 0270 pg_origin\n#==============================================================#\n# skip by default, require additional privilege setup\n# GRANT SELECT ON pg_replication_origin, pg_replication_origin_status TO pg_monitor;\npg_origin:\n  name: pg_origin\n  desc: PostgreSQL replay state (approximate) for a certain origin\n  query: |-\n    SELECT roname,\n      (('x' || lpad(split_part(remote_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(remote_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS remote_lsn,\n      (('x' || lpad(split_part(local_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(local_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS local_lsn\n    FROM pg_replication_origin o LEFT JOIN pg_replication_origin_status os ON o.roident = os.local_id;\n  ttl: 10\n  min_version: 90500\n  skip: true\n  tags: [ cluster ]\n  metrics:\n    - roname:              { usage: LABEL     ,description: \"The external, user defined, name of a replication origin.\" }\n    - remote_lsn:          { usage: COUNTER   ,description: \"The origin node's LSN up to which data has been replicated.\" }\n    - local_lsn:           { usage: COUNTER   ,description: \"This node's LSN at which remote_lsn has been replicated.\" }\n\n\n"
  },
  {
    "path": "legacy/config/0310-pg_size.yml",
    "content": "#==============================================================#\n# 0310 pg_size\n#==============================================================#\npg_size:\n  name: pg_size\n  desc: PostgreSQL database size (legacy 9.1-9.6)\n  query: |-\n    SELECT datname, pg_database_size(oid) AS bytes FROM pg_database;\n  ttl: 60\n  timeout: 1\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Database name\" }\n    - bytes:   { usage: GAUGE ,description: \"Database size in bytes\" }\n\n\n"
  },
  {
    "path": "legacy/config/0320-pg_archiver.yml",
    "content": "#==============================================================#\n# 0320 pg_archiver\n#==============================================================#\npg_archiver:\n  name: pg_archiver\n  desc: PostgreSQL archiver process statistics\n  query: |-\n    SELECT archived_count AS finish_count,failed_count,\n      extract(epoch FROM last_archived_time) AS finish_time,\n      extract(epoch FROM last_failed_time) AS failed_time,\n      extract(epoch FROM stats_reset) AS reset_time\n    FROM pg_stat_archiver;\n\n  ttl: 60\n  min_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - finish_count:        { usage: COUNTER ,description: \"Number of WAL files that have been successfully archived\" }\n    - failed_count:        { usage: COUNTER ,description: \"Number of failed attempts for archiving WAL files\" }\n    - finish_time:         { usage: GAUGE   ,description: \"Time of the last successful archive operation\" }\n    - failed_time:         { usage: GAUGE   ,description: \"Time of the last failed archival operation\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which archive statistics were last reset\" }\n\n\n"
  },
  {
    "path": "legacy/config/0330-pg_bgwriter.yml",
    "content": "#==============================================================#\n# 0330 pg_bgwriter\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_bgwriter.html\npg_bgwriter_94:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics (PG 9.4-16)\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, buffers_clean, buffers_backend, maxwritten_clean, buffers_backend_fsync, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER              ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER              ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER              ,description: \"Number of buffers written during checkpoints\" }\n    - buffers_clean:         { usage: COUNTER              ,description: \"Number of buffers written by the background writer\" }\n    - buffers_backend:       { usage: COUNTER              ,description: \"Number of buffers written directly by a backend\" }\n    - maxwritten_clean:      { usage: COUNTER              ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_backend_fsync: { usage: COUNTER              ,description: \"Number of times a backend had to execute its own fsync call\" }\n    - buffers_alloc:         { usage: COUNTER              ,description: \"Number of buffers allocated\" }\n    - reset_time:            { usage: GAUGE                ,description: \"Time at which bgwriter statistics were last reset\" }\n\npg_bgwriter_91:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics (PG 9.1-9.3)\"\n  query: SELECT checkpoints_timed, checkpoints_req, 0::BIGINT AS checkpoint_write_time, 0::BIGINT AS checkpoint_sync_time, buffers_checkpoint, buffers_clean, buffers_backend, maxwritten_clean, buffers_backend_fsync, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90100\n  max_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER              ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER              ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent writing checkpoint files, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent syncing checkpoint files, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - buffers_checkpoint:    { usage: COUNTER              ,description: \"Number of buffers written during checkpoints\" }\n    - buffers_clean:         { usage: COUNTER              ,description: \"Number of buffers written by the background writer\" }\n    - buffers_backend:       { usage: COUNTER              ,description: \"Number of buffers written directly by a backend\" }\n    - maxwritten_clean:      { usage: COUNTER              ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_backend_fsync: { usage: COUNTER              ,description: \"Number of times a backend had to execute its own fsync call\" }\n    - buffers_alloc:         { usage: COUNTER              ,description: \"Number of buffers allocated\" }\n    - reset_time:            { usage: GAUGE                ,description: \"Time at which bgwriter statistics were last reset\" }\n\n\n"
  },
  {
    "path": "legacy/config/0331-pg_checkpointer.yml",
    "content": "#==============================================================#\n# 0331 pg_checkpointer\n#==============================================================#\npg_checkpointer_94:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 9.4-16\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER ,rename: timed                   ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER ,rename: req                     ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,rename: write_time ,scale: 1e-3 ,description: \"Total amount of time that has been spent writing checkpoint files, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,rename: sync_time  ,scale: 1e-3 ,description: \"Total amount of time that has been spent synchronizing checkpoint files to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER ,rename: buffers_written         ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                                    ,description: \"Time at which checkpointer statistics were last reset\" }\n\npg_checkpointer_91:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 9.1-9.3\"\n  query: SELECT checkpoints_timed, checkpoints_req, 0::BIGINT AS checkpoint_write_time, 0::BIGINT AS checkpoint_sync_time, buffers_checkpoint, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90100\n  max_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER ,rename: timed                   ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER ,rename: req                     ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,rename: write_time ,scale: 1e-3 ,description: \"Total amount of time that has been spent writing checkpoint files, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,rename: sync_time  ,scale: 1e-3 ,description: \"Total amount of time that has been spent synchronizing checkpoint files to disk, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - buffers_checkpoint:    { usage: COUNTER ,rename: buffers_written         ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                                    ,description: \"Time at which checkpointer statistics were last reset\" }\n\n\n"
  },
  {
    "path": "legacy/config/0340-pg_ssl.yml",
    "content": "#==============================================================#\n# 0340 pg_ssl\n#==============================================================#\npg_ssl:\n  name: pg_ssl\n  desc: PostgreSQL SSL client connection count\n  query: |\n    SELECT count(*) FILTER (WHERE ssl) AS enabled, count(*) FILTER ( WHERE NOT ssl) AS disabled FROM pg_stat_ssl;\n  ttl: 10\n  min_version: 90500\n  tags: [ cluster ]\n  metrics:\n    - enabled:            { usage: GAUGE   ,description: \"Number of client connection that use ssl\" }\n    - disabled:           { usage: GAUGE   ,description: \"Number of client connection that does not use ssl\" }\n\n\n"
  },
  {
    "path": "legacy/config/0350-pg_checkpoint.yml",
    "content": "#==============================================================#\n# 0350 pg_checkpoint\n#==============================================================#\npg_checkpoint:\n  name: pg_checkpoint\n  desc: checkpoint information from pg_control_checkpoint (9.6)\n  query: |-\n    SELECT \n      (('x' || lpad(split_part(checkpoint_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(checkpoint_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS checkpoint_lsn,\n      (('x' || lpad(split_part(redo_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(redo_location::text, '/', 2), 8, '0'))::bit(32)::bigint)       AS redo_lsn,\n      timeline_id AS tli,\n      prev_timeline_id AS prev_tli,\n      full_page_writes,\n      split_part(next_xid, ':', 1) AS next_xid_epoch,\n      split_part(next_xid, ':', 2) AS next_xid,\n      next_oid::BIGINT,\n      next_multixact_id::text::BIGINT,\n      next_multi_offset::text::BIGINT,\n      oldest_xid::text::BIGINT,\n      oldest_xid_dbid::text::BIGINT,\n      oldest_active_xid::text::BIGINT,\n      oldest_multi_xid::text::BIGINT,\n      oldest_multi_dbid::BIGINT,\n      oldest_commit_ts_xid::text::BIGINT,\n      newest_commit_ts_xid::text::BIGINT,\n      checkpoint_time                             AS time,\n      extract(epoch from now() - checkpoint_time) AS elapse\n    FROM pg_control_checkpoint();\n\n  ttl: 60\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - checkpoint_lsn:       { usage: COUNTER ,description: \"Latest checkpoint location\" }\n    - redo_lsn:             { usage: COUNTER ,description: \"Latest checkpoint's REDO location\" }\n    - tli:                  { usage: COUNTER ,description: \"Latest checkpoint's TimeLineID\" }\n    - prev_tli:             { usage: COUNTER ,description: \"Latest checkpoint's PrevTimeLineID\" }\n    - full_page_writes:     { usage: GAUGE   ,description: \"Latest checkpoint's full_page_writes enabled\" }\n    - next_xid_epoch:       { usage: COUNTER ,description: \"Latest checkpoint's NextXID epoch\" }\n    - next_xid:             { usage: COUNTER ,description: \"Latest checkpoint's NextXID xid\" }\n    - next_oid:             { usage: COUNTER ,description: \"Latest checkpoint's NextOID\" }\n    - next_multixact_id:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiXactId\" }\n    - next_multi_offset:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiOffset\" }\n    - oldest_xid:           { usage: COUNTER ,description: \"Latest checkpoint's oldestXID\" }\n    - oldest_xid_dbid:      { usage: GAUGE   ,description: \"Latest checkpoint's oldestXID's DB OID\" }\n    - oldest_active_xid:    { usage: COUNTER ,description: \"Latest checkpoint's oldestActiveXID\" }\n    - oldest_multi_xid:     { usage: COUNTER ,description: \"Latest checkpoint's oldestMultiXid\" }\n    - oldest_multi_dbid:    { usage: GAUGE   ,description: \"Latest checkpoint's oldestMulti's DB OID\" }\n    - oldest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's oldestCommitTsXid\" }\n    - newest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's newestCommitTsXid\" }\n    - time:                 { usage: COUNTER ,description: \"Time of latest checkpoint\" }\n    - elapse:               { usage: GAUGE   ,description: \"Seconds elapsed since latest checkpoint in seconds\" }\n\n\n"
  },
  {
    "path": "legacy/config/0355-pg_timeline.yml",
    "content": "#==============================================================#\n# 0355 pg_timeline\n#==============================================================#\npg_timeline:\n  name: pg_timeline\n  desc: Current timeline ID from primary or replica\n  query: |\n    SELECT COALESCE(\n      (SELECT received_tli FROM pg_stat_wal_receiver),\n      (SELECT timeline_id FROM pg_control_checkpoint())\n    ) AS id;\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - id: { usage: GAUGE ,description: \"Current timeline ID\" }\n\n\n"
  },
  {
    "path": "legacy/config/0360-pg_recovery.yml",
    "content": "#==============================================================#\n# 0360 pg_recovery\n#==============================================================#\npg_recovery:\n  name: pg_recovery\n  desc: PostgreSQL control recovery metrics (9.6)\n  query: |\n    SELECT min_recovery_end_timeline AS min_timeline,\n      (('x' || lpad(split_part(min_recovery_end_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(min_recovery_end_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS min_lsn,\n      (('x' || lpad(split_part(backup_start_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(backup_start_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)     AS backup_start_lsn,\n      (('x' || lpad(split_part(backup_end_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(backup_end_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)       AS backup_end_lsn,\n      end_of_backup_record_required AS require_record\n    FROM pg_control_recovery();\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster, replica ]\n  metrics:\n    - min_timeline:      { usage: COUNTER ,description: \"Min recovery ending loc's timeline\" }\n    - min_lsn:           { usage: COUNTER ,description: \"Minimum recovery ending location\" }\n    - backup_start_lsn:  { usage: COUNTER ,description: \"Backup start location\" }\n    - backup_end_lsn:    { usage: COUNTER ,description: \"Backup end location\" }\n    - require_record:    { usage: GAUGE   ,description: \"End-of-backup record required\" }\n\n\n"
  },
  {
    "path": "legacy/config/0410-pg_activity.yml",
    "content": "#==============================================================#\n# 0410 pg_activity\n#==============================================================#\npg_activity_92:\n  name: pg_activity\n  desc: PostgreSQL backend activity group by database and state (9.2+)\n  query: |-\n    SELECT datname, state, coalesce(count, 0) AS count, coalesce(max_duration, 0) AS max_duration, coalesce(max_tx_duration, 0) AS max_tx_duration, coalesce(max_conn_duration, 0) AS max_conn_duration FROM\n        (SELECT d.datname, a.state FROM pg_database d, unnest(ARRAY ['active','idle','idle in transaction','idle in transaction (aborted)','fastpath function call','disabled']) a(state) WHERE d.datallowconn AND NOT d.datistemplate) base\n          LEFT JOIN (SELECT datname, state, count(*) AS count, max(extract(epoch from now() - state_change)) AS max_duration, max(extract(epoch from now() - xact_start))\n          AS max_tx_duration, max(extract(epoch from now() - backend_start)) AS max_conn_duration FROM pg_stat_activity WHERE pid <> pg_backend_pid() GROUP BY 1,2) data USING (datname,state);\n  ttl: 10\n  min_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - state:             { usage: LABEL ,description: \"Current overall state of this backend.\" }\n    - count:             { usage: GAUGE ,description: \"Count of connection among (datname,state)\" }\n    - max_duration:      { usage: GAUGE ,description: \"Max duration since last state change among (datname, state)\" }\n    - max_tx_duration:   { usage: GAUGE ,description: \"Max transaction duration since state change among (datname, state)\" }\n    - max_conn_duration: { usage: GAUGE ,description: \"Max backend session duration since state change among (datname, state)\" }\n\npg_activity_91:\n  name: pg_activity\n  desc: PostgreSQL backend activity group by database (9.1)\n  query: |\n    SELECT\n      datname,\n      'active' AS state,\n      count(*) AS count,\n      max(extract(epoch from now() - query_start))   AS max_duration,\n      max(extract(epoch from now() - xact_start))    AS max_tx_duration,\n      max(extract(epoch from now() - backend_start)) AS max_conn_duration\n    FROM pg_stat_activity\n    WHERE procpid <> pg_backend_pid()\n      AND datname IS NOT NULL\n    GROUP BY datname;\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - state:             { usage: LABEL ,description: \"Current overall state of this backend (always active on 9.1)\" }\n    - count:             { usage: GAUGE ,description: \"Count of connection among (datname,state)\" }\n    - max_duration:      { usage: GAUGE ,description: \"Max duration since query start among (datname)\" }\n    - max_tx_duration:   { usage: GAUGE ,description: \"Max transaction duration among (datname)\" }\n    - max_conn_duration: { usage: GAUGE ,description: \"Max backend session duration among (datname)\" }\n\n\n"
  },
  {
    "path": "legacy/config/0420-pg_wait.yml",
    "content": "#==============================================================#\n# 0420 pg_wait\n#==============================================================#\npg_wait_96:\n  name: pg_wait\n  desc: PostgreSQL backend client count group by wait event type (9.6)\n  query: |\n    SELECT coalesce(datname, '_system') AS datname, coalesce(wait_event_type, 'Running') AS event, count(*) AS count FROM pg_stat_activity GROUP BY 1, 2;\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database, _system for global process\" }\n    - event:   { usage: LABEL ,description: \"Wait event type\" }\n    - count:   { usage: GAUGE ,description: \"Count of WaitEvent on target database\" }\n\npg_wait_91:\n  name: pg_wait\n  desc: PostgreSQL backend client count group by waiting flag (9.1-9.5)\n  query: |\n    SELECT coalesce(datname, '_system') AS datname, CASE WHEN waiting THEN 'Waiting' ELSE 'Running' END AS event, count(*) AS count FROM pg_stat_activity GROUP BY 1, 2;\n  ttl: 10\n  min_version: 90100\n  max_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database, _system for global process\" }\n    - event:   { usage: LABEL ,description: \"Waiting flag, Waiting or Running\" }\n    - count:   { usage: GAUGE ,description: \"Backend count group by waiting flag\" }\n\n\n"
  },
  {
    "path": "legacy/config/0440-pg_xact.yml",
    "content": "#==============================================================#\n# 0440 pg_xact\n#==============================================================#\npg_xact:\n  name: pg_xact\n  desc: PostgreSQL transaction identifier metrics\n  query: |\n    WITH snap(v) AS (SELECT txid_current_snapshot()),\n         xset(v) AS (SELECT txid_snapshot_xip(v) FROM snap),\n         xnum(v) AS (SELECT count(*) FROM xset),\n         xmin(v) AS (SELECT txid_snapshot_xmin(v) FROM snap),\n         xmax(v) AS (SELECT txid_snapshot_xmax(v) FROM snap)\n    SELECT xmin.v AS xmin, xmax.v AS xmax, xnum.v AS xnum\n    FROM xmin, xmax, xnum;\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - xmin: { usage: COUNTER ,description: \"Earliest txid that is still active\" }\n    - xmax: { usage: COUNTER ,description: \"First as-yet-unassigned txid\" }\n    - xnum: { usage: GAUGE   ,description: \"Current active transaction count\" }\n\n\n"
  },
  {
    "path": "legacy/config/0450-pg_lock.yml",
    "content": "#==============================================================#\n# 0450 pg_lock\n#==============================================================#\npg_lock:\n  name: pg_lock\n  desc: PostgreSQL lock distribution by mode and database\n  query: |\n    SELECT datname, mode, coalesce(count, 0) AS count\n      FROM (SELECT d.oid AS database, d.datname, l.mode FROM pg_database d, unnest(ARRAY ['AccessShareLock','RowShareLock','RowExclusiveLock','ShareUpdateExclusiveLock', 'ShareLock','ShareRowExclusiveLock','ExclusiveLock','AccessExclusiveLock']) l(mode) WHERE d.datallowconn AND NOT d.datistemplate) base\n      LEFT JOIN (SELECT database, mode, count(*) AS count FROM pg_locks WHERE database IS NOT NULL GROUP BY 1, 2) cnt USING (database, mode);\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - mode:    { usage: LABEL ,description: \"Name of the lock mode held or desired by this process\" }\n    - count:   { usage: GAUGE ,description: \"Number of locks of corresponding mode and database\" }\n\n\n"
  },
  {
    "path": "legacy/config/0460-pg_query.yml",
    "content": "#==============================================================#\n# 0460 pg_query\n#==============================================================#\npg_query_94:\n  name: pg_query\n  desc: PostgreSQL query statement metrics, require pg_stat_statements installed, 9.4 - 12\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_time) AS exec_time, sum(blk_read_time) + sum(blk_write_time) AS io_time,\n      sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n    FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90400\n  max_version: 130000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\npg_query_91:\n  name: pg_query\n  desc: PostgreSQL query statement metrics, require pg_stat_statements installed, 9.1 - 9.3 (no queryid)\n  query: |-\n    SELECT datname, md5(query) AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_time) AS exec_time, 0::FLOAT AS io_time,\n      sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, 0::BIGINT AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n    FROM pg_stat_statements s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90100\n  max_version: 90400\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"MD5 hash of query text (no queryid before 9.4)\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds (N/A before 9.4, always 0)\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement (N/A before 9.4, always 0)\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\n\n"
  },
  {
    "path": "legacy/config/0610-pg_db.yml",
    "content": "#==============================================================#\n# 0610 pg_db\n#==============================================================#\npg_db_92:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database (9.2 - 9.6)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total, blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,blk_read_time,blk_write_time, extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n  ttl: 10\n  min_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\npg_db_91:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database (9.1, fewer columns)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total, blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts, 0::BIGINT AS temp_files, 0::BIGINT AS temp_bytes, 0::BIGINT AS deadlocks, 0::BIGINT AS blk_read_time, 0::BIGINT AS blk_write_time,\n      extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database (N/A on 9.1, always 0)\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database (N/A on 9.1, always 0)\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database (N/A on 9.1, always 0)\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds (N/A on 9.1, always 0)\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds (N/A on 9.1, always 0)\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\n\n"
  },
  {
    "path": "legacy/config/0620-pg_db_confl.yml",
    "content": "#==============================================================#\n# 0620 pg_db_confl\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_database_conflicts.html\npg_db_confl:\n  name: pg_db_confl\n  desc: PostgreSQL database conflicts metrics for pg 9.1 - 9.6\n  query: SELECT datid,datname,confl_tablespace,confl_lock,confl_snapshot,confl_bufferpin,confl_deadlock FROM pg_stat_database_conflicts;\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster, replica ]\n  metrics:\n    - datid:                { usage: DISCARD }\n    - datname:              { usage: LABEL   ,description: \"Name of this database\" }\n    - confl_tablespace:     { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to dropped tablespaces\" }\n    - confl_lock:           { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to lock timeouts\" }\n    - confl_snapshot:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to old snapshots\" }\n    - confl_bufferpin:      { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to pinned buffers\" }\n    - confl_deadlock:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to deadlocks\" }\n\n\n"
  },
  {
    "path": "legacy/config/0700-pg_table.yml",
    "content": "#==============================================================#\n# 0700 pg_table\n#==============================================================#\npg_table_94:\n  name: pg_table\n  desc: PostgreSQL table metrics 9.4-9.6\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90400\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_91:\n  name: pg_table\n  desc: PostgreSQL table metrics 9.1-9.3 (no n_mod_since_analyze)\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       NULL::BIGINT AS n_mod_since_analyze, psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90100\n  max_version: 90400\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,t/toast/116\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed (N/A on 9.1-9.3, NULL)\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\n\n"
  },
  {
    "path": "legacy/config/0710-pg_index.yml",
    "content": "#==============================================================#\n# 0710 pg_index\n#==============================================================#\npg_index:\n  name: pg_index\n  desc: PostgreSQL index metrics (legacy 9.1-9.6)\n  query: |-\n    SELECT CURRENT_CATALOG AS datname,\n      psui.schemaname || '.' || psui.indexrelname AS idxname,\n      psui.schemaname || '.' || psui.relname      AS relname,\n      psui.indexrelid AS relid,\n      c.relpages, c.reltuples,\n      psui.idx_scan, psui.idx_tup_read, psui.idx_tup_fetch,\n      psio.idx_blks_read, psio.idx_blks_hit\n    FROM pg_stat_user_indexes psui\n      JOIN pg_statio_user_indexes psio ON psio.indexrelid = psui.indexrelid\n      JOIN pg_class c ON c.oid = psui.indexrelid\n    WHERE psui.schemaname !~ '^pg_' AND psui.schemaname !~ '^_' AND psui.schemaname !~ '^timescaledb' AND psui.schemaname !~ '^citus' AND psui.schemaname !~ '^columnar'\n      AND psui.schemaname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor')\n    ORDER BY psui.idx_tup_read DESC LIMIT 512;\n\n  ttl: 10\n  timeout: 1\n  min_version: 90100\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - idxname:             { usage: LABEL    ,description: \"Name of this index (full-qualified schema name)\" }\n    - relname:             { usage: LABEL    ,description: \"Name of the table for this index (full-qualified schema name)\" }\n    - relid:               { usage: LABEL    ,description: \"Relation oid of this index\" }\n    - relpages:            { usage: GAUGE    ,description: \"Size of the on-disk representation of this index in pages\" }\n    - reltuples:           { usage: GAUGE    ,description: \"Estimate relation tuples\" }\n    - idx_scan:            { usage: COUNTER  ,description: \"Number of index scans initiated on this index\" }\n    - idx_tup_read:        { usage: COUNTER  ,description: \"Number of index entries returned by scans on this index\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,description: \"Number of live table rows fetched by simple index scans using this index\" }\n    - idx_blks_read:       { usage: COUNTER  ,description: \"Number of disk blocks read from this index\" }\n    - idx_blks_hit:        { usage: COUNTER  ,description: \"Number of buffer hits in this index\" }\n\n\n"
  },
  {
    "path": "legacy/config/0720-pg_func.yml",
    "content": "#==============================================================#\n# 0720 pg_func\n#==============================================================#\npg_func:\n  desc: PostgreSQL function metrics\n  query: SELECT CURRENT_CATALOG AS datname, schemaname || '.' || funcname AS funcname, sum(calls) AS calls, sum(total_time) AS total_time, sum(self_time) AS self_time FROM pg_stat_user_functions GROUP BY 2 ORDER BY 4 DESC LIMIT 128;\n  ttl: 10\n  min_version: 90100\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Name of belonged database\" }\n    - funcname:            { usage: LABEL    ,description: \"Name of this function, may have multiple override\" }\n    - calls:               { usage: COUNTER  ,description: \"Number of times this function has been called\" }\n    - total_time:          { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function and all other functions called by it, in seconds\" }\n    - self_time:           { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function itself, not including other functions called by it, in seconds\" }\n\n\n"
  },
  {
    "path": "legacy/config/0740-pg_relkind.yml",
    "content": "#==============================================================#\n# 0740 pg_relkind\n#==============================================================#\npg_relkind:\n  name: pg_relkind\n  desc: Postgres relation count by kind\n  query: |\n    SELECT CURRENT_CATALOG AS datname, relkind, count(*) AS count\n    FROM pg_class\n    GROUP BY relkind;\n  ttl: 60\n  timeout: 1\n  min_version: 90100\n  metrics:\n    - datname: { usage: LABEL ,description: \"Database name\" }\n    - relkind: { usage: LABEL ,description: \"Relation kind (r,i,S,t,v,c,...)\" }\n    - count:   { usage: GAUGE ,description: \"Number of relations\" }\n\n\n"
  },
  {
    "path": "legacy/config/0810-pg_table_size.yml",
    "content": "#==============================================================#\n# 0810 pg_table_size\n#==============================================================#\npg_table_size:\n  desc: PostgreSQL table size metrics, quite slow\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || rel.relname AS relname,\n       pg_total_relation_size(rel.oid)       AS bytes,\n       pg_relation_size(rel.oid)             AS relsize,\n       pg_indexes_size(rel.oid)              AS indexsize,\n       pg_total_relation_size(reltoastrelid) AS toastsize\n    FROM pg_namespace nsp JOIN pg_class rel ON nsp.oid = rel.relnamespace\n    WHERE nspname <> ALL(ARRAY['pg_catalog', 'information_schema']) AND rel.relkind = 'r'\n    ORDER BY 3 DESC NULLS LAST LIMIT 256;\n\n  ttl: 300\n  timeout: 2\n  min_version: 90100\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified table name\" }\n    - bytes:               { usage: GAUGE    ,default: 0  ,description: \"Total bytes of this table (including toast, index, toast index)\" }\n    - relsize:             { usage: GAUGE    ,default: 0  ,description: \"Bytes of this table itself (main, vm, fsm)\" }\n    - indexsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of all related indexes of this table\" }\n    - toastsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of toast tables of this table\" }\n\n\n"
  },
  {
    "path": "legacy/config/0820-pg_table_bloat.yml",
    "content": "#==============================================================#\n# 0820 pg_table_bloat\n#==============================================================#\n# pg_table_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_table_bloat:\n  name: pg_table_bloat\n  desc: PostgreSQL table bloat metrics, require auxiliary view pg_table_bloat to work\n  query: SELECT datname, nspname || '.' || relname AS relname, size, ratio FROM pg_table_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 90400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified name of this table\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this table\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this table from 0 to 1\" }\n\n\n"
  },
  {
    "path": "legacy/config/0830-pg_index_bloat.yml",
    "content": "#==============================================================#\n# 0830 pg_index_bloat\n#==============================================================#\n# pg_index_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_index_bloat:\n  name: pg_index_bloat\n  desc: PostgreSQL index bloat metrics, require auxiliary view pg_index_bloat to work\n  query: SELECT datname, nspname || '.' || idxname AS idxname, size, ratio FROM pg_index_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 90400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - idxname:             { usage: LABEL    ,description: \"Schema qualified name of this index\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this index\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this index from 0 to 1\" }\n\n\n"
  },
  {
    "path": "legacy/config/0910-pgbouncer_list.yml",
    "content": "#==============================================================#\n# 0910 pgbouncer_list\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-lists\npgbouncer_list:\n  name: pgbouncer_list\n  desc: Pgbouncer entry list\n  query: SHOW LISTS;\n  ttl: 10\n  min_version: 10800\n  fatal: true\n  tags: [ pgbouncer ]\n  metrics:\n    - list:                { usage: LABEL                 ,description: \"Pgbouncer internal list name\" }\n    - items:               { usage: GAUGE                 ,description: \"Number of corresponding pgbouncer object\" }\n\n\n"
  },
  {
    "path": "legacy/config/0920-pgbouncer_database.yml",
    "content": "#==============================================================#\n# 0920 pgbouncer_database\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-databases\npgbouncer_database_124:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (since 1.24)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                       { usage: LABEL  ,rename: datname       ,description: \"Name of configured database entry\" }\n    - host:                       { usage: LABEL                         ,description: \"Host that pgbouncer will connects to\" }\n    - port:                       { usage: LABEL                         ,description: \"Port that pgbouncer will connects to\" }\n    - database:                   { usage: LABEL  ,rename: real_datname  ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:                 { usage: DISCARD }\n    - pool_size:                  { usage: GAUGE                         ,description: \"Maximum number of server connections\" }\n    - min_pool_size:              { usage: GAUGE                         ,description: \"Minimum number of server connections\" }\n    - reserve_pool_size:          { usage: GAUGE  ,rename: reserve_pool  ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:            { usage: GAUGE                         ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:                  { usage: DISCARD }\n    - load_balance_hosts:         { usage: DISCARD }\n    - max_connections:            { usage: GAUGE                         ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections:        { usage: GAUGE                         ,description: \"Current number of connections for this database\" }\n    - max_client_connections:     { usage: GAUGE                         ,description: \"Maximum number of allowed client connections for this pgbouncer instance\" }\n    - current_client_connections: { usage: GAUGE                         ,description: \"Current number of client connections for this database\" }\n    - paused:                     { usage: GAUGE                         ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:                   { usage: GAUGE                         ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_123:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats 1.23\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:     { usage: GAUGE                       ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_116:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.16-1.22)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 11600\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_108:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.08-1.15)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\n\n"
  },
  {
    "path": "legacy/config/0930-pgbouncer_stat.yml",
    "content": "#==============================================================#\n# 0930 pgbouncer_stat\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-stats\npgbouncer_stat_124:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (since 1.24)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - total_client_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created by clients\" }\n    - total_server_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created on a server.\" }\n    - total_bind_count:              { usage: COUNTER                  ,description: \"Total number of prepared statements readied for execution by clients and forwarded to postgres\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n    - avg_client_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created by clients\" }\n    - avg_server_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created on a server.\" }\n    - avg_bind_count:                { usage: GAUGE                    ,description: \"Average number of prepared statements readied for execution by clients and forwarded to postgres\" }\n\npgbouncer_stat_123:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.23)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\npgbouncer_stat_108:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.08 - 1.22)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 10800\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\n\n"
  },
  {
    "path": "legacy/config/0940-pgbouncer_pool.yml",
    "content": "#==============================================================#\n# 0940 pgbouncer_pool\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-pools\npgbouncer_pool_124:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.24+)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n    - load_balance_hosts:    { usage: LABEL,                                 description: \"The load_balance_hosts in use\" }\n\npgbouncer_pool_118:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.18-1.23)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11800\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n\npgbouncer_pool_116:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.16-1.17)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11600\n  max_version: 11800\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_cancel_req:         { usage: GAUGE, rename: cancel_clients,   description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\npgbouncer_pool_108:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.08-1.15)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\n\n"
  },
  {
    "path": "legacy/config/1800-pg_tsdb_hypertable.yml",
    "content": "#==============================================================#\n# 1800 pg_tsdb_hypertable\n#==============================================================#\n# this collector reqires timescaledb extension to be installed\npg_tsdb_hypertable:\n  name: pg_tsdb_hypertable\n  desc: TimescaleDB hypertable overview\n  query: |-\n    SELECT \n      current_database() AS datname,\n      format('%I.%I', hypertable_schema, hypertable_name) AS relname,\n      num_dimensions AS dimensions, num_chunks AS chunks,\n      compression_enabled::BOOLEAN::int AS compressed,\n      hypertable_size(format('\"%I\".\"%I\"', hypertable_schema, hypertable_name)::RegClass) AS bytes\n    FROM timescaledb_information.hypertables;\n\n  ttl: 60\n  timeout: 2\n  min_version: 90600\n  skip: true\n  tags: [ \"extension:timescaledb\", \"schema:timescaledb_information\" ]\n  metrics:\n    - datname:         { usage: LABEL ,description: \"database name\" }\n    - relname:         { usage: LABEL ,description: \"Hypertable relation name\" }\n    - dimensions:      { usage: GAUGE ,description: \"Number of partitioning dimensions\" }\n    - chunks:          { usage: GAUGE ,description: \"Total chunks of this hypertable\" }\n    - compressed:      { usage: GAUGE ,description: \"1 if compression enabled\" }\n    - bytes:           { usage: GAUGE ,description: \"Total size of hypertable in bytes\" }\n\n\n"
  },
  {
    "path": "legacy/config/1900-pg_citus.yml",
    "content": "#==============================================================#\n# 1900 pg_citus_node\n#==============================================================#\n# https://docs.citusdata.com/en/latest/develop/api_metadata.html#worker-node-table\npg_citus_node:\n  name: pg_citus_node\n  desc: Citus worker coordinator node inventory\n  query: |-\n    SELECT\n      CONCAT(nodename, ':', nodeport) AS node,\n      current_database() AS datname,\n      nodeid AS id,\n      groupid AS group,\n      hasmetadata::BOOLEAN::INT AS has_meta,\n      isactive::BOOLEAN::INT AS is_active,\n      metadatasynced::BOOLEAN::INT AS meta_synced,\n      shouldhaveshards::BOOLEAN::INT AS have_shards\n    FROM pg_dist_node;\n  ttl: 60\n  min_version: 90600\n  tags: [ \"extension:citus\" ]\n  metrics:\n    - node:             { usage: LABEL ,description: \"nodename:port of the PostgreSQL instance\" }\n    - datname:          { usage: LABEL ,description: \"database name\" }\n    - id:               { usage: GAUGE ,description: \"auto‑generated node identifier\" }\n    - group:            { usage: GAUGE ,description: \"replication group id (primary + secondaries)\" }\n    - has_meta:         { usage: GAUGE ,description: \"1 = internal use flag set\" }\n    - is_active:        { usage: GAUGE ,description: \"1 = node currently accepts shards\" }\n    - meta_synced:      { usage: GAUGE ,description: \"1 = metadata fully synced to node\" }\n    - have_shards:      { usage: GAUGE ,description: \"1 = rebalancer may place shards here\" }\n\n\n"
  },
  {
    "path": "legacy/config/2000-pg_heartbeat.yml",
    "content": "#==============================================================#\n# 2000 heartbeat\n#==============================================================#\n# this is a example of application monitoring and predicate queries\npg_heartbeat:\n  name: pg_heartbeat\n  desc: monitoring heartbeat in monitor.heartbeat table\n  predicate_queries:\n    - name: if heartbeat table exists\n      predicate_query: |\n        SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'monitor' AND table_name = 'heartbeat');\n  query: |-\n    SELECT id AS cluster_name, extract(EPOCH FROM ts) AS ts, lsn, txid FROM monitor.heartbeat;\n\n  ttl: 10\n  min_version: 90100\n  tags: [ \"dbname:postgres\", \"schema:monitor\" ]\n  skip: true\n  metrics:\n    - cluster_name:     { usage: LABEL   ,description: \"cluster_name param of this database cluster\" }\n    - ts:               { usage: GAUGE   ,description: \"unix timestamp of the heartbeat\" }\n    - lsn:              { usage: COUNTER ,description: \"lsn of the heartbeat\" }\n    - txid:             { usage: GAUGE   ,description: \"txid of the heartbeat\" }\n\n\n"
  },
  {
    "path": "legacy/pg_exporter.yml",
    "content": "#==============================================================#\n# Desc      :   pg_exporter metrics collector definition (Legacy)\n# Ver       :   PostgreSQL 9.1 ~ 9.6 and pgbouncer 1.9~1.25+\n# Ctime     :   2019-12-09\n# Mtime     :   2026-02-07\n# Homepage  :   https://pigsty.io\n# Author    :   Ruohang Feng (rh@vonng.com)\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\n\n\n#==============================================================#\n# 1. Config File\n#==============================================================#\n# The configuration file for pg_exporter is a YAML file.\n# Default configurations are retrieved via following precedence:\n#     1. command line args:      --config=<config path>\n#     2. environment variables:  PG_EXPORTER_CONFIG=<config path>\n#     3. pg_exporter.yml        (Current directory)\n#     4. /etc/pg_exporter.yml   (config file)\n#     5. /etc/pg_exporter       (config dir)\n\n#==============================================================#\n# 2. Config Format\n#==============================================================#\n# pg_exporter config could be a single YAML file, or a directory containing a series of separated YAML files.\n# Each YAML config file consists of one or more metrics Collector definition, which are top-level objects.\n# If a directory is provided, all YAML in that directory will be merged in alphabetic order.\n\n#==============================================================#\n# 3. Version Compatibility\n#==============================================================#\n# Each collector has two optional version compatibility parameters: `min_version` and `max_version`.\n# These two parameters specify the version compatibility of the collector. If target postgres/pgbouncer's\n# version is less than `min_version`, or higher than `max_version`, the collector will not be installed.\n#\n# These two parameters are using PostgreSQL server version number format, which is a 6-digit integer\n# format as <major:2 digit><minor:2 digit>:<release: 2 digit>.\n#\n# For example:\n#   - 90100  stands for 9.1\n#   - 90600  stands for 9.6\n#   - 100000 stands for 10.0\n#\n# Version compatibility range is left-inclusive right-exclusive: [min, max)\n\n\n#==============================================================#\n# 0110 pg\n#==============================================================#\npg_primary_only:\n  name: pg\n  desc: PostgreSQL basic information (on primary)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      (('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n      (('x' || lpad(split_part(pg_current_xlog_insert_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_insert_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS insert_lsn,\n      (('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n      (('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_current_xlog_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n      NULL::BIGINT                                           AS receive_lsn,\n      NULL::BIGINT                                           AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      NULL::FLOAT                                            AS last_replay_time,\n      0::FLOAT                                               AS lag,\n      pg_is_in_recovery()                                    AS is_in_recovery,\n      FALSE                                                  AS is_wal_replay_paused;\n  tags: [ cluster, primary ]\n  ttl: 1\n  min_version: 90100\n  max_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\npg_replica_only:\n  name: pg\n  desc: PostgreSQL basic information (on replica, 9.1+)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      (('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n      NULL::BIGINT                                           AS insert_lsn,\n      NULL::BIGINT                                           AS write_lsn,\n      NULL::BIGINT                                           AS flush_lsn,\n      (('x' || lpad(split_part(pg_last_xlog_receive_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_last_xlog_receive_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS receive_lsn,\n      (('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(pg_last_xlog_replay_location()::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      extract(EPOCH FROM pg_last_xact_replay_timestamp())    AS last_replay_time,\n      CASE WHEN pg_last_xlog_receive_location() = pg_last_xlog_replay_location() THEN 0\n          ELSE EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp()) END AS lag,\n      pg_is_in_recovery() AS is_in_recovery,\n      pg_is_xlog_replay_paused() AS is_wal_replay_paused;\n\n  tags: [ cluster, replica ]\n  ttl: 1\n  min_version: 90100\n  max_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\n\n#==============================================================#\n# 0120 pg_meta\n#==============================================================#\npg_meta_96:\n  name: pg_meta\n  desc: PostgreSQL meta info for pg 9.6 (with pg_control_system)\n  query: |\n    SELECT\n      (SELECT system_identifier FROM pg_control_system())          AS cluster_id,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'cluster_name'), 'N/A') AS cluster_name,\n      (SELECT setting FROM pg_settings WHERE name = 'port')        AS listen_port,\n      (SELECT setting FROM pg_settings WHERE name = 'data_directory') AS data_dir,\n      (SELECT setting FROM pg_settings WHERE name = 'config_file') AS conf_path,\n      (SELECT setting FROM pg_settings WHERE name = 'hba_file')    AS hba_path,\n      (SELECT setting FROM pg_settings WHERE name = 'wal_level')   AS wal_level,\n      (SELECT setting FROM pg_settings WHERE name = 'server_encoding') AS encoding,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version') AS version,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version_num') AS ver_num,\n      version()                                                   AS ver_str,\n      (SELECT setting FROM pg_settings WHERE name = 'shared_preload_libraries') AS extensions,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'primary_conninfo'), 'N/A') AS primary_conninfo,\n      1                                                           AS info;\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\npg_meta_91:\n  name: pg_meta\n  desc: PostgreSQL meta info for pg 9.1 - 9.5\n  query: |\n    SELECT\n      'N/A'                                                      AS cluster_id,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'cluster_name'), 'N/A') AS cluster_name,\n      (SELECT setting FROM pg_settings WHERE name = 'port')       AS listen_port,\n      (SELECT setting FROM pg_settings WHERE name = 'data_directory') AS data_dir,\n      (SELECT setting FROM pg_settings WHERE name = 'config_file') AS conf_path,\n      (SELECT setting FROM pg_settings WHERE name = 'hba_file')   AS hba_path,\n      (SELECT setting FROM pg_settings WHERE name = 'wal_level')  AS wal_level,\n      (SELECT setting FROM pg_settings WHERE name = 'server_encoding') AS encoding,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version') AS version,\n      (SELECT setting FROM pg_settings WHERE name = 'server_version_num') AS ver_num,\n      version()                                                  AS ver_str,\n      (SELECT setting FROM pg_settings WHERE name = 'shared_preload_libraries') AS extensions,\n      coalesce((SELECT setting FROM pg_settings WHERE name = 'primary_conninfo'), 'N/A') AS primary_conninfo,\n      1                                                          AS info;\n  ttl: 10\n  min_version: 90100\n  max_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\n\n#==============================================================#\n# 0130 pg_setting\n#==============================================================#\n# Key PostgreSQL configuration parameters for PostgreSQL 9.1 - 9.6\n# Use scalar subquery on pg_settings for \"missing_ok\" semantics (return NULL if not exist)\npg_setting:\n  name: pg_setting\n  desc: PostgreSQL shared configuration parameters (legacy 9.1-9.6)\n  query: |\n    SELECT\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_connections')                   AS max_connections,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_prepared_transactions')         AS max_prepared_transactions,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_locks_per_transaction')         AS max_locks_per_transaction,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_worker_processes')              AS max_worker_processes,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_parallel_workers')              AS max_parallel_workers,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_parallel_workers_per_gather')   AS max_parallel_workers_per_gather,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_parallel_maintenance_workers')  AS max_parallel_maintenance_workers,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_replication_slots')             AS max_replication_slots,\n      (SELECT setting::int FROM pg_settings WHERE name = 'max_wal_senders')                   AS max_wal_senders,\n      (SELECT setting::int FROM pg_settings WHERE name = 'block_size')                        AS block_size,\n      (SELECT setting::int FROM pg_settings WHERE name = 'wal_block_size')                    AS wal_block_size,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'segment_size')                                        AS segment_size,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'wal_segment_size')                                    AS wal_segment_size,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'data_checksums') AS data_checksums,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'wal_log_hints')  AS wal_log_hints,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'fsync')          AS fsync,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'full_page_writes') AS full_page_writes,\n      (SELECT CASE setting WHEN 'minimal' THEN 1 WHEN 'archive' THEN 2 WHEN 'hot_standby' THEN 3 ELSE 0 END FROM pg_settings WHERE name = 'wal_level') AS wal_level,\n      (SELECT setting::int FROM pg_settings WHERE name = 'checkpoint_segments')               AS checkpoint_segments,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'min_wal_size')                                        AS min_wal_size,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'max_wal_size')                                        AS max_wal_size,\n      (SELECT setting::int FROM pg_settings WHERE name = 'wal_keep_segments')                 AS wal_keep_segments,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'shared_buffers')                                      AS shared_buffers,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'work_mem')                                            AS work_mem,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'maintenance_work_mem')                                AS maintenance_work_mem,\n      (SELECT setting::bigint * CASE unit WHEN '8kB' THEN 8192 WHEN 'kB' THEN 1024 WHEN 'MB' THEN 1048576 WHEN 'GB' THEN 1073741824 ELSE 1 END\n         FROM pg_settings WHERE name = 'effective_cache_size')                                AS effective_cache_size,\n      (SELECT CASE setting WHEN 'off' THEN 0 WHEN 'on' THEN 1 WHEN 'always' THEN 2 ELSE -1 END FROM pg_settings WHERE name = 'archive_mode') AS archive_mode,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'autovacuum') AS autovacuum,\n      (SELECT setting::int FROM pg_settings WHERE name = 'autovacuum_max_workers')            AS autovacuum_max_workers,\n      (SELECT setting::int FROM pg_settings WHERE name = 'checkpoint_timeout')                AS checkpoint_timeout,\n      (SELECT setting::float FROM pg_settings WHERE name = 'checkpoint_completion_target')    AS checkpoint_completion_target,\n      (SELECT CASE setting WHEN 'on' THEN 1 ELSE 0 END FROM pg_settings WHERE name = 'hot_standby') AS hot_standby,\n      (SELECT CASE setting\n        WHEN 'off' THEN 0 WHEN 'local' THEN 1 WHEN 'remote_write' THEN 2\n        WHEN 'on' THEN 3 WHEN 'remote_apply' THEN 4 ELSE -1 END\n        FROM pg_settings WHERE name = 'synchronous_commit')                                   AS synchronous_commit;\n\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - max_connections:                  { usage: GAUGE ,description: \"maximum number of concurrent connections to the database server\" }\n    - max_prepared_transactions:        { usage: GAUGE ,description: \"maximum number of transactions that can be in the prepared state simultaneously\" }\n    - max_locks_per_transaction:        { usage: GAUGE ,description: \"maximum number of locks per transaction\" }\n    - max_worker_processes:             { usage: GAUGE ,description: \"maximum number of background processes (9.4+)\" }\n    - max_parallel_workers:             { usage: GAUGE ,description: \"maximum number of parallel workers that can be active at one time (9.6+)\" }\n    - max_parallel_workers_per_gather:  { usage: GAUGE ,description: \"maximum number of parallel workers per Gather node (9.6+)\" }\n    - max_parallel_maintenance_workers: { usage: GAUGE ,description: \"maximum number of parallel maintenance workers (NULL on 9.x)\" }\n    - max_replication_slots:            { usage: GAUGE ,description: \"maximum number of replication slots (9.4+)\" }\n    - max_wal_senders:                  { usage: GAUGE ,description: \"maximum number of concurrent WAL sender connections\" }\n    - block_size:                       { usage: GAUGE ,description: \"database block size in bytes (default 8192)\" }\n    - wal_block_size:                   { usage: GAUGE ,description: \"WAL block size in bytes\" }\n    - segment_size:                     { usage: GAUGE ,description: \"database file segment size in bytes\" }\n    - wal_segment_size:                 { usage: GAUGE ,description: \"WAL segment size in bytes\" }\n    - data_checksums:                   { usage: GAUGE ,description: \"data checksums enabled, 1=on 0=off (9.3+)\" }\n    - wal_log_hints:                    { usage: GAUGE ,description: \"WAL log hints enabled, 1=on 0=off (9.4+)\" }\n    - fsync:                            { usage: GAUGE ,description: \"fsync enabled (CRITICAL for data safety), 1=on 0=off\" }\n    - full_page_writes:                 { usage: GAUGE ,description: \"full page writes enabled, 1=on 0=off\" }\n    - wal_level:                        { usage: GAUGE ,description: \"WAL level, 1=minimal 2=archive 3=hot_standby\" }\n    - checkpoint_segments:              { usage: GAUGE ,description: \"number of checkpoint segments (pre-9.5)\" }\n    - min_wal_size:                     { usage: GAUGE ,description: \"minimum WAL size in bytes (9.5+)\" }\n    - max_wal_size:                     { usage: GAUGE ,description: \"maximum WAL size in bytes (9.5+)\" }\n    - wal_keep_segments:                { usage: GAUGE ,description: \"WAL segments kept for standby replication (pg_basebackup/streaming)\" }\n    - shared_buffers:                   { usage: GAUGE ,description: \"shared buffer size in bytes\" }\n    - work_mem:                         { usage: GAUGE ,description: \"work memory size in bytes\" }\n    - maintenance_work_mem:             { usage: GAUGE ,description: \"maintenance work memory size in bytes\" }\n    - effective_cache_size:             { usage: GAUGE ,description: \"planner's assumption about effective OS cache size in bytes\" }\n    - archive_mode:                     { usage: GAUGE ,description: \"archive mode, 0=off 1=on 2=always\" }\n    - autovacuum:                       { usage: GAUGE ,description: \"autovacuum enabled, 1=on 0=off\" }\n    - autovacuum_max_workers:           { usage: GAUGE ,description: \"maximum number of autovacuum worker processes\" }\n    - checkpoint_timeout:               { usage: GAUGE ,description: \"checkpoint timeout in seconds\" }\n    - checkpoint_completion_target:     { usage: GAUGE ,description: \"checkpoint completion target (0.0-1.0)\" }\n    - hot_standby:                      { usage: GAUGE ,description: \"hot standby mode enabled, 1=on 0=off\" }\n    - synchronous_commit:               { usage: GAUGE ,description: \"synchronous commit level, 0=off 1=local 2=remote_write 3=on 4=remote_apply\" }\n\n\n#==============================================================#\n# 0210 pg_repl\n#==============================================================#\npg_repl_94:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 9.4 - 9.6 (with backend_xmin)\n  query: |-\n    SELECT appname, usename, address, pid, client_port, state, sync_state, sync_priority, backend_xmin, lsn,\n           lsn - sent_lsn  AS sent_diff, lsn - write_lsn AS write_diff, lsn - flush_lsn AS flush_diff, lsn - replay_lsn AS replay_diff,\n           sent_lsn, write_lsn, flush_lsn, replay_lsn,\n           0::FLOAT AS write_lag, 0::FLOAT AS flush_lag, 0::FLOAT AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM (\n      SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n             CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n             CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n             sync_priority, backend_xmin::TEXT::BIGINT AS backend_xmin,\n             (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n             (('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS sent_lsn,\n             (('x' || lpad(split_part(write_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(write_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n             (('x' || lpad(split_part(flush_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(flush_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n             (('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n             backend_start\n      FROM pg_stat_replication,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90400\n  max_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback.\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (N/A on 9.x)\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (N/A on 9.x)\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it (N/A on 9.x)\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\npg_repl_92:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 9.2 - 9.3\n  query: |-\n    SELECT appname, usename, address, pid, client_port, state, sync_state, sync_priority, backend_xmin, lsn,\n           lsn - sent_lsn  AS sent_diff, lsn - write_lsn AS write_diff, lsn - flush_lsn AS flush_diff, lsn - replay_lsn AS replay_diff,\n           sent_lsn, write_lsn, flush_lsn, replay_lsn,\n           0::FLOAT AS write_lag, 0::FLOAT AS flush_lag, 0::FLOAT AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM (\n      SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n             CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n             CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n             sync_priority, 0::BIGINT AS backend_xmin,\n             (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n             (('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS sent_lsn,\n             (('x' || lpad(split_part(write_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(write_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n             (('x' || lpad(split_part(flush_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(flush_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n             (('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n             backend_start\n      FROM pg_stat_replication,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90200\n  max_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback (N/A before 9.4)\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (N/A on 9.x)\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (N/A on 9.x)\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it (N/A on 9.x)\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\npg_repl_91:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 9.1 (procpid, no state/sync columns)\n  query: |-\n    SELECT appname, usename, address, pid, client_port, state, sync_state, sync_priority, backend_xmin, lsn,\n           lsn - sent_lsn  AS sent_diff, lsn - write_lsn AS write_diff, lsn - flush_lsn AS flush_diff, lsn - replay_lsn AS replay_diff,\n           sent_lsn, write_lsn, flush_lsn, replay_lsn,\n           0::FLOAT AS write_lag, 0::FLOAT AS flush_lag, 0::FLOAT AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM (\n      SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, procpid::TEXT AS pid, client_port,\n             0::INT AS state, 0::INT AS sync_state, 0::INT AS sync_priority, 0::BIGINT AS backend_xmin,\n             (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS lsn,\n             (('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS sent_lsn,\n             (('x' || lpad(split_part(write_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(write_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS write_lsn,\n             (('x' || lpad(split_part(flush_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(flush_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS flush_lsn,\n             (('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n              + ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS replay_lsn,\n             backend_start\n      FROM pg_stat_replication,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback (N/A before 9.4)\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (N/A on 9.x)\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (N/A on 9.x)\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it (N/A on 9.x)\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\n\n#==============================================================#\n# 0220 pg_sync_standby\n#==============================================================#\npg_sync_standby:\n  name: pg_sync_standby\n  desc: PostgreSQL synchronous standby status and names\n  query: |-\n    SELECT\n      CASE WHEN names <> '' THEN names ELSE '<null>' END AS names,\n      CASE WHEN names <> '' THEN 1 ELSE 0 END           AS enabled\n    FROM (SELECT current_setting('synchronous_standby_names') AS names) n;\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - names:   { usage: LABEL ,description: \"List of standby servers that can support synchronous replication\" }\n    - enabled: { usage: GAUGE ,description: \"Synchronous commit enabled, 1 if enabled, 0 if disabled\" }\n\n\n#==============================================================#\n# 0230 pg_downstream\n#==============================================================#\npg_downstream:\n  name: pg_downstream\n  desc: PostgreSQL replication client count (no state column on 9.1)\n  query: |-\n    SELECT 'connected' AS state, count(*) AS count FROM pg_stat_replication;\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - state: { usage: LABEL ,description: \"Replication client state\" }\n    - count: { usage: GAUGE ,description: \"Count of replication clients by state\" }\n\npg_downstream_92:\n  name: pg_downstream\n  desc: PostgreSQL replication client count (group by state)\n  query: |-\n    SELECT state, count(*) AS count FROM pg_stat_replication GROUP BY state;\n  ttl: 10\n  min_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - state: { usage: LABEL ,description: \"Replication client state\" }\n    - count: { usage: GAUGE ,description: \"Count of replication clients by state\" }\n\n\n#==============================================================#\n# 0240 pg_slot\n#==============================================================#\npg_slot_96:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 9.6 (with active_pid, confirmed_flush_lsn)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname, datoid, active_pid,\n      active, FALSE AS temporary,\n      xmin::TEXT::BIGINT AS xmin, catalog_xmin::TEXT::BIGINT AS catalog_xmin,\n      restart_lsn, confirm_lsn, current_lsn - restart_lsn AS retained_bytes\n    FROM (\n      SELECT slot_name, slot_type, plugin, database, datoid, active_pid, active, xmin, catalog_xmin,\n        (('x' || lpad(split_part(restart_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(restart_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS restart_lsn,\n        (('x' || lpad(split_part(confirmed_flush_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(confirmed_flush_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS confirm_lsn,\n        (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS current_lsn\n      FROM pg_replication_slots,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90600\n  max_version: 100000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:      { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:      { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:         { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:        { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:         { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:     { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:         { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:      { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot (N/A on 9.x, always 0)\" }\n    - xmin:           { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:   { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:    { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:    { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes: { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\npg_slot_95:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 9.5 (no confirmed_flush_lsn)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname, datoid, active_pid,\n      active, FALSE AS temporary,\n      xmin::TEXT::BIGINT AS xmin, catalog_xmin::TEXT::BIGINT AS catalog_xmin,\n      restart_lsn, confirm_lsn, current_lsn - restart_lsn AS retained_bytes\n    FROM (\n      SELECT slot_name, slot_type, plugin, database, datoid, active_pid, active, xmin, catalog_xmin,\n        (('x' || lpad(split_part(restart_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(restart_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS restart_lsn,\n        0::BIGINT AS confirm_lsn,\n        (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS current_lsn\n      FROM pg_replication_slots,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90500\n  max_version: 90600\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:      { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:      { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:         { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:        { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:         { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:     { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:         { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:      { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot (N/A on 9.x, always 0)\" }\n    - xmin:           { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:   { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:    { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:    { usage: COUNTER  ,description: \"Confirmed flush lsn (N/A before 9.6, always 0)\" }\n    - retained_bytes: { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\npg_slot_94:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 9.4 (no active_pid, confirmed_flush_lsn)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname, datoid, active_pid,\n      active, FALSE AS temporary,\n      xmin::TEXT::BIGINT AS xmin, catalog_xmin::TEXT::BIGINT AS catalog_xmin,\n      restart_lsn, confirm_lsn, current_lsn - restart_lsn AS retained_bytes\n    FROM (\n      SELECT slot_name, slot_type, plugin, database, datoid, NULL::INT AS active_pid, active, xmin, catalog_xmin,\n        (('x' || lpad(split_part(restart_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(restart_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS restart_lsn,\n        0::BIGINT AS confirm_lsn,\n        (('x' || lpad(split_part(current.loc::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n         + ('x' || lpad(split_part(current.loc::text, '/', 2), 8, '0'))::bit(32)::bigint) AS current_lsn\n      FROM pg_replication_slots,\n           (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_xlog_replay_location() ELSE pg_current_xlog_location() END AS loc) current\n    ) d;\n\n  ttl: 10\n  min_version: 90400\n  max_version: 90500\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:      { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:      { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:         { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:        { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:         { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:     { usage: GAUGE    ,description: \"Process ID is not available before 9.5 (NULL)\" }\n    - active:         { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:      { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot (N/A on 9.x, always 0)\" }\n    - xmin:           { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:   { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:    { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:    { usage: COUNTER  ,description: \"Confirmed flush lsn (N/A before 9.6, always 0)\" }\n    - retained_bytes: { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\n\n#==============================================================#\n# 0250 pg_recv\n#==============================================================#\npg_recv_96:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics (9.6 - 12)\n  query: |-\n    SELECT \n      (regexp_match(conninfo, '.*host=(\\S+).*'))[1] AS sender_host,\n      (regexp_match(conninfo, '.*port=(\\S+).*'))[1] AS sender_port,\n      coalesce(slot_name, 'NULL')                    AS slot_name,\n      pid,\n      CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      (('x' || lpad(split_part(receive_start_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(receive_start_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS init_lsn,\n      receive_start_tli AS init_tli,\n      (('x' || lpad(split_part(received_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(received_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)      AS flush_lsn,\n      received_tli       AS flush_tli,\n      (('x' || lpad(split_part(latest_end_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(latest_end_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)    AS reported_lsn,\n      last_msg_send_time    AS msg_send_time,\n      last_msg_receipt_time AS msg_recv_time,\n      latest_end_time       AS reported_time,\n      now()                 AS time\n    FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  min_version: 90600\n  max_version: 130000\n  tags: [ cluster, replica ]\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\n\n#==============================================================#\n# 0270 pg_origin\n#==============================================================#\n# skip by default, require additional privilege setup\n# GRANT SELECT ON pg_replication_origin, pg_replication_origin_status TO pg_monitor;\npg_origin:\n  name: pg_origin\n  desc: PostgreSQL replay state (approximate) for a certain origin\n  query: |-\n    SELECT roname,\n      (('x' || lpad(split_part(remote_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(remote_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS remote_lsn,\n      (('x' || lpad(split_part(local_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(local_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS local_lsn\n    FROM pg_replication_origin o LEFT JOIN pg_replication_origin_status os ON o.roident = os.local_id;\n  ttl: 10\n  min_version: 90500\n  skip: true\n  tags: [ cluster ]\n  metrics:\n    - roname:              { usage: LABEL     ,description: \"The external, user defined, name of a replication origin.\" }\n    - remote_lsn:          { usage: COUNTER   ,description: \"The origin node's LSN up to which data has been replicated.\" }\n    - local_lsn:           { usage: COUNTER   ,description: \"This node's LSN at which remote_lsn has been replicated.\" }\n\n\n#==============================================================#\n# 0310 pg_size\n#==============================================================#\npg_size:\n  name: pg_size\n  desc: PostgreSQL database size (legacy 9.1-9.6)\n  query: |-\n    SELECT datname, pg_database_size(oid) AS bytes FROM pg_database;\n  ttl: 60\n  timeout: 1\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Database name\" }\n    - bytes:   { usage: GAUGE ,description: \"Database size in bytes\" }\n\n\n#==============================================================#\n# 0320 pg_archiver\n#==============================================================#\npg_archiver:\n  name: pg_archiver\n  desc: PostgreSQL archiver process statistics\n  query: |-\n    SELECT archived_count AS finish_count,failed_count,\n      extract(epoch FROM last_archived_time) AS finish_time,\n      extract(epoch FROM last_failed_time) AS failed_time,\n      extract(epoch FROM stats_reset) AS reset_time\n    FROM pg_stat_archiver;\n\n  ttl: 60\n  min_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - finish_count:        { usage: COUNTER ,description: \"Number of WAL files that have been successfully archived\" }\n    - failed_count:        { usage: COUNTER ,description: \"Number of failed attempts for archiving WAL files\" }\n    - finish_time:         { usage: GAUGE   ,description: \"Time of the last successful archive operation\" }\n    - failed_time:         { usage: GAUGE   ,description: \"Time of the last failed archival operation\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which archive statistics were last reset\" }\n\n\n#==============================================================#\n# 0330 pg_bgwriter\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_bgwriter.html\npg_bgwriter_94:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics (PG 9.4-16)\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, buffers_clean, buffers_backend, maxwritten_clean, buffers_backend_fsync, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER              ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER              ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER              ,description: \"Number of buffers written during checkpoints\" }\n    - buffers_clean:         { usage: COUNTER              ,description: \"Number of buffers written by the background writer\" }\n    - buffers_backend:       { usage: COUNTER              ,description: \"Number of buffers written directly by a backend\" }\n    - maxwritten_clean:      { usage: COUNTER              ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_backend_fsync: { usage: COUNTER              ,description: \"Number of times a backend had to execute its own fsync call\" }\n    - buffers_alloc:         { usage: COUNTER              ,description: \"Number of buffers allocated\" }\n    - reset_time:            { usage: GAUGE                ,description: \"Time at which bgwriter statistics were last reset\" }\n\npg_bgwriter_91:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics (PG 9.1-9.3)\"\n  query: SELECT checkpoints_timed, checkpoints_req, 0::BIGINT AS checkpoint_write_time, 0::BIGINT AS checkpoint_sync_time, buffers_checkpoint, buffers_clean, buffers_backend, maxwritten_clean, buffers_backend_fsync, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90100\n  max_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER              ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER              ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent writing checkpoint files, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent syncing checkpoint files, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - buffers_checkpoint:    { usage: COUNTER              ,description: \"Number of buffers written during checkpoints\" }\n    - buffers_clean:         { usage: COUNTER              ,description: \"Number of buffers written by the background writer\" }\n    - buffers_backend:       { usage: COUNTER              ,description: \"Number of buffers written directly by a backend\" }\n    - maxwritten_clean:      { usage: COUNTER              ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_backend_fsync: { usage: COUNTER              ,description: \"Number of times a backend had to execute its own fsync call\" }\n    - buffers_alloc:         { usage: COUNTER              ,description: \"Number of buffers allocated\" }\n    - reset_time:            { usage: GAUGE                ,description: \"Time at which bgwriter statistics were last reset\" }\n\n\n#==============================================================#\n# 0331 pg_checkpointer\n#==============================================================#\npg_checkpointer_94:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 9.4-16\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER ,rename: timed                   ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER ,rename: req                     ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,rename: write_time ,scale: 1e-3 ,description: \"Total amount of time that has been spent writing checkpoint files, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,rename: sync_time  ,scale: 1e-3 ,description: \"Total amount of time that has been spent synchronizing checkpoint files to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER ,rename: buffers_written         ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                                    ,description: \"Time at which checkpointer statistics were last reset\" }\n\npg_checkpointer_91:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 9.1-9.3\"\n  query: SELECT checkpoints_timed, checkpoints_req, 0::BIGINT AS checkpoint_write_time, 0::BIGINT AS checkpoint_sync_time, buffers_checkpoint, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 90100\n  max_version: 90400\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER ,rename: timed                   ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER ,rename: req                     ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,rename: write_time ,scale: 1e-3 ,description: \"Total amount of time that has been spent writing checkpoint files, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,rename: sync_time  ,scale: 1e-3 ,description: \"Total amount of time that has been spent synchronizing checkpoint files to disk, in seconds (N/A on 9.1-9.3, always 0)\" }\n    - buffers_checkpoint:    { usage: COUNTER ,rename: buffers_written         ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                                    ,description: \"Time at which checkpointer statistics were last reset\" }\n\n\n#==============================================================#\n# 0340 pg_ssl\n#==============================================================#\npg_ssl:\n  name: pg_ssl\n  desc: PostgreSQL SSL client connection count\n  query: |\n    SELECT count(*) FILTER (WHERE ssl) AS enabled, count(*) FILTER ( WHERE NOT ssl) AS disabled FROM pg_stat_ssl;\n  ttl: 10\n  min_version: 90500\n  tags: [ cluster ]\n  metrics:\n    - enabled:            { usage: GAUGE   ,description: \"Number of client connection that use ssl\" }\n    - disabled:           { usage: GAUGE   ,description: \"Number of client connection that does not use ssl\" }\n\n\n#==============================================================#\n# 0350 pg_checkpoint\n#==============================================================#\npg_checkpoint:\n  name: pg_checkpoint\n  desc: checkpoint information from pg_control_checkpoint (9.6)\n  query: |-\n    SELECT \n      (('x' || lpad(split_part(checkpoint_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(checkpoint_location::text, '/', 2), 8, '0'))::bit(32)::bigint) AS checkpoint_lsn,\n      (('x' || lpad(split_part(redo_location::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(redo_location::text, '/', 2), 8, '0'))::bit(32)::bigint)       AS redo_lsn,\n      timeline_id AS tli,\n      prev_timeline_id AS prev_tli,\n      full_page_writes,\n      split_part(next_xid, ':', 1) AS next_xid_epoch,\n      split_part(next_xid, ':', 2) AS next_xid,\n      next_oid::BIGINT,\n      next_multixact_id::text::BIGINT,\n      next_multi_offset::text::BIGINT,\n      oldest_xid::text::BIGINT,\n      oldest_xid_dbid::text::BIGINT,\n      oldest_active_xid::text::BIGINT,\n      oldest_multi_xid::text::BIGINT,\n      oldest_multi_dbid::BIGINT,\n      oldest_commit_ts_xid::text::BIGINT,\n      newest_commit_ts_xid::text::BIGINT,\n      checkpoint_time                             AS time,\n      extract(epoch from now() - checkpoint_time) AS elapse\n    FROM pg_control_checkpoint();\n\n  ttl: 60\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - checkpoint_lsn:       { usage: COUNTER ,description: \"Latest checkpoint location\" }\n    - redo_lsn:             { usage: COUNTER ,description: \"Latest checkpoint's REDO location\" }\n    - tli:                  { usage: COUNTER ,description: \"Latest checkpoint's TimeLineID\" }\n    - prev_tli:             { usage: COUNTER ,description: \"Latest checkpoint's PrevTimeLineID\" }\n    - full_page_writes:     { usage: GAUGE   ,description: \"Latest checkpoint's full_page_writes enabled\" }\n    - next_xid_epoch:       { usage: COUNTER ,description: \"Latest checkpoint's NextXID epoch\" }\n    - next_xid:             { usage: COUNTER ,description: \"Latest checkpoint's NextXID xid\" }\n    - next_oid:             { usage: COUNTER ,description: \"Latest checkpoint's NextOID\" }\n    - next_multixact_id:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiXactId\" }\n    - next_multi_offset:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiOffset\" }\n    - oldest_xid:           { usage: COUNTER ,description: \"Latest checkpoint's oldestXID\" }\n    - oldest_xid_dbid:      { usage: GAUGE   ,description: \"Latest checkpoint's oldestXID's DB OID\" }\n    - oldest_active_xid:    { usage: COUNTER ,description: \"Latest checkpoint's oldestActiveXID\" }\n    - oldest_multi_xid:     { usage: COUNTER ,description: \"Latest checkpoint's oldestMultiXid\" }\n    - oldest_multi_dbid:    { usage: GAUGE   ,description: \"Latest checkpoint's oldestMulti's DB OID\" }\n    - oldest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's oldestCommitTsXid\" }\n    - newest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's newestCommitTsXid\" }\n    - time:                 { usage: COUNTER ,description: \"Time of latest checkpoint\" }\n    - elapse:               { usage: GAUGE   ,description: \"Seconds elapsed since latest checkpoint in seconds\" }\n\n\n#==============================================================#\n# 0355 pg_timeline\n#==============================================================#\npg_timeline:\n  name: pg_timeline\n  desc: Current timeline ID from primary or replica\n  query: |\n    SELECT COALESCE(\n      (SELECT received_tli FROM pg_stat_wal_receiver),\n      (SELECT timeline_id FROM pg_control_checkpoint())\n    ) AS id;\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - id: { usage: GAUGE ,description: \"Current timeline ID\" }\n\n\n#==============================================================#\n# 0360 pg_recovery\n#==============================================================#\npg_recovery:\n  name: pg_recovery\n  desc: PostgreSQL control recovery metrics (9.6)\n  query: |\n    SELECT min_recovery_end_timeline AS min_timeline,\n      (('x' || lpad(split_part(min_recovery_end_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(min_recovery_end_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint) AS min_lsn,\n      (('x' || lpad(split_part(backup_start_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(backup_start_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)     AS backup_start_lsn,\n      (('x' || lpad(split_part(backup_end_lsn::text, '/', 1), 8, '0'))::bit(32)::bigint * 4294967296\n       + ('x' || lpad(split_part(backup_end_lsn::text, '/', 2), 8, '0'))::bit(32)::bigint)       AS backup_end_lsn,\n      end_of_backup_record_required AS require_record\n    FROM pg_control_recovery();\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster, replica ]\n  metrics:\n    - min_timeline:      { usage: COUNTER ,description: \"Min recovery ending loc's timeline\" }\n    - min_lsn:           { usage: COUNTER ,description: \"Minimum recovery ending location\" }\n    - backup_start_lsn:  { usage: COUNTER ,description: \"Backup start location\" }\n    - backup_end_lsn:    { usage: COUNTER ,description: \"Backup end location\" }\n    - require_record:    { usage: GAUGE   ,description: \"End-of-backup record required\" }\n\n\n#==============================================================#\n# 0410 pg_activity\n#==============================================================#\npg_activity_92:\n  name: pg_activity\n  desc: PostgreSQL backend activity group by database and state (9.2+)\n  query: |-\n    SELECT datname, state, coalesce(count, 0) AS count, coalesce(max_duration, 0) AS max_duration, coalesce(max_tx_duration, 0) AS max_tx_duration, coalesce(max_conn_duration, 0) AS max_conn_duration FROM\n        (SELECT d.datname, a.state FROM pg_database d, unnest(ARRAY ['active','idle','idle in transaction','idle in transaction (aborted)','fastpath function call','disabled']) a(state) WHERE d.datallowconn AND NOT d.datistemplate) base\n          LEFT JOIN (SELECT datname, state, count(*) AS count, max(extract(epoch from now() - state_change)) AS max_duration, max(extract(epoch from now() - xact_start))\n          AS max_tx_duration, max(extract(epoch from now() - backend_start)) AS max_conn_duration FROM pg_stat_activity WHERE pid <> pg_backend_pid() GROUP BY 1,2) data USING (datname,state);\n  ttl: 10\n  min_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - state:             { usage: LABEL ,description: \"Current overall state of this backend.\" }\n    - count:             { usage: GAUGE ,description: \"Count of connection among (datname,state)\" }\n    - max_duration:      { usage: GAUGE ,description: \"Max duration since last state change among (datname, state)\" }\n    - max_tx_duration:   { usage: GAUGE ,description: \"Max transaction duration since state change among (datname, state)\" }\n    - max_conn_duration: { usage: GAUGE ,description: \"Max backend session duration since state change among (datname, state)\" }\n\npg_activity_91:\n  name: pg_activity\n  desc: PostgreSQL backend activity group by database (9.1)\n  query: |\n    SELECT\n      datname,\n      'active' AS state,\n      count(*) AS count,\n      max(extract(epoch from now() - query_start))   AS max_duration,\n      max(extract(epoch from now() - xact_start))    AS max_tx_duration,\n      max(extract(epoch from now() - backend_start)) AS max_conn_duration\n    FROM pg_stat_activity\n    WHERE procpid <> pg_backend_pid()\n      AND datname IS NOT NULL\n    GROUP BY datname;\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - state:             { usage: LABEL ,description: \"Current overall state of this backend (always active on 9.1)\" }\n    - count:             { usage: GAUGE ,description: \"Count of connection among (datname,state)\" }\n    - max_duration:      { usage: GAUGE ,description: \"Max duration since query start among (datname)\" }\n    - max_tx_duration:   { usage: GAUGE ,description: \"Max transaction duration among (datname)\" }\n    - max_conn_duration: { usage: GAUGE ,description: \"Max backend session duration among (datname)\" }\n\n\n#==============================================================#\n# 0420 pg_wait\n#==============================================================#\npg_wait_96:\n  name: pg_wait\n  desc: PostgreSQL backend client count group by wait event type (9.6)\n  query: |\n    SELECT coalesce(datname, '_system') AS datname, coalesce(wait_event_type, 'Running') AS event, count(*) AS count FROM pg_stat_activity GROUP BY 1, 2;\n  ttl: 10\n  min_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database, _system for global process\" }\n    - event:   { usage: LABEL ,description: \"Wait event type\" }\n    - count:   { usage: GAUGE ,description: \"Count of WaitEvent on target database\" }\n\npg_wait_91:\n  name: pg_wait\n  desc: PostgreSQL backend client count group by waiting flag (9.1-9.5)\n  query: |\n    SELECT coalesce(datname, '_system') AS datname, CASE WHEN waiting THEN 'Waiting' ELSE 'Running' END AS event, count(*) AS count FROM pg_stat_activity GROUP BY 1, 2;\n  ttl: 10\n  min_version: 90100\n  max_version: 90600\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database, _system for global process\" }\n    - event:   { usage: LABEL ,description: \"Waiting flag, Waiting or Running\" }\n    - count:   { usage: GAUGE ,description: \"Backend count group by waiting flag\" }\n\n\n#==============================================================#\n# 0440 pg_xact\n#==============================================================#\npg_xact:\n  name: pg_xact\n  desc: PostgreSQL transaction identifier metrics\n  query: |\n    WITH snap(v) AS (SELECT txid_current_snapshot()),\n         xset(v) AS (SELECT txid_snapshot_xip(v) FROM snap),\n         xnum(v) AS (SELECT count(*) FROM xset),\n         xmin(v) AS (SELECT txid_snapshot_xmin(v) FROM snap),\n         xmax(v) AS (SELECT txid_snapshot_xmax(v) FROM snap)\n    SELECT xmin.v AS xmin, xmax.v AS xmax, xnum.v AS xnum\n    FROM xmin, xmax, xnum;\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - xmin: { usage: COUNTER ,description: \"Earliest txid that is still active\" }\n    - xmax: { usage: COUNTER ,description: \"First as-yet-unassigned txid\" }\n    - xnum: { usage: GAUGE   ,description: \"Current active transaction count\" }\n\n\n#==============================================================#\n# 0450 pg_lock\n#==============================================================#\npg_lock:\n  name: pg_lock\n  desc: PostgreSQL lock distribution by mode and database\n  query: |\n    SELECT datname, mode, coalesce(count, 0) AS count\n      FROM (SELECT d.oid AS database, d.datname, l.mode FROM pg_database d, unnest(ARRAY ['AccessShareLock','RowShareLock','RowExclusiveLock','ShareUpdateExclusiveLock', 'ShareLock','ShareRowExclusiveLock','ExclusiveLock','AccessExclusiveLock']) l(mode) WHERE d.datallowconn AND NOT d.datistemplate) base\n      LEFT JOIN (SELECT database, mode, count(*) AS count FROM pg_locks WHERE database IS NOT NULL GROUP BY 1, 2) cnt USING (database, mode);\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - mode:    { usage: LABEL ,description: \"Name of the lock mode held or desired by this process\" }\n    - count:   { usage: GAUGE ,description: \"Number of locks of corresponding mode and database\" }\n\n\n#==============================================================#\n# 0460 pg_query\n#==============================================================#\npg_query_94:\n  name: pg_query\n  desc: PostgreSQL query statement metrics, require pg_stat_statements installed, 9.4 - 12\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_time) AS exec_time, sum(blk_read_time) + sum(blk_write_time) AS io_time,\n      sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n    FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90400\n  max_version: 130000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\npg_query_91:\n  name: pg_query\n  desc: PostgreSQL query statement metrics, require pg_stat_statements installed, 9.1 - 9.3 (no queryid)\n  query: |-\n    SELECT datname, md5(query) AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_time) AS exec_time, 0::FLOAT AS io_time,\n      sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, 0::BIGINT AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n    FROM pg_stat_statements s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90100\n  max_version: 90400\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"MD5 hash of query text (no queryid before 9.4)\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds (N/A before 9.4, always 0)\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement (N/A before 9.4, always 0)\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\n\n#==============================================================#\n# 0610 pg_db\n#==============================================================#\npg_db_92:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database (9.2 - 9.6)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total, blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,blk_read_time,blk_write_time, extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n  ttl: 10\n  min_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\npg_db_91:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database (9.1, fewer columns)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total, blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts, 0::BIGINT AS temp_files, 0::BIGINT AS temp_bytes, 0::BIGINT AS deadlocks, 0::BIGINT AS blk_read_time, 0::BIGINT AS blk_write_time,\n      extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n  ttl: 10\n  min_version: 90100\n  max_version: 90200\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database (N/A on 9.1, always 0)\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database (N/A on 9.1, always 0)\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database (N/A on 9.1, always 0)\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds (N/A on 9.1, always 0)\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds (N/A on 9.1, always 0)\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\n\n#==============================================================#\n# 0620 pg_db_confl\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_database_conflicts.html\npg_db_confl:\n  name: pg_db_confl\n  desc: PostgreSQL database conflicts metrics for pg 9.1 - 9.6\n  query: SELECT datid,datname,confl_tablespace,confl_lock,confl_snapshot,confl_bufferpin,confl_deadlock FROM pg_stat_database_conflicts;\n  ttl: 10\n  min_version: 90100\n  tags: [ cluster, replica ]\n  metrics:\n    - datid:                { usage: DISCARD }\n    - datname:              { usage: LABEL   ,description: \"Name of this database\" }\n    - confl_tablespace:     { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to dropped tablespaces\" }\n    - confl_lock:           { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to lock timeouts\" }\n    - confl_snapshot:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to old snapshots\" }\n    - confl_bufferpin:      { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to pinned buffers\" }\n    - confl_deadlock:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to deadlocks\" }\n\n\n#==============================================================#\n# 0700 pg_table\n#==============================================================#\npg_table_94:\n  name: pg_table\n  desc: PostgreSQL table metrics 9.4-9.6\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90400\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_91:\n  name: pg_table\n  desc: PostgreSQL table metrics 9.1-9.3 (no n_mod_since_analyze)\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       NULL::BIGINT AS n_mod_since_analyze, psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 90100\n  max_version: 90400\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,t/toast/116\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed (N/A on 9.1-9.3, NULL)\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\n\n#==============================================================#\n# 0710 pg_index\n#==============================================================#\npg_index:\n  name: pg_index\n  desc: PostgreSQL index metrics (legacy 9.1-9.6)\n  query: |-\n    SELECT CURRENT_CATALOG AS datname,\n      psui.schemaname || '.' || psui.indexrelname AS idxname,\n      psui.schemaname || '.' || psui.relname      AS relname,\n      psui.indexrelid AS relid,\n      c.relpages, c.reltuples,\n      psui.idx_scan, psui.idx_tup_read, psui.idx_tup_fetch,\n      psio.idx_blks_read, psio.idx_blks_hit\n    FROM pg_stat_user_indexes psui\n      JOIN pg_statio_user_indexes psio ON psio.indexrelid = psui.indexrelid\n      JOIN pg_class c ON c.oid = psui.indexrelid\n    WHERE psui.schemaname !~ '^pg_' AND psui.schemaname !~ '^_' AND psui.schemaname !~ '^timescaledb' AND psui.schemaname !~ '^citus' AND psui.schemaname !~ '^columnar'\n      AND psui.schemaname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor')\n    ORDER BY psui.idx_tup_read DESC LIMIT 512;\n\n  ttl: 10\n  timeout: 1\n  min_version: 90100\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - idxname:             { usage: LABEL    ,description: \"Name of this index (full-qualified schema name)\" }\n    - relname:             { usage: LABEL    ,description: \"Name of the table for this index (full-qualified schema name)\" }\n    - relid:               { usage: LABEL    ,description: \"Relation oid of this index\" }\n    - relpages:            { usage: GAUGE    ,description: \"Size of the on-disk representation of this index in pages\" }\n    - reltuples:           { usage: GAUGE    ,description: \"Estimate relation tuples\" }\n    - idx_scan:            { usage: COUNTER  ,description: \"Number of index scans initiated on this index\" }\n    - idx_tup_read:        { usage: COUNTER  ,description: \"Number of index entries returned by scans on this index\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,description: \"Number of live table rows fetched by simple index scans using this index\" }\n    - idx_blks_read:       { usage: COUNTER  ,description: \"Number of disk blocks read from this index\" }\n    - idx_blks_hit:        { usage: COUNTER  ,description: \"Number of buffer hits in this index\" }\n\n\n#==============================================================#\n# 0720 pg_func\n#==============================================================#\npg_func:\n  desc: PostgreSQL function metrics\n  query: SELECT CURRENT_CATALOG AS datname, schemaname || '.' || funcname AS funcname, sum(calls) AS calls, sum(total_time) AS total_time, sum(self_time) AS self_time FROM pg_stat_user_functions GROUP BY 2 ORDER BY 4 DESC LIMIT 128;\n  ttl: 10\n  min_version: 90100\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Name of belonged database\" }\n    - funcname:            { usage: LABEL    ,description: \"Name of this function, may have multiple override\" }\n    - calls:               { usage: COUNTER  ,description: \"Number of times this function has been called\" }\n    - total_time:          { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function and all other functions called by it, in seconds\" }\n    - self_time:           { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function itself, not including other functions called by it, in seconds\" }\n\n\n#==============================================================#\n# 0740 pg_relkind\n#==============================================================#\npg_relkind:\n  name: pg_relkind\n  desc: Postgres relation count by kind\n  query: |\n    SELECT CURRENT_CATALOG AS datname, relkind, count(*) AS count\n    FROM pg_class\n    GROUP BY relkind;\n  ttl: 60\n  timeout: 1\n  min_version: 90100\n  metrics:\n    - datname: { usage: LABEL ,description: \"Database name\" }\n    - relkind: { usage: LABEL ,description: \"Relation kind (r,i,S,t,v,c,...)\" }\n    - count:   { usage: GAUGE ,description: \"Number of relations\" }\n\n\n#==============================================================#\n# 0810 pg_table_size\n#==============================================================#\npg_table_size:\n  desc: PostgreSQL table size metrics, quite slow\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || rel.relname AS relname,\n       pg_total_relation_size(rel.oid)       AS bytes,\n       pg_relation_size(rel.oid)             AS relsize,\n       pg_indexes_size(rel.oid)              AS indexsize,\n       pg_total_relation_size(reltoastrelid) AS toastsize\n    FROM pg_namespace nsp JOIN pg_class rel ON nsp.oid = rel.relnamespace\n    WHERE nspname <> ALL(ARRAY['pg_catalog', 'information_schema']) AND rel.relkind = 'r'\n    ORDER BY 3 DESC NULLS LAST LIMIT 256;\n\n  ttl: 300\n  timeout: 2\n  min_version: 90100\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified table name\" }\n    - bytes:               { usage: GAUGE    ,default: 0  ,description: \"Total bytes of this table (including toast, index, toast index)\" }\n    - relsize:             { usage: GAUGE    ,default: 0  ,description: \"Bytes of this table itself (main, vm, fsm)\" }\n    - indexsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of all related indexes of this table\" }\n    - toastsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of toast tables of this table\" }\n\n\n#==============================================================#\n# 0820 pg_table_bloat\n#==============================================================#\n# pg_table_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_table_bloat:\n  name: pg_table_bloat\n  desc: PostgreSQL table bloat metrics, require auxiliary view pg_table_bloat to work\n  query: SELECT datname, nspname || '.' || relname AS relname, size, ratio FROM pg_table_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 90400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified name of this table\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this table\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this table from 0 to 1\" }\n\n\n#==============================================================#\n# 0830 pg_index_bloat\n#==============================================================#\n# pg_index_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_index_bloat:\n  name: pg_index_bloat\n  desc: PostgreSQL index bloat metrics, require auxiliary view pg_index_bloat to work\n  query: SELECT datname, nspname || '.' || idxname AS idxname, size, ratio FROM pg_index_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 90400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - idxname:             { usage: LABEL    ,description: \"Schema qualified name of this index\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this index\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this index from 0 to 1\" }\n\n\n#==============================================================#\n# 0910 pgbouncer_list\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-lists\npgbouncer_list:\n  name: pgbouncer_list\n  desc: Pgbouncer entry list\n  query: SHOW LISTS;\n  ttl: 10\n  min_version: 10800\n  fatal: true\n  tags: [ pgbouncer ]\n  metrics:\n    - list:                { usage: LABEL                 ,description: \"Pgbouncer internal list name\" }\n    - items:               { usage: GAUGE                 ,description: \"Number of corresponding pgbouncer object\" }\n\n\n#==============================================================#\n# 0920 pgbouncer_database\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-databases\npgbouncer_database_124:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (since 1.24)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                       { usage: LABEL  ,rename: datname       ,description: \"Name of configured database entry\" }\n    - host:                       { usage: LABEL                         ,description: \"Host that pgbouncer will connects to\" }\n    - port:                       { usage: LABEL                         ,description: \"Port that pgbouncer will connects to\" }\n    - database:                   { usage: LABEL  ,rename: real_datname  ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:                 { usage: DISCARD }\n    - pool_size:                  { usage: GAUGE                         ,description: \"Maximum number of server connections\" }\n    - min_pool_size:              { usage: GAUGE                         ,description: \"Minimum number of server connections\" }\n    - reserve_pool_size:          { usage: GAUGE  ,rename: reserve_pool  ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:            { usage: GAUGE                         ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:                  { usage: DISCARD }\n    - load_balance_hosts:         { usage: DISCARD }\n    - max_connections:            { usage: GAUGE                         ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections:        { usage: GAUGE                         ,description: \"Current number of connections for this database\" }\n    - max_client_connections:     { usage: GAUGE                         ,description: \"Maximum number of allowed client connections for this pgbouncer instance\" }\n    - current_client_connections: { usage: GAUGE                         ,description: \"Current number of client connections for this database\" }\n    - paused:                     { usage: GAUGE                         ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:                   { usage: GAUGE                         ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_123:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats 1.23\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:     { usage: GAUGE                       ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_116:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.16-1.22)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 11600\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_108:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.08-1.15)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\n\n#==============================================================#\n# 0930 pgbouncer_stat\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-stats\npgbouncer_stat_124:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (since 1.24)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - total_client_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created by clients\" }\n    - total_server_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created on a server.\" }\n    - total_bind_count:              { usage: COUNTER                  ,description: \"Total number of prepared statements readied for execution by clients and forwarded to postgres\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n    - avg_client_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created by clients\" }\n    - avg_server_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created on a server.\" }\n    - avg_bind_count:                { usage: GAUGE                    ,description: \"Average number of prepared statements readied for execution by clients and forwarded to postgres\" }\n\npgbouncer_stat_123:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.23)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\npgbouncer_stat_108:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.08 - 1.22)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 10800\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\n\n#==============================================================#\n# 0940 pgbouncer_pool\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-pools\npgbouncer_pool_124:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.24+)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n    - load_balance_hosts:    { usage: LABEL,                                 description: \"The load_balance_hosts in use\" }\n\npgbouncer_pool_118:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.18-1.23)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11800\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n\npgbouncer_pool_116:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.16-1.17)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11600\n  max_version: 11800\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_cancel_req:         { usage: GAUGE, rename: cancel_clients,   description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\npgbouncer_pool_108:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.08-1.15)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\n\n#==============================================================#\n# 1800 pg_tsdb_hypertable\n#==============================================================#\n# this collector reqires timescaledb extension to be installed\npg_tsdb_hypertable:\n  name: pg_tsdb_hypertable\n  desc: TimescaleDB hypertable overview\n  query: |-\n    SELECT \n      current_database() AS datname,\n      format('%I.%I', hypertable_schema, hypertable_name) AS relname,\n      num_dimensions AS dimensions, num_chunks AS chunks,\n      compression_enabled::BOOLEAN::int AS compressed,\n      hypertable_size(format('\"%I\".\"%I\"', hypertable_schema, hypertable_name)::RegClass) AS bytes\n    FROM timescaledb_information.hypertables;\n\n  ttl: 60\n  timeout: 2\n  min_version: 90600\n  skip: true\n  tags: [ \"extension:timescaledb\", \"schema:timescaledb_information\" ]\n  metrics:\n    - datname:         { usage: LABEL ,description: \"database name\" }\n    - relname:         { usage: LABEL ,description: \"Hypertable relation name\" }\n    - dimensions:      { usage: GAUGE ,description: \"Number of partitioning dimensions\" }\n    - chunks:          { usage: GAUGE ,description: \"Total chunks of this hypertable\" }\n    - compressed:      { usage: GAUGE ,description: \"1 if compression enabled\" }\n    - bytes:           { usage: GAUGE ,description: \"Total size of hypertable in bytes\" }\n\n\n#==============================================================#\n# 1900 pg_citus_node\n#==============================================================#\n# https://docs.citusdata.com/en/latest/develop/api_metadata.html#worker-node-table\npg_citus_node:\n  name: pg_citus_node\n  desc: Citus worker coordinator node inventory\n  query: |-\n    SELECT\n      CONCAT(nodename, ':', nodeport) AS node,\n      current_database() AS datname,\n      nodeid AS id,\n      groupid AS group,\n      hasmetadata::BOOLEAN::INT AS has_meta,\n      isactive::BOOLEAN::INT AS is_active,\n      metadatasynced::BOOLEAN::INT AS meta_synced,\n      shouldhaveshards::BOOLEAN::INT AS have_shards\n    FROM pg_dist_node;\n  ttl: 60\n  min_version: 90600\n  tags: [ \"extension:citus\" ]\n  metrics:\n    - node:             { usage: LABEL ,description: \"nodename:port of the PostgreSQL instance\" }\n    - datname:          { usage: LABEL ,description: \"database name\" }\n    - id:               { usage: GAUGE ,description: \"auto‑generated node identifier\" }\n    - group:            { usage: GAUGE ,description: \"replication group id (primary + secondaries)\" }\n    - has_meta:         { usage: GAUGE ,description: \"1 = internal use flag set\" }\n    - is_active:        { usage: GAUGE ,description: \"1 = node currently accepts shards\" }\n    - meta_synced:      { usage: GAUGE ,description: \"1 = metadata fully synced to node\" }\n    - have_shards:      { usage: GAUGE ,description: \"1 = rebalancer may place shards here\" }\n\n\n#==============================================================#\n# 2000 heartbeat\n#==============================================================#\n# this is a example of application monitoring and predicate queries\npg_heartbeat:\n  name: pg_heartbeat\n  desc: monitoring heartbeat in monitor.heartbeat table\n  predicate_queries:\n    - name: if heartbeat table exists\n      predicate_query: |\n        SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'monitor' AND table_name = 'heartbeat');\n  query: |-\n    SELECT id AS cluster_name, extract(EPOCH FROM ts) AS ts, lsn, txid FROM monitor.heartbeat;\n\n  ttl: 10\n  min_version: 90100\n  tags: [ \"dbname:postgres\", \"schema:monitor\" ]\n  skip: true\n  metrics:\n    - cluster_name:     { usage: LABEL   ,description: \"cluster_name param of this database cluster\" }\n    - ts:               { usage: GAUGE   ,description: \"unix timestamp of the heartbeat\" }\n    - lsn:              { usage: COUNTER ,description: \"lsn of the heartbeat\" }\n    - txid:             { usage: GAUGE   ,description: \"txid of the heartbeat\" }\n\n\n"
  },
  {
    "path": "main.go",
    "content": "/***********************************************************************\\\nCopyright © 2018-2026 Ruohang Feng <rh@vonng.com>\nContributors: https://github.com/pgsty/pg_exporter/graphs/contributors\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\\***********************************************************************/\n\npackage main\n\nimport \"pg_exporter/exporter\"\n\nfunc main() {\n\texporter.Run()\n}\n"
  },
  {
    "path": "monitor/initdb.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n#==============================================================#\n# File      :   initdb.sh\n# Mtime     :   2020-09-02\n# Desc      :   initdb.sh\n# Path      :   /pg/bin/initdb.sh\n# Depend    :   CentOS 7\n# Author    :   Vonng(rh@vonng.com)\n# Note      :   Run this as dbsu (postgres)\n#==============================================================#\nPROG_NAME=\"$(basename $0))\"\nPROG_DIR=\"$(cd $(dirname $0) && pwd)\"\n\n\n#---------------------------------------------------------------------------\nfunction log() {\n    printf \"[$(date \"+%Y-%m-%d %H:%M:%S\")][$HOSTNAME][INITDB] $*\\n\" >> /pg/log/initdb.log\n}\n#---------------------------------------------------------------------------\n\n\n#----------------------------------------------------------------------------\n# template variables\n#----------------------------------------------------------------------------\nPG_DBSU='{{ pg_dbsu }}'\nPG_REPLICATION_USERNAME='{{ pg_replication_username }}'\nPG_REPLICATION_PASSWORD='{{ pg_replication_password }}'\nPG_MONITOR_USERNAME='{{ pg_monitor_username }}'\nPG_MONITOR_PASSWORD='{{ pg_monitor_password }}'\nPG_DEFAULT_USERNAME='{{ pg_default_username }}'\nPG_DEFAULT_PASSWORD='{{ pg_default_password }}'\nPG_DEFAULT_DATABASE='{{ pg_default_database }}'\nPG_DEFAULT_SCHEMA='{{ pg_default_schema }}'\nPG_DEFAULT_EXTENSIONS='{{ pg_default_extensions }}'\n\n#----------------------------------------------------------------------------\n# system users\n#----------------------------------------------------------------------------\nlog \"initdb: create system users: ${PG_REPLICATION_USERNAME} , ${PG_MONITOR_USERNAME}\"\npsql -AXtwq postgres <<- EOF\n\t-- dbsu\n\tCREATE USER ${PG_DBSU};\n\tALTER USER \"${PG_DBSU}\" SUPERUSER;\n\tCOMMENT ON ROLE \"${PG_REPLICATION_USERNAME}\" IS 'system default sa';\n\n\t-- replication user (also used as rewind user)\n\tCREATE USER ${PG_REPLICATION_USERNAME};\n\tCOMMENT ON ROLE \"${PG_REPLICATION_USERNAME}\" IS 'system user for replication';\n\tALTER  USER  ${PG_REPLICATION_USERNAME} REPLICATION PASSWORD '${PG_REPLICATION_PASSWORD}';\n\tGRANT EXECUTE ON function pg_catalog.pg_ls_dir(text, boolean, boolean) TO \"${PG_REPLICATION_USERNAME}\";\n\tGRANT EXECUTE ON function pg_catalog.pg_stat_file(text, boolean) TO \"${PG_REPLICATION_USERNAME}\";\n\tGRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text) TO \"${PG_REPLICATION_USERNAME}\";\n\tGRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text, bigint, bigint, boolean) TO  \"${PG_REPLICATION_USERNAME}\";\n\n\t-- system user: dbuser_monitor\n\tCREATE USER \"${PG_MONITOR_USERNAME}\";\n\tCOMMENT ON ROLE \"${PG_MONITOR_USERNAME}\" IS 'system user for monitor';\n\tALTER USER \"${PG_MONITOR_USERNAME}\" LOGIN NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOREPLICATION;\n\tALTER USER \"${PG_MONITOR_USERNAME}\" PASSWORD '${PG_MONITOR_PASSWORD}' CONNECTION LIMIT 8;\n\tALTER USER \"${PG_MONITOR_USERNAME}\" SET search_path = public,monitor;\n\tGRANT pg_monitor TO \"${PG_MONITOR_USERNAME}\";\nEOF\n\n\n#----------------------------------------------------------------------------\n# default roles\n#----------------------------------------------------------------------------\nlog \"initdb: create default roles: dbrole_admin, dbrole_readwrite, dbrole_readonly\"\npsql -AXtwq postgres <<- EOF\n\t-- default read-only role: personal account, analysis & etl purpose\n\tCREATE ROLE dbrole_readonly;        -- analysis , personal account, etc...\n\tCOMMENT ON ROLE dbrole_readonly IS 'read-only role, for personal, analysis, etl purpose';\n\tALTER ROLE dbrole_readonly NOLOGIN NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOREPLICATION NOBYPASSRLS;\n\n\t-- default read-write role: common production account\n\tCREATE ROLE dbrole_readwrite;       -- common read-write, production account\n\tALTER ROLE dbrole_readwrite NOLOGIN NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOREPLICATION NOBYPASSRLS;\n\tCOMMENT ON ROLE dbrole_readwrite IS 'read-write role, common production account';\n\n\t-- default admin role: create database,role,table, partition, index, etc...\n\tCREATE ROLE dbrole_admin;\t\t\t-- admin role, create db, role, table, partition, index, etc...\n\tCOMMENT ON ROLE dbrole_admin IS 'admin role, create db, role, table, partition, index, etc...';\n\tALTER ROLE dbrole_admin NOLOGIN NOSUPERUSER INHERIT CREATEROLE CREATEDB NOREPLICATION BYPASSRLS;\n\n\t-- grant\n\tGRANT dbrole_readonly TO dbrole_readwrite;\n\tGRANT dbrole_readonly TO \"${PG_MONITOR_USERNAME}\"; -- since monitor user can only access from local or meta nodes\n\tGRANT dbrole_readwrite TO dbrole_admin;\nEOF\n\n\n#----------------------------------------------------------------------------\n# default user (business account)\n#----------------------------------------------------------------------------\nif [ ${PG_DEFAULT_USERNAME} != 'postgres' ]; then\n\tlog \"initdb: create default business user: ${PG_DEFAULT_USERNAME}\"\n\tpsql -AXtwq postgres <<- EOF\n\t\t-- default user\n\t\tCREATE USER \"${PG_DEFAULT_USERNAME}\";\n\t\tCOMMENT ON ROLE \"${PG_DEFAULT_USERNAME}\" IS 'default business user';\n\t\tALTER USER \"${PG_DEFAULT_USERNAME}\" LOGIN NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOREPLICATION BYPASSRLS;\n\t\tALTER USER \"${PG_DEFAULT_USERNAME}\" PASSWORD '${PG_DEFAULT_PASSWORD}';\n\t\tGRANT dbrole_readwrite TO \"${PG_DEFAULT_USERNAME}\";\n\tEOF\nfi\n\n\n#----------------------------------------------------------------------------\n# create pgpass\n#----------------------------------------------------------------------------\nlog \"initdb: create pgpass file\"\necho \"\" >> ~/.pgpass\nfunction add_pgpass(){\n\tlocal username=$1\n\tlocal password=$2\n\tif grep -q \"${username}\": ~/.pgpass; then\n\t\tsed -i \"/${username}/d\" ~/.pgpass\n\tfi\n\techo '*:*:*'\"${username}:${password}\" >> ~/.pgpass\n\tchmod 0600 ~/.pgpass\n}\nadd_pgpass ${PG_REPLICATION_USERNAME} ${PG_REPLICATION_PASSWORD}\nadd_pgpass ${PG_MONITOR_USERNAME} ${PG_MONITOR_PASSWORD}\nif [[ ${PG_DEFAULT_USERNAME} != 'postgres' ]]; then\n\tadd_pgpass ${PG_DEFAULT_USERNAME} ${PG_DEFAULT_PASSWORD}\nfi\n\n\n#----------------------------------------------------------------------------\n# default privilege\n#----------------------------------------------------------------------------\nlog \"initdb: alter default privilege: postgres template1\"\nfor database in postgres template1\ndo\n\tpsql -AXtwq ${database} <<- EOF\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT USAGE ON SCHEMAS TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT SELECT ON TABLES TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT SELECT ON SEQUENCES TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT EXECUTE ON FUNCTIONS TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT INSERT, UPDATE, DELETE ON TABLES TO dbrole_readwrite;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT USAGE, UPDATE ON SEQUENCES TO dbrole_readwrite;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT TRUNCATE, REFERENCES, TRIGGER ON TABLES TO dbrole_admin;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT CREATE ON SCHEMAS TO dbrole_admin;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE dbrole_admin GRANT USAGE ON TYPES TO dbrole_admin;\n\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT USAGE ON SCHEMAS TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT SELECT ON TABLES TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT SELECT ON SEQUENCES TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT EXECUTE ON FUNCTIONS TO dbrole_readonly;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT INSERT, UPDATE, DELETE ON TABLES TO dbrole_readwrite;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT USAGE, UPDATE ON SEQUENCES TO dbrole_readwrite;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT TRUNCATE, REFERENCES, TRIGGER ON TABLES TO dbrole_admin;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT CREATE ON SCHEMAS TO dbrole_admin;\n\t\tALTER DEFAULT PRIVILEGES FOR ROLE postgres GRANT USAGE ON TYPES TO dbrole_admin;\n\tEOF\ndone\n\n\n#----------------------------------------------------------------------------\n# template database\n#----------------------------------------------------------------------------\nlog \"initdb: init database template: postgres, template1\"\nfor database in postgres template1; do\n\tpsql -AXtwq ${database} <<-EOF\n\t\tCREATE SCHEMA IF NOT EXISTS monitor;\n\t\tSET search_path = public, monitor;\n\n\t\t-- create stats extensions within monitor schema\n\t\tCREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pgstattuple WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_qualstats WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_buffercache WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pageinspect WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_prewarm WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_visibility WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_freespacemap WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_repack WITH SCHEMA monitor;\n\t\tCREATE EXTENSION IF NOT EXISTS pg_stat_kcache WITH SCHEMA monitor;\n\t\t-- CREATE EXTENSION IF NOT EXISTS pg_cron WITH SCHEMA monitor;\n\n\t\t-- Table bloat estimate\n\t\tCREATE OR REPLACE VIEW monitor.pg_table_bloat AS\n\t\t    SELECT CURRENT_CATALOG AS datname, nspname, relname , bs * tblpages AS size,\n\t\t           CASE WHEN tblpages - est_tblpages_ff > 0 THEN (tblpages - est_tblpages_ff)/tblpages::FLOAT ELSE 0 END AS ratio\n\t\t    FROM (\n\t\t             SELECT ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff,\n\t\t                    tblpages, fillfactor, bs, tblid, nspname, relname, is_na\n\t\t             FROM (\n\t\t                      SELECT\n\t\t                          ( 4 + tpl_hdr_size + tpl_data_size + (2 * ma)\n\t\t                              - CASE WHEN tpl_hdr_size % ma = 0 THEN ma ELSE tpl_hdr_size % ma END\n\t\t                              - CASE WHEN ceil(tpl_data_size)::INT % ma = 0 THEN ma ELSE ceil(tpl_data_size)::INT % ma END\n\t\t                              ) AS tpl_size, (heappages + toastpages) AS tblpages, heappages,\n\t\t                          toastpages, reltuples, toasttuples, bs, page_hdr, tblid, nspname, relname, fillfactor, is_na\n\t\t                      FROM (\n\t\t                               SELECT\n\t\t                                   tbl.oid AS tblid, ns.nspname , tbl.relname, tbl.reltuples,\n\t\t                                   tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages,\n\t\t                                   coalesce(toast.reltuples, 0) AS toasttuples,\n\t\t                                   coalesce(substring(array_to_string(tbl.reloptions, ' ') FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor,\n\t\t                                   current_setting('block_size')::numeric AS bs,\n\t\t                                   CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma,\n\t\t                                   24 AS page_hdr,\n\t\t                                   23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END\n\t\t                                       + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size,\n\t\t                                   sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size,\n\t\t                                   bool_or(att.atttypid = 'pg_catalog.name'::regtype)\n\t\t                                       OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na\n\t\t                               FROM pg_attribute AS att\n\t\t                                        JOIN pg_class AS tbl ON att.attrelid = tbl.oid\n\t\t                                        JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace\n\t\t                                        LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname\n\t\t                                        LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid\n\t\t                               WHERE NOT att.attisdropped AND tbl.relkind = 'r' AND nspname NOT IN ('pg_catalog','information_schema')\n\t\t                               GROUP BY 1,2,3,4,5,6,7,8,9,10\n\t\t                           ) AS s\n\t\t                  ) AS s2\n\t\t         ) AS s3\n\t\t    WHERE NOT is_na;\n\n\n\t\t-- Index bloat estimate\n\t\tCREATE OR REPLACE VIEW monitor.pg_index_bloat AS\n\t\t    SELECT CURRENT_CATALOG AS datname, nspname, idxname AS relname, relpages::BIGINT * bs AS size,\n\t\t           COALESCE((relpages - ( reltuples * (6 + ma - (CASE WHEN index_tuple_hdr % ma = 0 THEN ma ELSE index_tuple_hdr % ma END)\n\t\t                                                   + nulldatawidth + ma - (CASE WHEN nulldatawidth % ma = 0 THEN ma ELSE nulldatawidth % ma END))\n\t\t                                      / (bs - pagehdr)::FLOAT  + 1 )), 0) / relpages::FLOAT AS ratio\n\t\t    FROM (\n\t\t             SELECT nspname,\n\t\t                    idxname,\n\t\t                    reltuples,\n\t\t                    relpages,\n\t\t                    current_setting('block_size')::INTEGER                                                               AS bs,\n\t\t                    (CASE WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END)  AS ma,\n\t\t                    24                                                                                                   AS pagehdr,\n\t\t                    (CASE WHEN max(COALESCE(pg_stats.null_frac, 0)) = 0 THEN 2 ELSE 6 END)                               AS index_tuple_hdr,\n\t\t                    sum((1.0 - COALESCE(pg_stats.null_frac, 0.0)) *\n\t\t                        COALESCE(pg_stats.avg_width, 1024))::INTEGER                                                     AS nulldatawidth\n\t\t             FROM pg_attribute\n\t\t                      JOIN (\n\t\t                 SELECT pg_namespace.nspname,\n\t\t                        ic.relname                                                   AS idxname,\n\t\t                        ic.reltuples,\n\t\t                        ic.relpages,\n\t\t                        pg_index.indrelid,\n\t\t                        pg_index.indexrelid,\n\t\t                        tc.relname                                                   AS tablename,\n\t\t                        regexp_split_to_table(pg_index.indkey::TEXT, ' ') :: INTEGER AS attnum,\n\t\t                        pg_index.indexrelid                                          AS index_oid\n\t\t                 FROM pg_index\n\t\t                          JOIN pg_class ic ON pg_index.indexrelid = ic.oid\n\t\t                          JOIN pg_class tc ON pg_index.indrelid = tc.oid\n\t\t                          JOIN pg_namespace ON pg_namespace.oid = ic.relnamespace\n\t\t                          JOIN pg_am ON ic.relam = pg_am.oid\n\t\t                 WHERE pg_am.amname = 'btree' AND ic.relpages > 0 AND nspname NOT IN ('pg_catalog', 'information_schema')\n\t\t             ) ind_atts ON pg_attribute.attrelid = ind_atts.indexrelid AND pg_attribute.attnum = ind_atts.attnum\n\t\t                      JOIN pg_stats ON pg_stats.schemaname = ind_atts.nspname\n\t\t                 AND ((pg_stats.tablename = ind_atts.tablename AND pg_stats.attname = pg_get_indexdef(pg_attribute.attrelid, pg_attribute.attnum, TRUE))\n\t\t                     OR (pg_stats.tablename = ind_atts.idxname AND pg_stats.attname = pg_attribute.attname))\n\t\t             WHERE pg_attribute.attnum > 0\n\t\t             GROUP BY 1, 2, 3, 4, 5, 6\n\t\t         ) est\n\t\t    LIMIT 512;\n\n\n\t\t-- index bloat overview\n\t\tCREATE OR REPLACE VIEW monitor.pg_table_bloat_human AS\n\t\tSELECT nspname || '.' || relname AS name,\n\t\t       pg_size_pretty(size)      AS size,\n\t\t       pg_size_pretty((size * ratio)::BIGINT) AS wasted,\n\t\t       round(100 * ratio::NUMERIC, 2)  as ratio\n\t\tFROM monitor.pg_table_bloat ORDER BY wasted DESC NULLS LAST;\n\n\t\tCREATE OR REPLACE VIEW monitor.pg_index_bloat_human AS\n\t\tSELECT nspname || '.' || relname              AS name,\n\t\t       pg_size_pretty(size)                   AS size,\n\t\t       pg_size_pretty((size * ratio)::BIGINT) AS wasted,\n\t\t       round(100 * ratio::NUMERIC, 2)         as ratio\n\t\tFROM monitor.pg_index_bloat;\n\n\n\t\t-- pg session\n\t\tDROP VIEW IF EXISTS monitor.pg_session;\n\t\tCREATE OR REPLACE VIEW monitor.pg_session AS\n\t\tSELECT coalesce(datname, 'all') AS datname,\n\t\t       numbackends,\n\t\t       active,\n\t\t       idle,\n\t\t       ixact,\n\t\t       max_duration,\n\t\t       max_tx_duration,\n\t\t       max_conn_duration\n\t\tFROM (\n\t\t         SELECT datname,\n\t\t                count(*)                                         AS numbackends,\n\t\t                count(*) FILTER ( WHERE state = 'active' )       AS active,\n\t\t                count(*) FILTER ( WHERE state = 'idle' )         AS idle,\n\t\t                count(*) FILTER ( WHERE state = 'idle in transaction'\n\t\t                    OR state = 'idle in transaction (aborted)' ) AS ixact,\n\t\t                max(extract(epoch from now() - state_change))\n\t\t                FILTER ( WHERE state = 'active' )                AS max_duration,\n\t\t                max(extract(epoch from now() - xact_start))      AS max_tx_duration,\n\t\t                max(extract(epoch from now() - backend_start))   AS max_conn_duration\n\t\t         FROM pg_stat_activity\n\t\t         WHERE backend_type = 'client backend'\n\t\t           AND pid <> pg_backend_pid()\n\t\t         GROUP BY ROLLUP (1)\n\t\t         ORDER BY 1 NULLS FIRST\n\t\t     ) t;\n\t\tCOMMENT ON VIEW monitor.pg_session IS 'postgres session stats';\n\n\t\tDROP VIEW IF EXISTS monitor.pg_kill;\n\t\tCREATE OR REPLACE VIEW monitor.pg_kill AS\n\t\tSELECT pid,\n\t\t       pg_terminate_backend(pid)                 AS killed,\n\t\t       datname                                   AS dat,\n\t\t       usename                                   AS usr,\n\t\t       application_name                          AS app,\n\t\t       client_addr                               AS addr,\n\t\t       state,\n\t\t       extract(epoch from now() - state_change)  AS query_time,\n\t\t       extract(epoch from now() - xact_start)    AS xact_time,\n\t\t       extract(epoch from now() - backend_start) AS conn_time,\n\t\t       substring(query, 1, 40)                   AS query\n\t\tFROM pg_stat_activity\n\t\tWHERE backend_type = 'client backend'\n\t\t  AND pid <> pg_backend_pid();\n\t\tCOMMENT ON VIEW monitor.pg_kill IS 'kill all backend session';\n\n\t\t-- quick cancel view\n\t\tDROP VIEW IF EXISTS monitor.pg_cancel;\n\t\tCREATE OR REPLACE VIEW monitor.pg_cancel AS\n\t\tSELECT pid,\n\t\t       pg_cancel_backend(pid)                    AS cancel,\n\t\t       datname                                   AS dat,\n\t\t       usename                                   AS usr,\n\t\t       application_name                          AS app,\n\t\t       client_addr                               AS addr,\n\t\t       state,\n\t\t       extract(epoch from now() - state_change)  AS query_time,\n\t\t       extract(epoch from now() - xact_start)    AS xact_time,\n\t\t       extract(epoch from now() - backend_start) AS conn_time,\n\t\t       substring(query, 1, 40)\n\t\tFROM pg_stat_activity\n\t\tWHERE state = 'active'\n\t\t  AND backend_type = 'client backend'\n\t\t  and pid <> pg_backend_pid();\n\t\tCOMMENT ON VIEW monitor.pg_cancel IS 'cancel backend queries';\n\n\t\t-- seq scan\n\t\tDROP VIEW IF EXISTS monitor.pg_seq_scan;\n\t\tCREATE OR REPLACE VIEW monitor.pg_seq_scan AS\n\t\tSELECT schemaname                             AS nspname,\n\t\t       relname,\n\t\t       seq_scan,\n\t\t       seq_tup_read,\n\t\t       seq_tup_read / seq_scan                AS seq_tup_avg,\n\t\t       idx_scan,\n\t\t       n_live_tup + n_dead_tup                AS tuples,\n\t\t       n_live_tup / (n_live_tup + n_dead_tup) AS dead_ratio\n\t\tFROM pg_stat_user_tables\n\t\tWHERE seq_scan > 0\n\t\t  and (n_live_tup + n_dead_tup) > 0\n\t\tORDER BY seq_tup_read DESC\n\t\tLIMIT 50;\n\t\tCOMMENT ON VIEW monitor.pg_seq_scan IS 'table that have seq scan';\n\tEOF\n\n\tpsql -AXtwq ${database} <<-'EOF'\n\t\tCREATE OR REPLACE FUNCTION monitor.pg_shmem() RETURNS SETOF pg_shmem_allocations AS $$ SELECT * FROM pg_shmem_allocations;$$ LANGUAGE SQL SECURITY DEFINER;\n\tEOF\n\ndone\n\n\n#----------------------------------------------------------------------------\n# default database\n#----------------------------------------------------------------------------\nif [ ${PG_DEFAULT_DATABASE} != 'postgres' ]; then\n\tlog \"initdb: create default database: ${PG_DEFAULT_DATABASE}\"\n\tpsql -AXtwq postgres <<- EOF\n\t\tCREATE DATABASE \"${PG_DEFAULT_DATABASE}\";\n\tEOF\n\n\tif [ ${PG_DEFAULT_SCHEMA} != 'public' ]; then\n\t\tlog \"initdb: create default schema on ${PG_DEFAULT_DATABASE} : ${PG_DEFAULT_SCHEMA}\"\n\t\tpsql -AXtwq ${PG_DEFAULT_DATABASE} <<- EOF\n\t\t\tCREATE SCHEMA IF NOT EXISTS ${PG_DEFAULT_SCHEMA};\n\t\t\tALTER USER \"${PG_DBSU}\" SET search_path = ${PG_DEFAULT_SCHEMA},public,monitor;\n\t\tEOF\n\tfi\n\n\tif [ ${PG_DEFAULT_EXTENSIONS} != '' ]; then\n\t\tlog \"initdb: create default extensions on ${PG_DEFAULT_DATABASE} : ${PG_DEFAULT_EXTENSIONS}\"\n\t\tfor ext in ${PG_DEFAULT_EXTENSIONS//,/ }\n\t\tdo\n\t\t\tlog \"initdb: create extension ${ext};\"\n\t\t\tpsql -AXtwq ${PG_DEFAULT_DATABASE} <<- EOF\n\t\t\t\tCREATE EXTENSION IF NOT EXISTS ${ext} WITH SCHEMA public;\n\t\t\tEOF\n\t\tdone\n\tfi\nfi\n\n\n#----------------------------------------------------------------------------\n# customize commands\n#----------------------------------------------------------------------------\nlog \"initdb: completed!\"\n"
  },
  {
    "path": "monitor/pgrds-instance.json",
    "content": "{\n    \"annotations\": {\n        \"list\": [\n            {\n                \"builtIn\": 1,\n                \"datasource\": {\n                    \"type\": \"datasource\",\n                    \"uid\": \"grafana\"\n                },\n                \"enable\": true,\n                \"hide\": true,\n                \"iconColor\": \"rgba(0, 211, 255, 1)\",\n                \"name\": \"Annotations & Alerts\",\n                \"target\": {\n                    \"limit\": 100,\n                    \"matchAny\": false,\n                    \"tags\": [],\n                    \"type\": \"dashboard\"\n                },\n                \"type\": \"dashboard\"\n            }\n        ]\n    },\n    \"author\": \"Ruohang Feng (rh@vonng.com)\",\n    \"description\": \"PostgreSQL Monitoring for Remote RDS instances (with limited metrics)\",\n    \"editable\": true,\n    \"fiscalYearStartMonth\": 0,\n    \"graphTooltip\": 0,\n    \"id\": null,\n    \"license\": \"AGPLv3 @ https://pigsty.io/docs/about/license\",\n    \"links\": [\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Overview\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Overview\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        },\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Cluster\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Cluster\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        },\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Instance\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Instance\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        },\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Database\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Database\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        }\n    ],\n    \"liveNow\": false,\n    \"panels\": [\n        {\n            \"collapsed\": false,\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 0\n            },\n            \"id\": 86,\n            \"panels\": [],\n            \"title\": \"Overview\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"mappings\": [],\n                    \"max\": 2.5,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#6986a3\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Cluster\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${cls}\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Cluster\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGRDS Cluster : ${cls}\",\n                                        \"url\": \"/d/pgrds-cluster?var-cls=${cls}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${ins}\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Instance\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGCAT Instance : ${ins}\",\n                                        \"url\": \"/d/pgcat-instance?var-dsn=${ins}.${datname}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"IP\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Node IP\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${ip}\"\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"Node Instance : ${ip}\",\n                                        \"url\": \"/d/node-instance?var-id=${ip}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Name\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${node}\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Hostname\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"Node Instance : ${node}\",\n                                        \"url\": \"/d/node-instance?var-id=${node}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 4,\n                \"w\": 6,\n                \"x\": 0,\n                \"y\": 1\n            },\n            \"id\": 189,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"horizontal\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 20,\n                    \"valueSize\": 16\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"1\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Instance\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"1\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Cluster\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"All instances among pgsql cluster ${cls}\\n\\nInstance: Goto PGSQL Instance\\n\\nIP: Goto PGSQL Node\\n\\nStatus: Goto PGSQL Service\\n\\nLoad: max(cpu,postgres,pgbouncer)\\n\\nSpace: Disk space usage max(all device)\\n\\nProxy: session number, Goto Haproxy Admin Page\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"custom\": {\n                        \"align\": \"center\",\n                        \"cellOptions\": {\n                            \"type\": \"auto\"\n                        },\n                        \"inspect\": false\n                    },\n                    \"mappings\": [],\n                    \"max\": 1.2,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#e3e3e3e0\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGRDS Instance ${__data.fields.Instance}\",\n                                        \"url\": \"/d/pgrds-instance?var-ins=${__data.fields.Instance}&${__url_time_range}\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.width\"\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Host\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": []\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Role\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#3e668f\",\n                                                \"index\": 0,\n                                                \"text\": \"primary\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"replica\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"mode\": \"gradient\",\n                                    \"type\": \"color-background\"\n                                }\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Service for ${cls}-${__data.fields.Role}\",\n                                        \"url\": \"/d/pgsql-service?var-svc=${cls}-${__data.fields.Role}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Load\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"auto\"\n                                }\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"mode\": \"thresholds\"\n                                }\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"short\"\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 120\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 0.1\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 0.3\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 0.5\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 0.7\n                                        },\n                                        {\n                                            \"color\": \"#b783af\",\n                                            \"value\": 0.9\n                                        },\n                                        {\n                                            \"color\": \"text\",\n                                            \"value\": 1\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 2\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"-1\": {\n                                                \"color\": \"transparent\",\n                                                \"index\": 0,\n                                                \"text\": \"N/A\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Cluster\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Cluster for ${__data.fields.Cluster}\",\n                                        \"url\": \"/d/pgsql-cluster?var-cls=${__data.fields.Cluster}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"TPS\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": 32\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 32000\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"DB Conn\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 4\n                                        },\n                                        {\n                                            \"color\": \"#EAB839\",\n                                            \"value\": 20\n                                        },\n                                        {\n                                            \"color\": \"#EF843C\",\n                                            \"value\": 40\n                                        },\n                                        {\n                                            \"color\": \"#E24D42\",\n                                            \"value\": 80\n                                        },\n                                        {\n                                            \"color\": \"#b783af\",\n                                            \"value\": 100\n                                        },\n                                        {\n                                            \"color\": \"text\",\n                                            \"value\": 400\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"RT\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"match\": \"nan\",\n                                            \"result\": {\n                                                \"index\": 1,\n                                                \"text\": \"-\"\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 1\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 2\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 4\n                                        },\n                                        {\n                                            \"color\": \"#b783af\",\n                                            \"value\": 8\n                                        },\n                                        {\n                                            \"color\": \"text\",\n                                            \"value\": 16\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Session\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 72\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 1\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 1000\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 2000\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 3000\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Queue\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 60\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 1\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"HAProxy\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"HAProxy Admin Page : ${__data.fields.Instance}\",\n                                        \"url\": \"http://h.pigsty/${__data.fields.Instance}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Up\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#cc4637d9\",\n                                                \"index\": 0,\n                                                \"text\": \"Dead\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"Alive\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-background\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"UPTime\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 1\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 100\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 300\n                                        },\n                                        {\n                                            \"color\": \"#eab839\",\n                                            \"value\": 3600\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 86400\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 18,\n                \"x\": 6,\n                \"y\": 1\n            },\n            \"id\": 191,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"cellHeight\": \"sm\",\n                \"footer\": {\n                    \"countRows\": false,\n                    \"fields\": \"\",\n                    \"reducer\": [\n                        \"sum\"\n                    ],\n                    \"show\": false\n                },\n                \"showHeader\": true,\n                \"sortBy\": [\n                    {\n                        \"desc\": false,\n                        \"displayName\": \"Instance\"\n                    }\n                ]\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"min by (ins,ip) (pg_up{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg:ins:active_time_rate1m{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (ins) (pg:ins:xact_total_rate1m{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"min by (ins,ip) (pg_in_recovery{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"D\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg:ins:num_backends{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"E\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pgbouncer:ins:xact_rt_1m{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": true,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"F\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg_uptime{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"G\"\n                }\n            ],\n            \"transformations\": [\n                {\n                    \"id\": \"seriesToColumns\",\n                    \"options\": {\n                        \"byField\": \"ins\"\n                    }\n                },\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time\": true,\n                            \"Time 1\": true,\n                            \"Time 10\": true,\n                            \"Time 2\": true,\n                            \"Time 3\": true,\n                            \"Time 4\": true,\n                            \"Time 6\": true,\n                            \"Time 8\": true,\n                            \"Time 9\": true,\n                            \"Value #A\": false,\n                            \"Value #B\": false,\n                            \"Value #H\": false,\n                            \"__name__\": true,\n                            \"__name__ 1\": true,\n                            \"__name__ 2\": true,\n                            \"__name__ 3\": true,\n                            \"__name__ 5\": true,\n                            \"__name__ 7\": true,\n                            \"cls\": true,\n                            \"cls 1\": true,\n                            \"cls 2\": true,\n                            \"cls 3\": true,\n                            \"cls 4\": true,\n                            \"cls 5\": true,\n                            \"cls 6\": true,\n                            \"cls 7\": true,\n                            \"instance\": false,\n                            \"instance 1\": true,\n                            \"instance 2\": false,\n                            \"instance 3\": true,\n                            \"instance 4\": true,\n                            \"instance 5\": true,\n                            \"instance 6\": true,\n                            \"ip 2\": true,\n                            \"ip 3\": true,\n                            \"ip 4\": true,\n                            \"ip 5\": true,\n                            \"ip 6\": true,\n                            \"ip 7\": true,\n                            \"job\": true,\n                            \"job 1\": true,\n                            \"job 2\": true,\n                            \"job 3\": true,\n                            \"job 4\": true,\n                            \"job 5\": true,\n                            \"job 6\": true,\n                            \"job 7\": true\n                        },\n                        \"indexByName\": {\n                            \"Time 1\": 7,\n                            \"Time 2\": 8,\n                            \"Time 3\": 9,\n                            \"Time 4\": 10,\n                            \"Time 5\": 11,\n                            \"Value #A\": 2,\n                            \"Value #B\": 4,\n                            \"Value #C\": 5,\n                            \"Value #D\": 3,\n                            \"Value #E\": 6,\n                            \"ins\": 0,\n                            \"ip 1\": 1,\n                            \"ip 2\": 12\n                        },\n                        \"renameByName\": {\n                            \"Time 4\": \"\",\n                            \"Value #A\": \"Up\",\n                            \"Value #B\": \"Load\",\n                            \"Value #C\": \"TPS\",\n                            \"Value #D\": \"Role\",\n                            \"Value #E\": \"Session\",\n                            \"Value #F\": \"RT\",\n                            \"Value #G\": \"UPTime\",\n                            \"Value #H\": \"LB\",\n                            \"Value #I\": \"QPS\",\n                            \"Value #J\": \"LB Clients\",\n                            \"Value #K\": \"Lag\",\n                            \"cls 1\": \"\",\n                            \"cls 2\": \"\",\n                            \"ins\": \"Instance\",\n                            \"instance\": \"HAProxy\",\n                            \"instance 2\": \"\",\n                            \"ip\": \"IP\",\n                            \"ip 1\": \"Host\"\n                        }\n                    }\n                }\n            ],\n            \"type\": \"table\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"mappings\": [],\n                    \"max\": 2.5,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#6986a3\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 2,\n                \"w\": 6,\n                \"x\": 0,\n                \"y\": 5\n            },\n            \"id\": 190,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"/.*/\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"valueSize\": 12\n                },\n                \"textMode\": \"value\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (address) (label_join(pg_meta_info{ins=\\\"$ins\\\"}, \\\"address\\\", \\\":\\\", \\\"ip\\\", \\\"listen_port\\\"))\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"__auto\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"A\"\n                }\n            ],\n            \"transformations\": [\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time\": true,\n                            \"Value\": true,\n                            \"__name__\": true,\n                            \"cls\": true,\n                            \"cluster_id\": true,\n                            \"ins\": true,\n                            \"instance\": true,\n                            \"ip\": false,\n                            \"job\": true,\n                            \"ver_num\": true,\n                            \"version\": true,\n                            \"wal_level\": true\n                        },\n                        \"indexByName\": {\n                            \"Time\": 0,\n                            \"Value\": 9,\n                            \"__name__\": 1,\n                            \"cls\": 2,\n                            \"cluster_id\": 3,\n                            \"ins\": 4,\n                            \"instance\": 12,\n                            \"ip\": 10,\n                            \"job\": 5,\n                            \"listen_port\": 11,\n                            \"ver_num\": 8,\n                            \"version\": 6,\n                            \"wal_level\": 7\n                        },\n                        \"renameByName\": {\n                            \"cls\": \"Cluster\",\n                            \"cluster_id\": \"Cluster ID\",\n                            \"ins\": \"Leader\",\n                            \"ip\": \"Host\",\n                            \"listen_port\": \"Port\",\n                            \"version\": \"Version\",\n                            \"wal_level\": \"WAL Level\"\n                        }\n                    }\n                },\n                {\n                    \"id\": \"filterFieldsByName\",\n                    \"options\": {}\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"mappings\": [],\n                    \"max\": 2.5,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#6986a3\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Leader\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGRDS Leader : ${primary}\",\n                                        \"url\": \"/d/pgrds-instance?var-ins=${primary}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Kernel\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"pattern\": \".*wiltondb.*\",\n                                            \"result\": {\n                                                \"color\": \"#d82024e3\",\n                                                \"index\": 0,\n                                                \"text\": \"Babelfish\"\n                                            }\n                                        },\n                                        \"type\": \"regex\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"pattern\": \".*PolarDB.*\",\n                                            \"result\": {\n                                                \"color\": \"#f25009\",\n                                                \"index\": 1,\n                                                \"text\": \"PolarDB\"\n                                            }\n                                        },\n                                        \"type\": \"regex\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"pattern\": \".*IvorySQL.*\",\n                                            \"result\": {\n                                                \"color\": \"#ee9832\",\n                                                \"index\": 2,\n                                                \"text\": \"IvorySQL\"\n                                            }\n                                        },\n                                        \"type\": \"regex\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"pattern\": \"PostgreSQL.*\",\n                                            \"result\": {\n                                                \"color\": \"#3e668f\",\n                                                \"index\": 3,\n                                                \"text\": \"PostgreSQL\"\n                                            }\n                                        },\n                                        \"type\": \"regex\"\n                                    }\n                                ]\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 6,\n                \"x\": 0,\n                \"y\": 7\n            },\n            \"id\": 209,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"horizontal\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"/.*/\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 14,\n                    \"valueSize\": 16\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_meta_info{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"__auto\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"A\"\n                }\n            ],\n            \"transformations\": [\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time\": true,\n                            \"Value\": true,\n                            \"__name__\": true,\n                            \"cls\": true,\n                            \"cluster_id\": false,\n                            \"cluster_name\": true,\n                            \"conf_path\": false,\n                            \"data_dir\": false,\n                            \"extensions\": true,\n                            \"hba_path\": false,\n                            \"ins\": true,\n                            \"instance\": true,\n                            \"ip\": true,\n                            \"job\": true,\n                            \"listen_port\": true,\n                            \"primary_conninfo\": true,\n                            \"ver_num\": false,\n                            \"ver_str\": false,\n                            \"version\": true\n                        },\n                        \"includeByName\": {},\n                        \"indexByName\": {\n                            \"Time\": 3,\n                            \"Value\": 10,\n                            \"__name__\": 4,\n                            \"cls\": 5,\n                            \"cluster_id\": 9,\n                            \"cluster_name\": 14,\n                            \"conf_path\": 15,\n                            \"data_dir\": 17,\n                            \"extensions\": 18,\n                            \"hba_path\": 16,\n                            \"ins\": 6,\n                            \"instance\": 13,\n                            \"ip\": 11,\n                            \"job\": 7,\n                            \"listen_port\": 12,\n                            \"ver_num\": 1,\n                            \"ver_str\": 0,\n                            \"version\": 2,\n                            \"wal_level\": 8\n                        },\n                        \"renameByName\": {\n                            \"cls\": \"Cluster\",\n                            \"cluster_id\": \"Cluster ID\",\n                            \"conf_path\": \"Config\",\n                            \"data_dir\": \"Data\",\n                            \"hba_path\": \"HBA\",\n                            \"ins\": \"Leader\",\n                            \"ip\": \"Host\",\n                            \"listen_port\": \"Port\",\n                            \"ver_num\": \"Version\",\n                            \"ver_str\": \"Kernel\",\n                            \"version\": \"Version\",\n                            \"wal_level\": \"WAL Level\"\n                        }\n                    }\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Replication for ${cls}\",\n                            \"url\": \"/d/pgsql-replication?var-cls=${cls}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"max\": 2.5,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"A\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#f5a673\",\n                                                \"index\": 0,\n                                                \"text\": \"Primary\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"Replica\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"Role\"\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"B\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#3e668f\",\n                                                \"index\": 0,\n                                                \"text\": \"No\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"Yes\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"C\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 1\n                                        }\n                                    ]\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"D\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": null\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#f5a673\",\n                                                \"index\": 0,\n                                                \"text\": \"Leading\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#3e668f\",\n                                                \"index\": 1,\n                                                \"text\": \"Follow\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"Node Instance : ${__field.labels.sender_host}\",\n                                        \"url\": \"/d/node-instance?var-id=${__field.labels.sender_host}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"E\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 1\n                                        }\n                                    ]\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"F\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 1\n                                        }\n                                    ]\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 3,\n                \"x\": 6,\n                \"y\": 7\n            },\n            \"id\": 194,\n            \"links\": [\n                {\n                    \"title\": \"PGSQL Replication : ${cls}\",\n                    \"url\": \"/d/pgsql-replication?var-cls=${cls}&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"horizontal\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 10,\n                    \"valueSize\": 10\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"pg_in_recovery{ins=\\\"$ins\\\"}\",\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"recovery\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"(pg_recv_init_lsn{ins=\\\"$ins\\\"} > bool 0) or on() vector(0)\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ sender_host }} \",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"D\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"count(pg_repl_lsn{ins=\\\"$ins\\\"}) or on() vector(0)\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Downstream\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_sync_standby_enabled{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Sync Commit\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"count by (ins)(pg_pubrel_count{ins=\\\"$ins\\\"}) > bool 0 or on() vector(0)\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Publication\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"E\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"count by (ins)(pg_sub_id{ins=\\\"$ins\\\"}) or on() vector(0)\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Subscription\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"F\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"transparent\",\n                                    \"index\": 1\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"WAL Paused\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 0,\n                                                \"text\": \"Running\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#f5a673\",\n                                                \"index\": 1,\n                                                \"text\": \"Paused\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"match\": \"null+nan\",\n                                            \"result\": {\n                                                \"color\": \"transparent\",\n                                                \"index\": 2\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"WAL\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 0,\n                                                \"text\": \"Proceed\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#f5a673\",\n                                                \"index\": 1,\n                                                \"text\": \"Paused\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"match\": \"null+nan\",\n                                            \"result\": {\n                                                \"color\": \"transparent\",\n                                                \"index\": 2\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"PG Uptime\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#cc4637d9\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 300\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 3600\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 86400\n                                        }\n                                    ]\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Aliveness\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#cc4637d9\",\n                                                \"index\": 0,\n                                                \"text\": \"Dead\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"Alive\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Last Reload\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 3,\n                \"x\": 9,\n                \"y\": 7\n            },\n            \"id\": 193,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"horizontal\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 10,\n                    \"valueSize\": 10\n                },\n                \"textMode\": \"auto\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_up{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"instant\": true,\n                    \"legendFormat\": \"__auto\",\n                    \"range\": false,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_uptime{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"legendFormat\": \"__auto\",\n                    \"range\": false,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_version{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"legendFormat\": \"__auto\",\n                    \"range\": false,\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_conf_reload_time{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"legendFormat\": \"__auto\",\n                    \"range\": false,\n                    \"refId\": \"D\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:timeline{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"legendFormat\": \"__auto\",\n                    \"range\": false,\n                    \"refId\": \"E\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_is_wal_replay_paused{ins=\\\"$ins\\\"}\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"legendFormat\": \"__auto\",\n                    \"range\": false,\n                    \"refId\": \"F\"\n                }\n            ],\n            \"transformations\": [\n                {\n                    \"id\": \"joinByField\",\n                    \"options\": {\n                        \"byField\": \"ins\",\n                        \"mode\": \"outer\"\n                    }\n                },\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time\": true,\n                            \"Time 1\": true,\n                            \"Time 10\": true,\n                            \"Time 11\": true,\n                            \"Time 12\": true,\n                            \"Time 2\": true,\n                            \"Time 3\": true,\n                            \"Time 4\": true,\n                            \"Time 5\": true,\n                            \"Time 6\": true,\n                            \"Time 7\": true,\n                            \"Time 8\": true,\n                            \"Time 9\": true,\n                            \"Value #C\": false,\n                            \"Value #E\": false,\n                            \"Value #H\": true,\n                            \"Value #I\": true,\n                            \"Value #K\": true,\n                            \"__name__ 1\": false,\n                            \"cls\": true,\n                            \"ins\": true,\n                            \"scope\": false\n                        },\n                        \"indexByName\": {\n                            \"Time 1\": 6,\n                            \"Time 2\": 7,\n                            \"Time 3\": 8,\n                            \"Time 4\": 9,\n                            \"Time 5\": 10,\n                            \"Time 6\": 11,\n                            \"Value #A\": 0,\n                            \"Value #B\": 2,\n                            \"Value #C\": 5,\n                            \"Value #D\": 3,\n                            \"Value #E\": 4,\n                            \"Value #F\": 1,\n                            \"__name__ 1\": 12,\n                            \"__name__ 2\": 18,\n                            \"__name__ 3\": 23,\n                            \"__name__ 4\": 28,\n                            \"__name__ 5\": 33,\n                            \"__name__ 6\": 38,\n                            \"cls 1\": 14,\n                            \"cls 2\": 19,\n                            \"cls 3\": 24,\n                            \"cls 4\": 29,\n                            \"cls 5\": 34,\n                            \"cls 6\": 39,\n                            \"ins\": 13,\n                            \"instance 1\": 15,\n                            \"instance 2\": 20,\n                            \"instance 3\": 25,\n                            \"instance 4\": 30,\n                            \"instance 5\": 35,\n                            \"instance 6\": 40,\n                            \"ip 1\": 16,\n                            \"ip 2\": 21,\n                            \"ip 3\": 26,\n                            \"ip 4\": 31,\n                            \"ip 5\": 36,\n                            \"ip 6\": 41,\n                            \"job 1\": 17,\n                            \"job 2\": 22,\n                            \"job 3\": 27,\n                            \"job 4\": 32,\n                            \"job 5\": 37,\n                            \"job 6\": 42\n                        },\n                        \"renameByName\": {\n                            \"Value #A\": \"Aliveness\",\n                            \"Value #B\": \"PG Uptime\",\n                            \"Value #C\": \"Version\",\n                            \"Value #D\": \"Last Reload\",\n                            \"Value #E\": \"Timeline\",\n                            \"Value #F\": \"WAL Paused\",\n                            \"Value #G\": \"\",\n                            \"Value #H\": \"\",\n                            \"Value #I\": \"\",\n                            \"Value #J\": \"\",\n                            \"Value #K\": \"\",\n                            \"Value #L\": \"Up\",\n                            \"cls\": \"Cluster\",\n                            \"ins\": \"Instance\",\n                            \"scope\": \"Shard\"\n                        }\n                    }\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database of this cluster ${cls}\\n\\nLoad: active_time / backends (PG14 only)\\n\\nQuery RT : max query rt of this database\\n\\nClient: Pgbouncer Active Clients\\n\\nServer: Pgbouncer Active Servers\\n\\nBackend: Postgres num backends\\n\\nT = is Template?\\n\\nD = Disabled in Pgbouncer ?\\n\\nP = Paused in Pgbouncer ?\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"custom\": {\n                        \"align\": \"center\",\n                        \"cellOptions\": {\n                            \"mode\": \"gradient\",\n                            \"type\": \"color-background\"\n                        },\n                        \"inspect\": false\n                    },\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#e3e3e3e0\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Database\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Database : ${ins}.${__data.fields.Database}\",\n                                        \"url\": \"/d/pgsql-database?var-ins=${ins}&var-datname=${__data.fields.Database}&${__url_time_range}\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"postgres\": {\n                                                \"color\": \"#808080\",\n                                                \"index\": 2\n                                            },\n                                            \"template0\": {\n                                                \"color\": \"#c0c0c0e0\",\n                                                \"index\": 0\n                                            },\n                                            \"template1\": {\n                                                \"color\": \"#a8a8a8e0\",\n                                                \"index\": 1\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            },\n                            {\n                                \"id\": \"filterable\"\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Size\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"decbytes\"\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 1000000000\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 1000000000000\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 10000000000000\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"mode\": \"thresholds\"\n                                }\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 0\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Age\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 60000000\n                                        },\n                                        {\n                                            \"color\": \"#EAB839\",\n                                            \"value\": 200000000\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 600000000\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 1000000000\n                                        },\n                                        {\n                                            \"color\": \"#b783af\",\n                                            \"value\": 2000000000\n                                        },\n                                        {\n                                            \"color\": \"text\",\n                                            \"value\": 2137483647\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"percentunit\"\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 60\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"mode\": \"thresholds\"\n                                }\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 1\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"TPS\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 30000\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 70\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"mode\": \"thresholds\"\n                                }\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 1\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"T\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 40\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"F\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#f5a673\",\n                                                \"index\": 2,\n                                                \"text\": \"T\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"match\": \"null+nan\",\n                                            \"result\": {\n                                                \"color\": \"#e3e3e3e0\",\n                                                \"index\": 0,\n                                                \"text\": \"N\"\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"mode\": \"gradient\",\n                                    \"type\": \"color-background\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 4\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 1000\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"mode\": \"thresholds\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 75\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"ConnLimit\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 85\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"color\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"-1\": {\n                                                \"color\": \"#3e668f\",\n                                                \"index\": 1,\n                                                \"text\": \"NO LIMIT\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"match\": \"null+nan\",\n                                            \"result\": {\n                                                \"color\": \"gray\",\n                                                \"index\": 0,\n                                                \"text\": \"N/A\"\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    },\n                                    {\n                                        \"options\": {\n                                            \"from\": 0,\n                                            \"result\": {\n                                                \"color\": \"#f5a673\",\n                                                \"index\": 2\n                                            },\n                                            \"to\": 99999999\n                                        },\n                                        \"type\": \"range\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byRegexp\",\n                            \"options\": \"Conn%\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"percentunit\"\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 0.1\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 0.3\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 0.5\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 0.7\n                                        },\n                                        {\n                                            \"color\": \"#b783af\",\n                                            \"value\": 0.9\n                                        },\n                                        {\n                                            \"color\": \"text\",\n                                            \"value\": 0.99\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 1\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Client\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 60\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 1000\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Server\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 60\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 4\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 1000\n                                        }\n                                    ]\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"RT\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#fcdb72\",\n                                            \"value\": 1\n                                        },\n                                        {\n                                            \"color\": \"#f5a673\",\n                                            \"value\": 2\n                                        },\n                                        {\n                                            \"color\": \"red\",\n                                            \"value\": 4\n                                        },\n                                        {\n                                            \"color\": \"#b783af\",\n                                            \"value\": 8\n                                        },\n                                        {\n                                            \"color\": \"text\",\n                                            \"value\": 16\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"match\": \"null+nan\",\n                                            \"result\": {\n                                                \"index\": 0,\n                                                \"text\": \"-\"\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Load\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"short\"\n                            },\n                            {\n                                \"id\": \"decimals\",\n                                \"value\": 1\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        },\n                                        {\n                                            \"color\": \"#346f36cc\",\n                                            \"value\": 0.1\n                                        }\n                                    ]\n                                }\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"match\": \"null+nan\",\n                                            \"result\": {\n                                                \"index\": 0,\n                                                \"text\": \"-\"\n                                            }\n                                        },\n                                        \"type\": \"special\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"PoolSize\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"auto\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"OID\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 80\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGCAT Database : ${ins}.${__data.fields.Database}\",\n                                        \"url\": \"/d/pgcat-database?var-dsn=${ins}.${__data.fields.Database}\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"from\": 0,\n                                            \"result\": {\n                                                \"color\": \"#bfbfbf4d\",\n                                                \"index\": 0\n                                            },\n                                            \"to\": 10\n                                        },\n                                        \"type\": \"range\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-text\"\n                                }\n                            },\n                            {\n                                \"id\": \"thresholds\",\n                                \"value\": {\n                                    \"mode\": \"absolute\",\n                                    \"steps\": [\n                                        {\n                                            \"color\": \"#3e668f\",\n                                            \"value\": null\n                                        }\n                                    ]\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 7\n            },\n            \"id\": 192,\n            \"options\": {\n                \"cellHeight\": \"sm\",\n                \"footer\": {\n                    \"countRows\": false,\n                    \"fields\": \"\",\n                    \"reducer\": [\n                        \"sum\"\n                    ],\n                    \"show\": false\n                },\n                \"showHeader\": true,\n                \"sortBy\": [\n                    {\n                        \"desc\": true,\n                        \"displayName\": \"OID\"\n                    }\n                ]\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_size_bytes{cls=\\\"$cls\\\", datname!~\\\"wal|log\\\"})\",\n                    \"format\": \"table\",\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Age\",\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"max by (datname) (pg:db:age{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Commit\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"max by (datname) (pg_db_is_template{cls=\\\"$cls\\\", ins=\\\"$primary\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"isTemplate\",\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_activity_count{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Backend\",\n                    \"refId\": \"D\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg:db:xact_commit_rate1m{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"TPS\",\n                    \"refId\": \"E\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"max by (datname) (pg_db_conn_limit{ins=\\\"$primary\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Conn Limit\",\n                    \"refId\": \"F\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"max by (datname) (pg:db:conn_usage{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"PG Conn Usage\",\n                    \"refId\": \"H\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg:db:active_time_rate1m{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Load\",\n                    \"refId\": \"L\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (datname) (pg_db_datid{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"OID\",\n                    \"refId\": \"O\"\n                }\n            ],\n            \"transformations\": [\n                {\n                    \"id\": \"seriesToColumns\",\n                    \"options\": {\n                        \"byField\": \"datname\"\n                    }\n                },\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time 1\": true,\n                            \"Time 10\": true,\n                            \"Time 11\": true,\n                            \"Time 12\": true,\n                            \"Time 13\": true,\n                            \"Time 14\": true,\n                            \"Time 15\": true,\n                            \"Time 2\": true,\n                            \"Time 3\": true,\n                            \"Time 4\": true,\n                            \"Time 5\": true,\n                            \"Time 6\": true,\n                            \"Time 7\": true,\n                            \"Time 8\": true,\n                            \"Time 9\": true,\n                            \"Value #G\": false,\n                            \"Value #H\": false,\n                            \"host\": true\n                        },\n                        \"indexByName\": {\n                            \"Time 1\": 10,\n                            \"Time 2\": 11,\n                            \"Time 3\": 12,\n                            \"Time 4\": 13,\n                            \"Time 5\": 14,\n                            \"Time 6\": 15,\n                            \"Time 7\": 16,\n                            \"Time 8\": 17,\n                            \"Time 9\": 18,\n                            \"Value #A\": 3,\n                            \"Value #B\": 4,\n                            \"Value #C\": 9,\n                            \"Value #D\": 5,\n                            \"Value #E\": 6,\n                            \"Value #F\": 8,\n                            \"Value #H\": 7,\n                            \"Value #L\": 2,\n                            \"Value #O\": 1,\n                            \"datname\": 0\n                        },\n                        \"renameByName\": {\n                            \"Time 1\": \"\",\n                            \"Time 7\": \"\",\n                            \"Value #A\": \"Size\",\n                            \"Value #B\": \"Age\",\n                            \"Value #C\": \"T\",\n                            \"Value #D\": \"Backend\",\n                            \"Value #E\": \"TPS\",\n                            \"Value #F\": \"ConnLimit\",\n                            \"Value #G\": \"RT\",\n                            \"Value #H\": \"Conn%\",\n                            \"Value #I\": \"D\",\n                            \"Value #J\": \"P\",\n                            \"Value #K\": \"PoolSize\",\n                            \"Value #L\": \"Load\",\n                            \"Value #M\": \"Client\",\n                            \"Value #N\": \"Server\",\n                            \"Value #O\": \"OID\",\n                            \"datname\": \"Database\",\n                            \"host\": \"Target\",\n                            \"real_datname\": \"Datname\"\n                        }\n                    }\n                }\n            ],\n            \"type\": \"table\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Instance : TPS by Instance\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=94&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 32\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 32000\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 0,\n                \"y\": 13\n            },\n            \"id\": 46,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:xact_commit_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Commit\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Instance : Rollback\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=169&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 1\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 4\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 8\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 2,\n                \"y\": 13\n            },\n            \"id\": 57,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:xact_rollback_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Rollback\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Instance : RT\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=109&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 1\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 2\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 4\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 8\n                            },\n                            {\n                                \"color\": \"text\",\n                                \"value\": 16\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 4,\n                \"y\": 13\n            },\n            \"id\": 59,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:active_time_rate1m{ins=\\\"$ins\\\"} / pg:ins:xact_total_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"RT\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Conn Usage\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=90&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 0.1\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 0.3\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 0.5\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 0.7\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 0.9\n                            },\n                            {\n                                \"color\": \"text\",\n                                \"value\": 1\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 6,\n                \"y\": 13\n            },\n            \"id\": 106,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max(pg:db:conn_usage{cls=\\\"$cls\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Conn%\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Backend by Instance\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=96&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 4\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 2000\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 8,\n                \"y\": 13\n            },\n            \"id\": 64,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (cls) (pg_db_numbackends{cls=\\\"$cls\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Backend\",\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Session by State\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=149&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 4\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 2000\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 10,\n                \"y\": 13\n            },\n            \"id\": 107,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:active_backends{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Active Conn\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Idle in Transaction Conn\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=159&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 1\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 8\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 12,\n                \"y\": 13\n            },\n            \"id\": 203,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max(pg:ins:ixact_backends{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"iXact Conn\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"decimals\": 2,\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Instance : Row Fetched\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=127&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 32\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 32000\n                            }\n                        ]\n                    },\n                    \"unit\": \"rowsps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 14,\n                \"y\": 13\n            },\n            \"id\": 204,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 12\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:tup_fetched_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Row Fetch\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"decimals\": 2,\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Row Changed\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=128&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 32\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 32000\n                            }\n                        ]\n                    },\n                    \"unit\": \"rowsps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 16,\n                \"y\": 13\n            },\n            \"id\": 205,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 12\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:tup_modified_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Row Change\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Instance : Blocks Read Bandwidth\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=182&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"noValue\": \"\\u2205\",\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 10000000\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 100000000\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 500000000\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 1000000000\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 2000000000\n                            },\n                            {\n                                \"color\": \"text\",\n                                \"value\": 4000000000\n                            }\n                        ]\n                    },\n                    \"unit\": \"Bps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 18,\n                \"y\": 13\n            },\n            \"id\": 206,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 14\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(pg:db:blks_read_1m{ins=\\\"$ins\\\"}) * 4096\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Blks Read\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"decimals\": 2,\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Age of Databases\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=208&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"max\": 1,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"percentage\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 2\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 10\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 30\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 90\n                            },\n                            {\n                                \"color\": \"text\",\n                                \"value\": 100\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 20,\n                \"y\": 13\n            },\n            \"id\": 63,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:age{ins=\\\"$ins\\\"} / 2147483647\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Age\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Database Size\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=176&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 1000000000\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 1000000000000\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 10000000000000\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 3,\n                \"w\": 2,\n                \"x\": 22,\n                \"y\": 13\n            },\n            \"id\": 202,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 12,\n                    \"valueSize\": 18\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(pg_size_bytes{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Size\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Load, 1 = 100% one cpu core usage.\\nCalculated by session active time  (PG14+)\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"decimals\": 2,\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : Load\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${ins}&viewPanel=147&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 0.1\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 3,\n                \"x\": 0,\n                \"y\": 16\n            },\n            \"id\": 199,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {},\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:cls:active_time_rate1m{cls=\\\"$cls\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Load\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Load for Instances / Databases in last 5 minutes\\nload 1 = 100% usage of 1 core cpu time\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 20,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineStyle\": {\n                            \"fill\": \"solid\"\n                        },\n                        \"lineWidth\": 1,\n                        \"pointSize\": 3,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 9,\n                \"x\": 3,\n                \"y\": 16\n            },\n            \"id\": 196,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:active_time_rate1m{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"links\": [\n                        {\n                            \"targetBlank\": true,\n                            \"title\": \"PGSQL Alert for Cluster ${cls}\",\n                            \"url\": \"http://a.pigsty/#/alerts?filter=%7Bcls%3D%22${cls}%22%7D\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 1\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 2\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 3\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 4\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 3,\n                \"x\": 12,\n                \"y\": 16\n            },\n            \"id\": 198,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"auto\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {},\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.1.4\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"count(ALERTS{ins=\\\"$ins\\\", alertstate=\\\"firing\\\"}) or on() vector(0)\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Alert\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Alerting event graph. Each stripe represent an alerting Event. Gray transparent stipe are pending alerts.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"hidden\",\n                        \"axisSoftMax\": 1.2,\n                        \"axisSoftMin\": 0,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 98,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [\n                        {\n                            \"targetBlank\": true,\n                            \"title\": \"AlertInfo ${__field.labels.alertname} on Instance ${ins}\",\n                            \"url\": \"http://a.pigsty/#/alerts?filter=%7Bins%3D%22${ins}%22%2C%20alertname%3D%22${__field.labels.alertname}%22%7D\"\n                        },\n                        {\n                            \"targetBlank\": true,\n                            \"title\": \"Silence ${__field.labels.alertname} on Cluster ${ins}\",\n                            \"url\": \"http://a.pigsty/#/silences/new?filter=%7Bins%3D%22${ins}%22%2C%20alertname%3D%22${__field.labels.alertname}%22%7D\"\n                        },\n                        {\n                            \"title\": \"PGSQL Cluster for ${__field.labels.cls} : Alerts\",\n                            \"url\": \"/d/pgsql-cluster?var-cls=${__field.labels.cls}&${__url_time_range}\"\n                        },\n                        {\n                            \"title\": \"PGSQL Node for ${__field.labels.ins}\",\n                            \"url\": \"/d/node-instance?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"A\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.fillOpacity\",\n                                \"value\": 66\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Firing\\ud83d\\udd25\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"B\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.fillOpacity\",\n                                \"value\": 25\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"rgba(128, 128, 128, 0.5)\",\n                                    \"mode\": \"fixed\"\n                                }\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"color\": \"gray\",\n                                                \"index\": 0,\n                                                \"text\": \"Pend\\u23f0\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byType\",\n                            \"options\": \"time\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.axisPlacement\",\n                                \"value\": \"auto\"\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Alert\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"red\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 9,\n                \"x\": 15,\n                \"y\": 16\n            },\n            \"id\": 197,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"ALERTS{ins=\\\"$ins\\\", alertstate=\\\"firing\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"[{{ severity }}\\ud83d\\udd25] {{alertname}}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"ALERTS{ins=\\\"$ins\\\", alertstate=\\\"pending\\\"} \",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"[{{ severity }}\\u23f0] {{alertname}}\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"exemplar\": false,\n                    \"expr\": \"0\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Alert\",\n                    \"refId\": \"C\"\n                }\n            ],\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 21\n            },\n            \"id\": 133,\n            \"panels\": [],\n            \"title\": \"Activity\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Rate in last 5min of:\\n\\n\\npg_stat_database. xact_commit: Number of transactions in this database that have been committed\\n\\npg_stat_database. xact_rollback: Number of transactions in this database that have been rolled back\\n\\non this postgres instance.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 20,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"smooth\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"A\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"red\",\n                                    \"mode\": \"fixed\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.axisPlacement\",\n                                \"value\": \"auto\"\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Commits\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Rollbacks\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#cc4637d9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 22\n            },\n            \"id\": 169,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=169&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0-beta2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (ins) (pg:ins:xact_commit_rate5m{ins=\\\"$ins\\\"})\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 1,\n                    \"legendFormat\": \"Commits\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (ins) (pg:ins:xact_rollback_rate5m{ins=\\\"$ins\\\"})\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 1,\n                    \"legendFormat\": \"Rollbacks\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Transaction Commits / Rollbacks (rate5m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"pg_stat_database: active_time / (xact_commit + xact_rollback)\\n\\n\\nTime spent executing SQL statements in this instance / Number of transactions in this instance in last 1 minute\\n\\n\\nOnly available on PG14+\\n\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 10,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"smooth\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.fillOpacity\",\n                                \"value\": 21\n                            },\n                            {\n                                \"id\": \"custom.lineWidth\",\n                                \"value\": 0\n                            },\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.gradientMode\",\n                                \"value\": \"hue\"\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Instance : ${__field.labels.ins}\",\n                                        \"url\": \"/d/pgsql-instance?var-ins=${__field.labels.ins}\\ufeff&\\ufeff${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"B\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Database : ${__field.labels.ins}.${__field.labels.datname}\",\n                                        \"url\": \"/d/pgsql-database?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}&viewPanel=137\"\n                                    }\n                                ]\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 22\n            },\n            \"id\": 109,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Transaction RT: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=109&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0-beta2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:active_time_rate1m{ins=\\\"$ins\\\"} / pg:ins:xact_total_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"intervalFactor\": 1,\n                    \"legendFormat\": \"Instance\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:active_time_rate1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'} / pg:db:xact_total_rate1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 1,\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Transaction RT (1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Transaction Committed rate in last 1 minute, group on database level\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 20,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"smooth\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Xacts for ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-xacts?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.lineWidth\",\n                                \"value\": 0\n                            },\n                            {\n                                \"id\": \"custom.fillOpacity\",\n                                \"value\": 20\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 28\n            },\n            \"id\": 94,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster TPS: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=94&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0-beta2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:xact_commit_rate1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 1,\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"TPS by Database (rate1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Postgres Load Index in last 1 minutes\\n\\n\\nrate(pg_stat_database.active_time[5m])\\n\\n\\nload 1 = 100% usage of one cpu core.\\n\\n\\nCalculated by session active time  (PG14+) @ database level.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 40,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineStyle\": {\n                            \"fill\": \"solid\"\n                        },\n                        \"lineWidth\": 1,\n                        \"pointSize\": 3,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 28\n            },\n            \"id\": 147,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Load: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=147&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:active_time_rate1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Postgres Load (rate1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Tuples fetched from databases r/s in last minute, group by database on this instance. \",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 3,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"cps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 34\n            },\n            \"id\": 127,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Row Fetched: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=127&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (rate(pg_db_tup_fetched{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}[1m]))\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Row Fetched (rate1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Tuples fetched, inserted, updated, delete r/s in last minute, on this instance\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 50,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"cps\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"DELETED\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#cc4637d9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"INSERTED\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"UPDATED\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#fcdb72\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 34\n            },\n            \"id\": 128,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Row Modified: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=128&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(rate(pg_db_tup_inserted{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}[1m]))\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"INSERTED\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(rate(pg_db_tup_updated{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}[1m]))\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"UPDATED\",\n                    \"range\": true,\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(rate(pg_db_tup_deleted{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}[1m]))\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"DELETED\",\n                    \"range\": true,\n                    \"refId\": \"D\"\n                }\n            ],\n            \"title\": \"Row Modified (rate1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Table lock categorized in to 3 major categories:\\nRead locks, Write Locks, and Exclusive locks.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"bars\",\n                        \"fillOpacity\": 100,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": true,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 80\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Read\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Write\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Exclusive\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#cc4637d9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 40\n            },\n            \"id\": 180,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Locks by Category: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=180&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Name\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.5\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:xlock_count{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Exclusive\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:wlock_count{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Write\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:rlock_count{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Read\",\n                    \"range\": true,\n                    \"refId\": \"C\"\n                }\n            ],\n            \"title\": \"Locks by Category\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Table Locks in 8 different mode, on this instance\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"bars\",\n                        \"fillOpacity\": 55,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": true,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"AccessShareLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#56A64B\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"RowShareLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#8AB8FF\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"RowExclusiveLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3274D9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"ShareUpdateExclusiveLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#F2CC0C\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"ShareLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#CC9D00\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"ShareRowExclusiveLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#FF780A\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"ExclusiveLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#E02F44\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"AccessExclusiveLock\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#A352CC\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 12,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 40\n            },\n            \"id\": 154,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Locks : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=154&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\",\n                        \"mean\",\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"bottom\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.5\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (mode) (pg_lock_count{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ mode }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Locks\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Very long transactions, max elapse time (y) group by session state. On this postgres instance\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 46\n            },\n            \"id\": 152,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster SAGE: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=152&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (state) (pg_activity_max_tx_duration{ins=\\\"$ins\\\", state!~\\\"(idle.*|disabled)\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ state }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"SAGE\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 52\n            },\n            \"id\": 132,\n            \"panels\": [],\n            \"title\": \"Session\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Ratio of database session / max allowed sesion per database. the limit is min of max_connections and database's connection limit.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"axisSoftMin\": 0,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"area\"\n                        }\n                    },\n                    \"decimals\": 1,\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"green\",\n                                \"value\": 0.1\n                            },\n                            {\n                                \"color\": \"yellow\",\n                                \"value\": 0.3\n                            },\n                            {\n                                \"color\": \"orange\",\n                                \"value\": 0.5\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 0.7\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 0.9\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 53\n            },\n            \"id\": 90,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=90&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:conn_usage{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Connection Usage\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Idle in Transaction backend number of all databases in this instance.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"axisSoftMax\": 2,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 71,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"area\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 1\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 53\n            },\n            \"id\": 159,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=159&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_activity_count{ins=\\\"$ins\\\", state=~\\\"idle in.*\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Idle in Transaction Backends\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Number of database backend process / session by database.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 59\n            },\n            \"id\": 96,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Backends: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=96&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_activity_count{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Backends\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Newly established session on each database.\\nIncrease number of last 1 minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 71,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"super-light-green\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 59\n            },\n            \"id\": 153,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=153&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (increase(pg_db_sessions{ins=\\\"$ins\\\"}[1m]))\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"New Sessions (increase1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Backend number group by state in this instance.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"idle\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#808080\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 65\n            },\n            \"id\": 149,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=149&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (state) (pg_activity_count{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ state }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Backends by State\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Backend number group by backend type in this instance.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"client backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"autovacuum launcher\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#b783af\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"background writer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"checkpointer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"super-light-orange\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"logical replication launcher\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"walwriter\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#cc4637d9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"archiver\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"TimescaleDB Background Worker Launcher\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#fcdb72\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"NULL\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#808080\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 65\n            },\n            \"id\": 150,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=150&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (type) (pg_backend_count{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ type }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Backends by Type\",\n            \"transformations\": [\n                {\n                    \"id\": \"renameByRegex\",\n                    \"options\": {\n                        \"regex\": \"(Value)\",\n                        \"renamePattern\": \"NULL\"\n                    }\n                }\n            ],\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Max connection duration group by session time.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"idle\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#808080\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 71\n            },\n            \"id\": 151,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=151&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (state) (pg_activity_max_conn_duration{ins=\\\"$ins\\\", state!=\\\"idle|disabled\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ state }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Max Conn Lifespan\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Backend number group by wait event type in this instance.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 71,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"client backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"autovacuum launcher\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#b783af\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"background writer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"checkpointer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"super-light-orange\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"logical replication launcher\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"walwriter\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"super-light-blue\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"idle\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"rgba(128, 128, 128, 0.5)\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"active\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"disabled\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#fcdb72\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"idle in transaction (aborted)\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#b783af\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"idle in transaction\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#cc4637d9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Client\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"NULL\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#808080\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 71\n            },\n            \"id\": 165,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=165&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (event) (pg_wait_count{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ event }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Backends by Wait Event\",\n            \"transformations\": [\n                {\n                    \"id\": \"renameByRegex\",\n                    \"options\": {\n                        \"regex\": \"(Value)\",\n                        \"renamePattern\": \"NULL\"\n                    }\n                }\n            ],\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Time spent executing SQL statements in this database\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 9,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"area\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"orange\",\n                                \"value\": 0.5\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 0.7\n                            },\n                            {\n                                \"color\": \"purple\",\n                                \"value\": 0.9\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 77\n            },\n            \"id\": 183,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=183&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (rate(pg_db_active_time{ins=\\\"$ins\\\"}[1m]))\\n/ sum by (datname) (rate(pg_db_session_time{ins=\\\"$ins\\\"}[1m]))\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Active% (of Session Time)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Abandon: Number of database sessions to this database that were terminated because connection to the client was lost\\n\\n\\nFatal: Number of database sessions to this database that were terminated by fatal errors\\n\\n\\nKilled: Number of database sessions to this database that were terminated by operator intervention\\n\\n\\navailable on PG 14+\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 71,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"super-light-green\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 77\n            },\n            \"id\": 184,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=184&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (increase(pg_db_sessions_abandoned{ins=\\\"$ins\\\"}[1m]))\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"[Abandoned] : {{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (increase(pg_db_sessions_fatal{ins=\\\"$ins\\\"}[1m]))\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"[Fatal] : {{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (increase(pg_db_sessions_killed{ins=\\\"$ins\\\"}[1m]))\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"[Killed] : {{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"C\"\n                }\n            ],\n            \"title\": \"Sessions Failure in 1m\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 83\n            },\n            \"id\": 171,\n            \"panels\": [],\n            \"title\": \"Persist\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Rate of lsn in last minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"fixedColor\": \"#f5a673\",\n                        \"mode\": \"fixed\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 20,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"smooth\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 3,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGRDS Instance : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgrds-instance?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"Bps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 84\n            },\n            \"id\": 207,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=140&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": false\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:ins:lsn_rate1m{ins=\\\"$ins\\\"}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"LSN Progress (rate1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"XID Usage of each databases in this instance.\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"area\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Database : ${datname}\",\n                            \"url\": \"/d/pgsql-database?var-ins=${ins}&var-datname=${datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"match\": \"null+nan\",\n                                \"result\": {\n                                    \"color\": \"gray\",\n                                    \"index\": 0,\n                                    \"text\": \"\\u2205\"\n                                }\n                            },\n                            \"type\": \"special\"\n                        }\n                    ],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"yellow\",\n                                \"value\": 2\n                            },\n                            {\n                                \"color\": \"orange\",\n                                \"value\": 10\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 30\n                            },\n                            {\n                                \"color\": \"purple\",\n                                \"value\": 90\n                            },\n                            {\n                                \"color\": \"text\",\n                                \"value\": 100\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 84\n            },\n            \"id\": 208,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster Age: ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=161&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.3\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (datname) (pg:db:age{cls=\\\"$cls\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Age Usage\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 30,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Persist : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-persist?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 90\n            },\n            \"id\": 176,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=176&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_size_bytes{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Database Cluster Size\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 8,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Persist : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-persist?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 90\n            },\n            \"id\": 178,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=178&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_size_bytes{ins=\\\"$ins\\\", datname=~\\\"(log|wal)\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Database WAL/Log Size\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Scheduled\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Requested\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 96\n            },\n            \"id\": 160,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=160&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_bgwriter_checkpoints_timed{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Scheduled\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_bgwriter_checkpoints_req{ins=\\\"$ins\\\"} \",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Requested\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Checkpoint Scheduled / Requested\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 30,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Database for ${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-database?var-ins=${ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"ms\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Sync\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#cc4637d9\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Write\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 96\n            },\n            \"id\": 174,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=174&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"rate(pg_bgwriter_checkpoint_sync_time{ins=\\\"$ins\\\"}[1m])\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Sync\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"- rate(pg_bgwriter_checkpoint_write_time{ins=\\\"$ins\\\"}[1m])\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Write\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Checkpoint Time : Sync/Write\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Clean\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Checkpoint\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 102\n            },\n            \"id\": 172,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=172&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"rate(pg_bgwriter_buffers_clean{ins=\\\"$ins\\\"}[1m]) * 8192\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Clean\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"rate(pg_bgwriter_buffers_checkpoint{ins=\\\"$ins\\\"}[1m]) * 8192\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Checkpoint\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"rate(pg_bgwriter_buffers_backend{ins=\\\"$ins\\\"}[1m]) * 8192\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Backend\",\n                    \"refId\": \"C\"\n                }\n            ],\n            \"title\": \"BGWriter Buffer Flush\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Clean\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Checkpoint\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Alloc\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"super-light-red\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 102\n            },\n            \"id\": 173,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=173&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"list\",\n                    \"placement\": \"bottom\",\n                    \"showLegend\": false\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"rate(pg_bgwriter_buffers_alloc{ins=\\\"$ins\\\"}[1m]) * 8192\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Alloc\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"BGWriter Buffer Alloc\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database 4k blocks access\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Persist : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-persist?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Clean\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Checkpoint\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 108\n            },\n            \"id\": 179,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=179&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Name\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg:db:blks_access_1m{ins=\\\"$ins\\\"}) * 4096\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Blocks Access 1m\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database 4k blocks hit ratio in last 1 minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"axisSoftMax\": 1,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 2,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 2,\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Persist : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-persist?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 108\n            },\n            \"id\": 170,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=170&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": false\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:blks_hit_ratio1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Blocks Hit Ratio (1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database 4k blocks access\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Persist : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-persist?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Clean\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Backend\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Checkpoint\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 114\n            },\n            \"id\": 182,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=182&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Name\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg:db:blks_read_1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'}) * 4096\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Blocks Read (1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": true,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 5,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Persist : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-persist?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 114\n            },\n            \"id\": 181,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=181&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg:db:blk_read_time_seconds_rate1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\\u25b2 {{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"- sum by (datname) (pg:db:blk_write_time_seconds_rate1m{ins=\\\"$ins\\\", datname!~'rdsadmin|polardb_admin|template\\\\\\\\d'})\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\\u25bc {{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Blocks Read/Write Time Spent Rate1m\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 120\n            },\n            \"id\": 162,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=162&${__url_time_range}\\n\"\n                }\n            ],\n            \"panels\": [],\n            \"title\": \"Database\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database size on cluster primary\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 35,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 121\n            },\n            \"id\": 175,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=175&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg_size_bytes{ins=\\\"$ins\\\", datname!~'wal|log|template\\\\\\\\d'}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Database Size\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database Size Change on Cluster Primary in Last 10 minutes\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 35,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 1,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"decbytes\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 121\n            },\n            \"id\": 185,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=185&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"delta(pg_size_bytes{ins=\\\"$ins\\\", datname!~'wal|log|template\\\\\\\\d'}[10m])\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Database Size Delta 10m\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database Transaction Commit Rate in last 1 minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 20,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"smooth\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"custom.lineWidth\",\n                                \"value\": 0\n                            },\n                            {\n                                \"id\": \"custom.fillOpacity\",\n                                \"value\": 20\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 127\n            },\n            \"id\": 144,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=144&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0-beta2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg:db:xact_commit_rate1m{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'})\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 1,\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"TPS by Database (rate1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Active processs for each database in this cluster\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 60,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 127\n            },\n            \"id\": 148,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=148&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_activity_count{ins=\\\"$ins\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Session by Database\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Database 4k blocks hit ratio in last 1 minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"axisSoftMax\": 1,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 2,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 2,\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Database : ${__field.labels.ins}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-database?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 133\n            },\n            \"id\": 155,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=155&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": false\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:blks_hit_ratio1m{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Database Blocks Hit Ratio (1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"number of dangerous idle in transaction backend in different database amoung this cluster\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"axisSoftMax\": 2,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 71,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"area\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 1\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 133\n            },\n            \"id\": 167,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=167&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (pg_activity_count{ins=\\\"$ins\\\", state=~\\\"idle in.*\\\"})\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Idle in Transaction Backends\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Connection used ratio of min(\\n  max_connections @ instance level,\\n  connlimit @ database level\\n)\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"axisSoftMin\": 0,\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"area\"\n                        }\n                    },\n                    \"decimals\": 1,\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Database : ${__field.labels.ins}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-database?var-ins=${__field.labels.ins}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": 0.1\n                            },\n                            {\n                                \"color\": \"#fcdb72\",\n                                \"value\": 0.3\n                            },\n                            {\n                                \"color\": \"#f5a673\",\n                                \"value\": 0.5\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 0.7\n                            },\n                            {\n                                \"color\": \"#b783af\",\n                                \"value\": 0.9\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 139\n            },\n            \"id\": 168,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=168&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:db:conn_usage{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Connection Usage\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 71,\n                        \"gradientMode\": \"hue\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepBefore\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"auto\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Session : ${__field.labels.ins}\",\n                            \"url\": \"/d/pgsql-session?var-ins=${__field.labels.ins}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"super-light-green\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 139\n            },\n            \"id\": 166,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=166&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"increase(pg_db_sessions{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m])\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"New Sessions (incr1m)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Tuples fetched from databases among this cluster\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 3,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"cps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 145\n            },\n            \"id\": 163,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=163&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname) (rate(pg_db_tup_fetched{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m]))\",\n                    \"interval\": \"\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Row Fetched\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Tuples fetched, inserted, updated, delete among this cluster group by database\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 50,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\\n\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"cps\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 145\n            },\n            \"id\": 164,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=164&${__url_time_range}\\n\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"multi\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(rate(pg_db_tup_inserted{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m])) by (datname)\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"INSERT.{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(rate(pg_db_tup_updated{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m])) by (datname)\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"UPDATE.{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum(rate(pg_db_tup_deleted{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m])) by (datname)\",\n                    \"hide\": false,\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"DELETE.{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"D\"\n                }\n            ],\n            \"title\": \"Row Modified\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 151\n            },\n            \"id\": 124,\n            \"links\": [\n                {\n                    \"title\": \"PGRDS Cluster : ${cls}\",\n                    \"url\": \"/d/pgrds-cluster?var-cls=${cls}&viewPanel=124&${__url_time_range}\\n\"\n                }\n            ],\n            \"panels\": [],\n            \"title\": \"Table & Query\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Index Scan + Seq Scan on this table per second\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 2,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 7,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 152\n            },\n            \"id\": 125,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.1\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname,relname) (\\n    pg:table:scan_rate1m{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}\\n)\",\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"{{ datname }}.{{ relname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Table Scan (scan/s)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 2,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"short\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 7,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 152\n            },\n            \"id\": 126,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.1\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"sum by (datname,relname)  (\\n    rate(pg_table_tup_read{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m])\\n)\",\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"{{ datname }}.{{ relname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Tuple Read (rows/s)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"ops\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 11,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 159\n            },\n            \"id\": 187,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\",\n                        \"mean\",\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"bottom\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"pg:query:call_rate1m{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}\",\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"{{ datname }}.{{ query }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Query Call\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Top Query Time Spent among this cluster\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 40,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [\n                        {\n                            \"title\": \"PGSQL Databases :  ${cls}.${__field.labels.datname}\",\n                            \"url\": \"/d/pgsql-databases?var-cls=${cls}&var-datname=${__field.labels.datname}&${__url_time_range}\"\n                        }\n                    ],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 11,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 159\n            },\n            \"id\": 111,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\",\n                        \"mean\",\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"bottom\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"8.0.0\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"rate(pg_query_exec_time{ins=\\\"$ins\\\", datname!~'template\\\\\\\\d'}[1m])\",\n                    \"interval\": \"\",\n                    \"intervalFactor\": 2,\n                    \"legendFormat\": \"{{ datname }}.{{ query }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Query Time \",\n            \"type\": \"timeseries\"\n        }\n    ],\n    \"refresh\": \"\",\n    \"revision\": 1,\n    \"schemaVersion\": 39,\n    \"tags\": [\n        \"Pigsty\",\n        \"PGSQL\",\n        \"Instance\",\n        \"PGRDS\"\n    ],\n    \"templating\": {\n        \"list\": [\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up, ins)\",\n                \"description\": \"Unique instance identifier (e.g pg-meta-1)\",\n                \"hide\": 0,\n                \"includeAll\": false,\n                \"label\": \"Instance\",\n                \"multi\": false,\n                \"name\": \"ins\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up, ins)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"skipUrlSync\": false,\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up{ins=\\\"$ins\\\"} , ip)\",\n                \"description\": \"IP address of this postgres instance\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"IP\",\n                \"multi\": false,\n                \"name\": \"ip\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up{ins=\\\"$ins\\\"} , ip)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"skipUrlSync\": false,\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up{ins=\\\"$ins\\\"},  ins)\",\n                \"description\": \"Sequence number of this instance, which is an unique integer among a postgres cluster\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Sequence\",\n                \"multi\": false,\n                \"name\": \"seq\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up{ins=\\\"$ins\\\"},  ins)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"/^[a-zA-Z0-9-_]+-(\\\\d+)$/\",\n                \"skipUrlSync\": false,\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up{ins=\\\"$ins\\\"}, cls)\",\n                \"description\": \"Cluster identifier for this postgres instance, cls should be unique among entire environment. such as pg-meta, pg-test\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Cluster\",\n                \"multi\": false,\n                \"name\": \"cls\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up{ins=\\\"$ins\\\"}, cls)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"skipUrlSync\": false,\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(node_uname_info{ip=\\\"$ip\\\"},nodename)\",\n                \"description\": \"Node name of current postgres instance\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Node\",\n                \"multi\": false,\n                \"name\": \"node\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(node_uname_info{ip=\\\"$ip\\\"},nodename)\",\n                    \"refId\": \"PrometheusVariableQueryEditor-VariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"skipUrlSync\": false,\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_db_age{ins=\\\"$ins\\\", datname!~\\\"template0|template1|postgres|rdsadmin|polardb_admin\\\"},datname)\",\n                \"description\": \"Non-trivial database in this instance\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Database\",\n                \"multi\": false,\n                \"name\": \"datname\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_db_age{ins=\\\"$ins\\\", datname!~\\\"template0|template1|postgres|rdsadmin|polardb_admin\\\"},datname)\",\n                    \"refId\": \"PrometheusVariableQueryEditor-VariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"skipUrlSync\": false,\n                \"sort\": 1,\n                \"type\": \"query\"\n            }\n        ]\n    },\n    \"time\": {\n        \"from\": \"now-1h\",\n        \"to\": \"now\"\n    },\n    \"timepicker\": {},\n    \"timezone\": \"\",\n    \"title\": \"PGRDS Instance\",\n    \"uid\": \"pgrds-instance\",\n    \"version\": 1,\n    \"weekStart\": \"\"\n}"
  },
  {
    "path": "monitor/pgsql-exporter.json",
    "content": "{\n    \"annotations\": {\n        \"list\": [\n            {\n                \"builtIn\": 1,\n                \"datasource\": {\n                    \"type\": \"datasource\",\n                    \"uid\": \"grafana\"\n                },\n                \"enable\": true,\n                \"hide\": true,\n                \"iconColor\": \"rgba(0, 211, 255, 1)\",\n                \"name\": \"Annotations & Alerts\",\n                \"target\": {\n                    \"limit\": 100,\n                    \"matchAny\": false,\n                    \"tags\": [],\n                    \"type\": \"dashboard\"\n                },\n                \"type\": \"dashboard\"\n            }\n        ]\n    },\n    \"author\": \"Ruohang Feng (rh@vonng.com)\",\n    \"description\": \"PostgreSQL Instance Dashboard\",\n    \"editable\": true,\n    \"fiscalYearStartMonth\": 0,\n    \"graphTooltip\": 0,\n    \"id\": null,\n    \"license\": \"AGPLv3 @ https://pigsty.io/docs/about/license\",\n    \"links\": [\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Overview\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Overview\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        },\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Cluster\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Cluster\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        },\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Instance\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Instance\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        },\n        {\n            \"asDropdown\": true,\n            \"icon\": \"external link\",\n            \"includeVars\": true,\n            \"keepTime\": true,\n            \"tags\": [\n                \"Pigsty\",\n                \"PGSQL\",\n                \"Database\"\n            ],\n            \"targetBlank\": false,\n            \"title\": \"Database\",\n            \"tooltip\": \"\",\n            \"type\": \"dashboards\",\n            \"url\": \"\"\n        }\n    ],\n    \"panels\": [\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 0\n            },\n            \"id\": 137,\n            \"panels\": [],\n            \"title\": \"Overview\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"mappings\": [],\n                    \"max\": 2.5,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#3e668f\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Cluster\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${cls}\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Cluster\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Cluster : ${cls}\",\n                                        \"url\": \"/d/pgsql-cluster?var-cls=${cls}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${ins}\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Instance\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGCAT Instance : ${ins}\",\n                                        \"url\": \"/d/pgcat-instance?var-dsn=${ins}.${datname}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"IP\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Node IP\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${ip}\"\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"Node Instance : ${ip}\",\n                                        \"url\": \"/d/node-instance?var-id=${ip}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Name\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"displayName\",\n                                \"value\": \"${node}\"\n                            },\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"1\": {\n                                                \"index\": 0,\n                                                \"text\": \"Hostname\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"Node Instance : ${node}\",\n                                        \"url\": \"/d/node-instance?var-id=${node}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 6,\n                \"x\": 0,\n                \"y\": 1\n            },\n            \"id\": 110,\n            \"options\": {\n                \"colorMode\": \"background\",\n                \"graphMode\": \"area\",\n                \"justifyMode\": \"auto\",\n                \"orientation\": \"horizontal\",\n                \"percentChangeColorMode\": \"standard\",\n                \"reduceOptions\": {\n                    \"calcs\": [\n                        \"lastNotNull\"\n                    ],\n                    \"fields\": \"\",\n                    \"values\": false\n                },\n                \"showPercentChange\": false,\n                \"text\": {\n                    \"titleSize\": 20,\n                    \"valueSize\": 16\n                },\n                \"textMode\": \"value_and_name\",\n                \"wideLayout\": true\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"1\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Instance\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"1\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Cluster\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"1\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"IP\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"1\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"Name\",\n                    \"queryType\": \"measurements\",\n                    \"refId\": \"D\"\n                }\n            ],\n            \"title\": \"\",\n            \"type\": \"stat\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Exporter Aliveness Status in ${cls}\\n\\nInstance: Goto PGSQL Instance\\n\\nIP: Goto PGSQL Node\\n\\nStatus: Goto PGSQL Service\\n\\nLoad: max(cpu,postgres,pgbouncer)\\n\\nSpace: Disk space usage max(all device)\\n\\nProxy: session number, Goto Haproxy Admin Page\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"custom\": {\n                        \"align\": \"center\",\n                        \"cellOptions\": {\n                            \"type\": \"auto\"\n                        },\n                        \"inspect\": false\n                    },\n                    \"mappings\": [],\n                    \"max\": 1.2,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#e3e3e3e0\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byRegexp\",\n                            \"options\": \"/postgres|pgbouncer|pgbackrest/\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#cc4637d9\",\n                                                \"index\": 0,\n                                                \"text\": \"DOWN\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"UP\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-background\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 100\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byRegexp\",\n                            \"options\": \"/.*up/\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 100\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Exporter : ${__data.fields.Instance}\",\n                                        \"url\": \"/d/pgsql-exporter?var-ins=${__data.fields.Instance}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 10,\n                \"x\": 6,\n                \"y\": 1\n            },\n            \"id\": 144,\n            \"links\": [\n                {\n                    \"title\": \"PGSQL Instance : ${primary}\",\n                    \"url\": \"/d/pgsql-instance?var-ins=${primary}&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"cellHeight\": \"sm\",\n                \"footer\": {\n                    \"countRows\": false,\n                    \"fields\": \"\",\n                    \"reducer\": [\n                        \"sum\"\n                    ],\n                    \"show\": false\n                },\n                \"showHeader\": true,\n                \"sortBy\": [\n                    {\n                        \"desc\": false,\n                        \"displayName\": \"pg uptime\"\n                    }\n                ]\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg_exporter_agent_up{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pgbouncer_exporter_agent_up{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"__auto\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pgbackrest_exporter_agent_up{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg_exporter_uptime{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"F\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pgbouncer_exporter_uptime{cls=\\\"$cls\\\"})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"G\"\n                }\n            ],\n            \"title\": \"Export Status\",\n            \"transformations\": [\n                {\n                    \"id\": \"seriesToColumns\",\n                    \"options\": {\n                        \"byField\": \"ins\",\n                        \"mode\": \"outer\"\n                    }\n                },\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time\": true,\n                            \"Time 1\": true,\n                            \"Time 10\": true,\n                            \"Time 2\": true,\n                            \"Time 3\": true,\n                            \"Time 4\": true,\n                            \"Time 6\": true,\n                            \"Time 8\": true,\n                            \"Time 9\": true,\n                            \"Value #A\": false,\n                            \"Value #B\": false,\n                            \"Value #H\": false,\n                            \"__name__\": true,\n                            \"__name__ 1\": true,\n                            \"__name__ 2\": true,\n                            \"__name__ 3\": true,\n                            \"__name__ 5\": true,\n                            \"__name__ 7\": true,\n                            \"cls\": true,\n                            \"cls 1\": true,\n                            \"cls 2\": true,\n                            \"cls 3\": true,\n                            \"cls 4\": true,\n                            \"cls 5\": true,\n                            \"cls 6\": true,\n                            \"cls 7\": true,\n                            \"instance\": true,\n                            \"instance 1\": true,\n                            \"instance 2\": false,\n                            \"instance 3\": true,\n                            \"instance 4\": true,\n                            \"instance 5\": true,\n                            \"instance 6\": true,\n                            \"ip 1\": true,\n                            \"ip 2\": true,\n                            \"ip 3\": true,\n                            \"ip 4\": true,\n                            \"ip 5\": true,\n                            \"ip 6\": true,\n                            \"ip 7\": true,\n                            \"job\": true,\n                            \"job 1\": true,\n                            \"job 2\": true,\n                            \"job 3\": true,\n                            \"job 4\": true,\n                            \"job 5\": true,\n                            \"job 6\": true,\n                            \"job 7\": true\n                        },\n                        \"includeByName\": {},\n                        \"indexByName\": {\n                            \"Time 1\": 5,\n                            \"Time 2\": 6,\n                            \"Time 3\": 7,\n                            \"Time 4\": 8,\n                            \"Value #A\": 1,\n                            \"Value #B\": 2,\n                            \"Value #C\": 3,\n                            \"Value #D\": 4,\n                            \"ins\": 0\n                        },\n                        \"renameByName\": {\n                            \"Time 4\": \"\",\n                            \"Value #A\": \"postgres\",\n                            \"Value #B\": \"pgbouncer\",\n                            \"Value #C\": \"pgbackrest\",\n                            \"Value #D\": \"pgb uptime\",\n                            \"Value #E\": \"DB Conn\",\n                            \"Value #F\": \"pg uptime\",\n                            \"Value #G\": \"pgb uptime\",\n                            \"Value #H\": \"LB\",\n                            \"Value #I\": \"QPS\",\n                            \"Value #J\": \"LB Clients\",\n                            \"Value #K\": \"Lag\",\n                            \"cls 1\": \"\",\n                            \"cls 2\": \"\",\n                            \"ins\": \"Instance\",\n                            \"instance\": \"\",\n                            \"instance 2\": \"\",\n                            \"ip\": \"IP\",\n                            \"ip 1\": \"IP\"\n                        }\n                    }\n                }\n            ],\n            \"type\": \"table\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 12,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 2,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"0\": {\n                                    \"index\": 0,\n                                    \"text\": \"Dead\"\n                                },\n                                \"1\": {\n                                    \"index\": 1,\n                                    \"text\": \"UP\"\n                                }\n                            },\n                            \"type\": \"value\"\n                        }\n                    ],\n                    \"max\": 1.2,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 8,\n                \"x\": 16,\n                \"y\": 1\n            },\n            \"id\": 145,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"min\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Min\",\n                    \"sortDesc\": false\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_agent_up{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"pg_exporter\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_agent_up{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"pgbouncer_exporter\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_up{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"postgres\",\n                    \"range\": true,\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_up{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"D\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"patroni_up{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"patroni\",\n                    \"range\": true,\n                    \"refId\": \"E\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbackrest_exporter_agent_up{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbackrest_exporter\",\n                    \"range\": true,\n                    \"refId\": \"F\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"up{ins=\\\"$ins\\\", job=~\\\"pgsql|pgrds\\\"}\",\n                    \"hide\": true,\n                    \"legendFormat\": \"{{ instance }}\",\n                    \"range\": true,\n                    \"refId\": \"Z\"\n                }\n            ],\n            \"title\": \"Aliveness\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 7\n            },\n            \"id\": 142,\n            \"panels\": [],\n            \"title\": \"Global Status\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"0\": {\n                                    \"index\": 0,\n                                    \"text\": \"Dead\"\n                                },\n                                \"1\": {\n                                    \"index\": 1,\n                                    \"text\": \"UP\"\n                                }\n                            },\n                            \"type\": \"value\"\n                        }\n                    ],\n                    \"max\": 1.2,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 8\n            },\n            \"id\": 139,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"min\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Min\",\n                    \"sortDesc\": false\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_agent_up{}\",\n                    \"legendFormat\": \"{{ instance }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_agent_up{}\",\n                    \"legendFormat\": \"{{ instance }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Aliveness\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"All instances among pgsql cluster ${cls}\\n\\nInstance: Goto PGSQL Instance\\n\\nIP: Goto PGSQL Node\\n\\nStatus: Goto PGSQL Service\\n\\nLoad: max(cpu,postgres,pgbouncer)\\n\\nSpace: Disk space usage max(all device)\\n\\nProxy: session number, Goto Haproxy Admin Page\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"thresholds\"\n                    },\n                    \"custom\": {\n                        \"align\": \"center\",\n                        \"cellOptions\": {\n                            \"type\": \"auto\"\n                        },\n                        \"inspect\": false\n                    },\n                    \"mappings\": [],\n                    \"max\": 1.2,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#e3e3e3e0\",\n                                \"value\": null\n                            }\n                        ]\n                    }\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byRegexp\",\n                            \"options\": \"/pg_exporter|pgb_exporter/\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"mappings\",\n                                \"value\": [\n                                    {\n                                        \"options\": {\n                                            \"0\": {\n                                                \"color\": \"#cc4637d9\",\n                                                \"index\": 0,\n                                                \"text\": \"DOWN\"\n                                            },\n                                            \"1\": {\n                                                \"color\": \"#346f36cc\",\n                                                \"index\": 1,\n                                                \"text\": \"UP\"\n                                            }\n                                        },\n                                        \"type\": \"value\"\n                                    }\n                                ]\n                            },\n                            {\n                                \"id\": \"custom.cellOptions\",\n                                \"value\": {\n                                    \"type\": \"color-background\"\n                                }\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 110\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byRegexp\",\n                            \"options\": \"/.*up/\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"s\"\n                            },\n                            {\n                                \"id\": \"custom.width\",\n                                \"value\": 100\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Instance\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"links\",\n                                \"value\": [\n                                    {\n                                        \"title\": \"PGSQL Exporter : ${__data.fields.Instance}\",\n                                        \"url\": \"/d/pgsql-exporter?var-ins=${__data.fields.Instance}&${__url_time_range}\"\n                                    }\n                                ]\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 12,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 8\n            },\n            \"id\": 141,\n            \"links\": [\n                {\n                    \"title\": \"PGSQL Instance : ${primary}\",\n                    \"url\": \"/d/pgsql-instance?var-ins=${primary}&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"cellHeight\": \"sm\",\n                \"footer\": {\n                    \"countRows\": false,\n                    \"fields\": \"\",\n                    \"reducer\": [\n                        \"sum\"\n                    ],\n                    \"show\": false\n                },\n                \"showHeader\": true,\n                \"sortBy\": [\n                    {\n                        \"desc\": false,\n                        \"displayName\": \"pg uptime\"\n                    }\n                ]\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg_exporter_agent_up{})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pgbouncer_exporter_agent_up{})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pg_exporter_uptime{})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"C\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"exemplar\": false,\n                    \"expr\": \"max by (ins) (pgbouncer_exporter_uptime{})\",\n                    \"format\": \"table\",\n                    \"hide\": false,\n                    \"instant\": true,\n                    \"interval\": \"\",\n                    \"legendFormat\": \"\",\n                    \"refId\": \"D\"\n                }\n            ],\n            \"title\": \"\",\n            \"transformations\": [\n                {\n                    \"id\": \"seriesToColumns\",\n                    \"options\": {\n                        \"byField\": \"ins\",\n                        \"mode\": \"outer\"\n                    }\n                },\n                {\n                    \"id\": \"organize\",\n                    \"options\": {\n                        \"excludeByName\": {\n                            \"Time\": true,\n                            \"Time 1\": true,\n                            \"Time 10\": true,\n                            \"Time 2\": true,\n                            \"Time 3\": true,\n                            \"Time 4\": true,\n                            \"Time 6\": true,\n                            \"Time 8\": true,\n                            \"Time 9\": true,\n                            \"Value #A\": false,\n                            \"Value #B\": false,\n                            \"Value #H\": false,\n                            \"__name__\": true,\n                            \"__name__ 1\": true,\n                            \"__name__ 2\": true,\n                            \"__name__ 3\": true,\n                            \"__name__ 5\": true,\n                            \"__name__ 7\": true,\n                            \"cls\": true,\n                            \"cls 1\": true,\n                            \"cls 2\": true,\n                            \"cls 3\": true,\n                            \"cls 4\": true,\n                            \"cls 5\": true,\n                            \"cls 6\": true,\n                            \"cls 7\": true,\n                            \"instance\": true,\n                            \"instance 1\": true,\n                            \"instance 2\": false,\n                            \"instance 3\": true,\n                            \"instance 4\": true,\n                            \"instance 5\": true,\n                            \"instance 6\": true,\n                            \"ip 1\": true,\n                            \"ip 2\": true,\n                            \"ip 3\": true,\n                            \"ip 4\": true,\n                            \"ip 5\": true,\n                            \"ip 6\": true,\n                            \"ip 7\": true,\n                            \"job\": true,\n                            \"job 1\": true,\n                            \"job 2\": true,\n                            \"job 3\": true,\n                            \"job 4\": true,\n                            \"job 5\": true,\n                            \"job 6\": true,\n                            \"job 7\": true\n                        },\n                        \"indexByName\": {\n                            \"Time 1\": 5,\n                            \"Time 2\": 6,\n                            \"Time 3\": 7,\n                            \"Time 4\": 8,\n                            \"Value #A\": 1,\n                            \"Value #B\": 2,\n                            \"Value #C\": 3,\n                            \"Value #D\": 4,\n                            \"ins\": 0\n                        },\n                        \"renameByName\": {\n                            \"Time 4\": \"\",\n                            \"Value #A\": \"pg_exporter\",\n                            \"Value #B\": \"pgb_exporter\",\n                            \"Value #C\": \"pg uptime\",\n                            \"Value #D\": \"pgb uptime\",\n                            \"Value #E\": \"DB Conn\",\n                            \"Value #F\": \"RT\",\n                            \"Value #G\": \"LB Conn\",\n                            \"Value #H\": \"LB\",\n                            \"Value #I\": \"QPS\",\n                            \"Value #J\": \"LB Clients\",\n                            \"Value #K\": \"Lag\",\n                            \"cls 1\": \"\",\n                            \"cls 2\": \"\",\n                            \"ins\": \"Instance\",\n                            \"instance\": \"\",\n                            \"instance 2\": \"\",\n                            \"ip\": \"IP\",\n                            \"ip 1\": \"IP\"\n                        }\n                    }\n                }\n            ],\n            \"type\": \"table\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"points\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 0,\n                        \"pointSize\": 2,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 14\n            },\n            \"id\": 138,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_scrape_duration{}\",\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Scrape Duration\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 20\n            },\n            \"id\": 146,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"last\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Last\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_uptime{}\",\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_uptime{}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Global Uptime\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Error Increase in last 1 minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 12,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 2,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 20\n            },\n            \"id\": 147,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Name\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pg_exporter_scrape_error_count{}[1m])\",\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pgbouncer_exporter_scrape_error_count{}[1m])\",\n                    \"legendFormat\": \"{{ ins }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Global Error Rate\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 26\n            },\n            \"id\": 130,\n            \"panels\": [],\n            \"title\": \"Metrics\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 10,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 80\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 27\n            },\n            \"id\": 124,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [],\n                    \"displayMode\": \"list\",\n                    \"placement\": \"bottom\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_uptime{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"postgres\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_uptime{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Up Time\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 12,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 2,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [],\n                    \"mappings\": [\n                        {\n                            \"options\": {\n                                \"0\": {\n                                    \"index\": 0,\n                                    \"text\": \"Dead\"\n                                },\n                                \"1\": {\n                                    \"index\": 1,\n                                    \"text\": \"UP\"\n                                }\n                            },\n                            \"type\": \"value\"\n                        }\n                    ],\n                    \"max\": 1.2,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 27\n            },\n            \"id\": 128,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"min\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Min\",\n                    \"sortDesc\": false\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_agent_up{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"postgres\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_agent_up{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbackrest_exporter_agent_up{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbackrest\",\n                    \"range\": true,\n                    \"refId\": \"D\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"up{ins=\\\"$ins\\\", job=~\\\"pgsql|pgrds\\\"}\",\n                    \"hide\": true,\n                    \"legendFormat\": \"{{ instance }}\",\n                    \"range\": true,\n                    \"refId\": \"C\"\n                }\n            ],\n            \"title\": \"Exporter Aliveness\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 10,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 32\n            },\n            \"id\": 129,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_scrape_duration{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"postgres\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_scrape_duration{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Scrape Duration\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Error Increase in last 1 minute\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 12,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 2,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"postgres\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 32\n            },\n            \"id\": 136,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Name\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pg_exporter_scrape_error_count{ins=\\\"$ins\\\"}[1m])\",\n                    \"legendFormat\": \"postgres\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pgbouncer_exporter_scrape_error_count{ins=\\\"$ins\\\"}[1m])\",\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Errors Count Per Minute\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 10,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 37\n            },\n            \"id\": 125,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_server_scrape_duration{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_server_scrape_duration{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Scrape Duration (per Server)\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"Scrape Count\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 12,\n                        \"gradientMode\": \"opacity\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 2,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 1,\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"Error\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#E02F44\",\n                                    \"mode\": \"fixed\"\n                                }\n                            },\n                            {\n                                \"id\": \"unit\",\n                                \"value\": \"short\"\n                            },\n                            {\n                                \"id\": \"min\",\n                                \"value\": 0\n                            },\n                            {\n                                \"id\": \"max\",\n                                \"value\": 0.1\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 37\n            },\n            \"id\": 126,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pg_exporter_server_scrape_total_count{ins=\\\"$ins\\\"}[1m])\",\n                    \"legendFormat\": \"{{ datname }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pgbouncer_exporter_server_scrape_total_count{ins=\\\"$ins\\\"}[1m])\",\n                    \"legendFormat\": \"pgbouncer\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Scrape Count Per Minute\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 42\n            },\n            \"id\": 134,\n            \"panels\": [],\n            \"title\": \"Collectors\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 10,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"line+area\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"transparent\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 43\n            },\n            \"id\": 123,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Max\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"sum by (query) (increase(pg_exporter_query_scrape_error_count{ins=\\\"$ins\\\"}[1m]))\",\n                    \"legendFormat\": \"{{query}}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Query Errors\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 2,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 6,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 43\n            },\n            \"id\": 132,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"sum by (query) (pg_exporter_query_scrape_metric_count{ins=\\\"$ins\\\"})\",\n                    \"legendFormat\": \"{{query}}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"sum by (query) (pgbouncer_exporter_query_scrape_metric_count{ins=\\\"$ins\\\"})\",\n                    \"hide\": false,\n                    \"legendFormat\": \"{{query}}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Metrics Count\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 3,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 80\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 15,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 49\n            },\n            \"id\": 131,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\",\n                        \"lastNotNull\",\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true,\n                    \"sortBy\": \"Mean\",\n                    \"sortDesc\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pg_exporter_query_scrape_duration{ins=\\\"$ins\\\"}[1m]) / \\nincrease(pg_exporter_query_scrape_total_count{ins=\\\"$ins\\\"}[1m])\",\n                    \"legendFormat\": \"{{ datname }}.{{ query }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pgbouncer_exporter_query_scrape_duration{ins=\\\"$ins\\\"}[1m]) / \\nincrease(pgbouncer_exporter_query_scrape_total_count{ins=\\\"$ins\\\"}[1m])\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbouncer.{{ query }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Query Duration\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 0,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"max\": 1,\n                    \"min\": 0,\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            },\n                            {\n                                \"color\": \"red\",\n                                \"value\": 80\n                            }\n                        ]\n                    },\n                    \"unit\": \"percentunit\"\n                },\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 9,\n                \"w\": 12,\n                \"x\": 0,\n                \"y\": 64\n            },\n            \"id\": 133,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\",\n                        \"lastNotNull\",\n                        \"max\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pg_exporter_query_scrape_hit_count{ins=\\\"$ins\\\"}[5m]) / \\nincrease(pg_exporter_query_scrape_total_count{ins=\\\"$ins\\\"}[5m])\",\n                    \"legendFormat\": \"{{ datname }}.{{query}}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"increase(pgbouncer_exporter_query_scrape_hit_count{ins=\\\"$ins\\\"}[5m]) / \\nincrease(pgbouncer_exporter_query_scrape_total_count{ins=\\\"$ins\\\"}[5m])\",\n                    \"hide\": false,\n                    \"legendFormat\": \"{{ datname }}.{{query}}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Query Cache Hit Rate\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"prometheus\",\n                \"uid\": \"ds-prometheus\"\n            },\n            \"description\": \"\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"mode\": \"palette-classic\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"line\",\n                        \"fillOpacity\": 1,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"stepAfter\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": false,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"none\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"links\": [],\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"green\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"s\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbouncer\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 9,\n                \"w\": 12,\n                \"x\": 12,\n                \"y\": 64\n            },\n            \"id\": 135,\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"mean\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": true\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"multi\",\n                    \"sort\": \"desc\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pg_exporter_query_cache_ttl{ins=\\\"$ins\\\"}\",\n                    \"legendFormat\": \"{{ datname }}.{{ query }}\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                },\n                {\n                    \"datasource\": {\n                        \"type\": \"prometheus\",\n                        \"uid\": \"ds-prometheus\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"pgbouncer_exporter_query_cache_ttl{ins=\\\"$ins\\\"}\",\n                    \"hide\": false,\n                    \"legendFormat\": \"pgbouncer. {{ query }}\",\n                    \"range\": true,\n                    \"refId\": \"B\"\n                }\n            ],\n            \"title\": \"Cache TTL\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"collapsed\": false,\n            \"gridPos\": {\n                \"h\": 1,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 73\n            },\n            \"id\": 98,\n            \"panels\": [],\n            \"title\": \"PG Exporter Logs: ${ins}\",\n            \"type\": \"row\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"loki\",\n                \"uid\": \"ds-loki\"\n            },\n            \"description\": \"pg_exporter logs count\",\n            \"fieldConfig\": {\n                \"defaults\": {\n                    \"color\": {\n                        \"fixedColor\": \"#346f36cc\",\n                        \"mode\": \"fixed\"\n                    },\n                    \"custom\": {\n                        \"axisBorderShow\": false,\n                        \"axisCenteredZero\": false,\n                        \"axisColorMode\": \"text\",\n                        \"axisLabel\": \"\",\n                        \"axisPlacement\": \"auto\",\n                        \"barAlignment\": 0,\n                        \"barWidthFactor\": 0.6,\n                        \"drawStyle\": \"bars\",\n                        \"fillOpacity\": 100,\n                        \"gradientMode\": \"none\",\n                        \"hideFrom\": {\n                            \"graph\": false,\n                            \"legend\": false,\n                            \"tooltip\": false,\n                            \"viz\": false\n                        },\n                        \"insertNulls\": false,\n                        \"lineInterpolation\": \"linear\",\n                        \"lineWidth\": 1,\n                        \"pointSize\": 5,\n                        \"scaleDistribution\": {\n                            \"type\": \"linear\"\n                        },\n                        \"showPoints\": \"never\",\n                        \"spanNulls\": true,\n                        \"stacking\": {\n                            \"group\": \"A\",\n                            \"mode\": \"normal\"\n                        },\n                        \"thresholdsStyle\": {\n                            \"mode\": \"off\"\n                        }\n                    },\n                    \"decimals\": 0,\n                    \"mappings\": [],\n                    \"thresholds\": {\n                        \"mode\": \"absolute\",\n                        \"steps\": [\n                            {\n                                \"color\": \"#346f36cc\",\n                                \"value\": null\n                            }\n                        ]\n                    },\n                    \"unit\": \"none\"\n                },\n                \"overrides\": [\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"A\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#346f36cc\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"B\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#3e668f\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byFrameRefID\",\n                            \"options\": \"C\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"#f5a673\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    },\n                    {\n                        \"matcher\": {\n                            \"id\": \"byName\",\n                            \"options\": \"pgbackrest\"\n                        },\n                        \"properties\": [\n                            {\n                                \"id\": \"color\",\n                                \"value\": {\n                                    \"fixedColor\": \"light-red\",\n                                    \"mode\": \"fixed\"\n                                }\n                            }\n                        ]\n                    }\n                ]\n            },\n            \"gridPos\": {\n                \"h\": 5,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 74\n            },\n            \"id\": 100,\n            \"interval\": \"1s\",\n            \"links\": [\n                {\n                    \"title\": \"PG Exporter Logs for ${ins}\",\n                    \"url\": \"/d/logs-instance?var-ins=$ins&var-src=syslog&var-search=exporter&${__url_time_range}\"\n                }\n            ],\n            \"options\": {\n                \"legend\": {\n                    \"calcs\": [\n                        \"sum\"\n                    ],\n                    \"displayMode\": \"table\",\n                    \"placement\": \"right\",\n                    \"showLegend\": false\n                },\n                \"tooltip\": {\n                    \"hideZeros\": false,\n                    \"mode\": \"single\",\n                    \"sort\": \"none\"\n                }\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"loki\",\n                        \"uid\": \"ds-loki\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"count_over_time(({ip=\\\"$ip\\\", src=\\\"syslog\\\"} |~ \\\"pg_exporter\\\")[$__interval])\",\n                    \"legendFormat\": \"\",\n                    \"queryType\": \"range\",\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Logs per $__interval\",\n            \"type\": \"timeseries\"\n        },\n        {\n            \"datasource\": {\n                \"type\": \"loki\",\n                \"uid\": \"ds-loki\"\n            },\n            \"description\": \"Recent logs for pgbouncer & patroni & postgres\",\n            \"fieldConfig\": {\n                \"defaults\": {},\n                \"overrides\": []\n            },\n            \"gridPos\": {\n                \"h\": 12,\n                \"w\": 24,\n                \"x\": 0,\n                \"y\": 79\n            },\n            \"id\": 102,\n            \"options\": {\n                \"dedupStrategy\": \"none\",\n                \"enableInfiniteScrolling\": false,\n                \"enableLogDetails\": true,\n                \"prettifyLogMessage\": false,\n                \"showCommonLabels\": false,\n                \"showLabels\": false,\n                \"showTime\": true,\n                \"sortOrder\": \"Descending\",\n                \"wrapLogMessage\": false\n            },\n            \"pluginVersion\": \"11.5.2\",\n            \"targets\": [\n                {\n                    \"datasource\": {\n                        \"type\": \"loki\",\n                        \"uid\": \"ds-loki\"\n                    },\n                    \"editorMode\": \"code\",\n                    \"expr\": \"{ip=\\\"$ip\\\"} |~ \\\"pg_exporter\\\"\",\n                    \"instant\": false,\n                    \"queryType\": \"range\",\n                    \"range\": true,\n                    \"refId\": \"A\"\n                }\n            ],\n            \"title\": \"Recent Logs\",\n            \"type\": \"logs\"\n        }\n    ],\n    \"preload\": false,\n    \"refresh\": \"\",\n    \"schemaVersion\": 40,\n    \"tags\": [\n        \"Pigsty\",\n        \"PGSQL\",\n        \"Instance\"\n    ],\n    \"templating\": {\n        \"list\": [\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up, ins)\",\n                \"description\": \"Unique instance identifier (e.g pg-meta-1)\",\n                \"includeAll\": false,\n                \"label\": \"Instance\",\n                \"name\": \"ins\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up, ins)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up{ins=\\\"$ins\\\"} , ip)\",\n                \"description\": \"IP address of this postgres instance\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"IP\",\n                \"name\": \"ip\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up{ins=\\\"$ins\\\"} , ip)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up{ins=\\\"$ins\\\"},  ins)\",\n                \"description\": \"Sequence number of this instance, which is an unique integer among a postgres cluster\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Sequence\",\n                \"name\": \"seq\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up{ins=\\\"$ins\\\"},  ins)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"/^[a-zA-Z0-9-_]+-(\\\\d+)$/\",\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_up{ins=\\\"$ins\\\"}, cls)\",\n                \"description\": \"Cluster identifier for this postgres instance, cls should be unique among entire environment. such as pg-meta, pg-test\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Cluster\",\n                \"name\": \"cls\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_up{ins=\\\"$ins\\\"}, cls)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(node_uname_info{ip=\\\"$ip\\\"},nodename)\",\n                \"description\": \"Node name of current postgres instance\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Node\",\n                \"name\": \"node\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(node_uname_info{ip=\\\"$ip\\\"},nodename)\",\n                    \"refId\": \"PrometheusVariableQueryEditor-VariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"sort\": 1,\n                \"type\": \"query\"\n            },\n            {\n                \"current\": {},\n                \"datasource\": {\n                    \"type\": \"prometheus\",\n                    \"uid\": \"ds-prometheus\"\n                },\n                \"definition\": \"label_values(pg_db_age{ins=\\\"$ins\\\",datname!~'postgres|template0|template1'}, datname)\",\n                \"description\": \"Non-trivial database in this instance\",\n                \"hide\": 2,\n                \"includeAll\": false,\n                \"label\": \"Database\",\n                \"name\": \"datname\",\n                \"options\": [],\n                \"query\": {\n                    \"query\": \"label_values(pg_db_age{ins=\\\"$ins\\\",datname!~'postgres|template0|template1'}, datname)\",\n                    \"refId\": \"StandardVariableQuery\"\n                },\n                \"refresh\": 1,\n                \"regex\": \"\",\n                \"sort\": 1,\n                \"type\": \"query\"\n            }\n        ]\n    },\n    \"time\": {\n        \"from\": \"now-1h\",\n        \"to\": \"now\"\n    },\n    \"timepicker\": {},\n    \"timezone\": \"Asia/Shanghai\",\n    \"title\": \"PGSQL Exporter\",\n    \"uid\": \"pgsql-exporter\",\n    \"version\": 1,\n    \"weekStart\": \"\"\n}"
  },
  {
    "path": "package/nfpm-amd64-deb.yaml",
    "content": "name: \"pg-exporter\"\narch: \"amd64\"\nplatform: \"linux\"\nversion: \"v1.2.2\"\nrelease: \"1\"\nversion_schema: semver\nmaintainer: Ruohang Feng <rh@vonng.com>\ndescription: |\n  Prometheus exporter for PostgreSQL / Pgbouncer server metrics.\n  Supported version: Postgres9.x - 18+ & Pgbouncer 1.8 - 1.25+\n  Part of Project Pigsty -- Battery Included PostgreSQL Distribution\n  with ultimate observability support: https://pigsty.io/docs/pg_exporter\n\nvendor: \"PGSTY\"\nhomepage: \"https://pigsty.io/docs/pg_exporter\"\nlicense: \"Apache-2.0 License\"\n\nrpm:\n  compression: gzip\n  prefixes:\n    - /usr/bin\n\ncontents:\n  - src: pg_exporter\n    dst: /usr/bin/pg_exporter\n    file_info:\n      mode: 0755\n\n  - src: pg_exporter.yml\n    dst: /etc/pg_exporter.yml\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.default\n    dst: /etc/default/pg_exporter\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.service\n    dst: /lib/systemd/system/pg_exporter.service\n    type: config\n\n  - src: LICENSE\n    dst: /usr/share/doc/pg_exporter/LICENSE\n    file_info:\n      mode: 0644\n\nscripts:\n  preinstall: package/preinstall.sh\n"
  },
  {
    "path": "package/nfpm-amd64-rpm.yaml",
    "content": "name: \"pg_exporter\"\narch: \"amd64\"\nplatform: \"linux\"\nversion: \"v1.2.2\"\nrelease: \"1\"\nversion_schema: semver\nmaintainer: Ruohang Feng <rh@vonng.com>\ndescription: |\n  Prometheus exporter for PostgreSQL / Pgbouncer server metrics.\n  Supported version: Postgres9.x - 18+ & Pgbouncer 1.8 - 1.25+\n  Part of Project Pigsty -- Battery Included PostgreSQL Distribution\n  with ultimate observability support: https://pigsty.io/docs/pg_exporter\n\nvendor: \"PGSTY\"\nhomepage: \"https://pigsty.io/docs/pg_exporter\"\nlicense: \"Apache-2.0 License\"\n\nrpm:\n  compression: gzip\n  prefixes:\n    - /usr/bin\n\ncontents:\n  - src: pg_exporter\n    dst: /usr/bin/pg_exporter\n    file_info:\n      mode: 0755\n\n  - src: pg_exporter.yml\n    dst: /etc/pg_exporter.yml\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.default\n    dst: /etc/default/pg_exporter\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.service\n    dst: /usr/lib/systemd/system/pg_exporter.service\n    type: config\n\n  - src: LICENSE\n    dst: /usr/share/doc/pg_exporter/LICENSE\n    file_info:\n      mode: 0644\n\nscripts:\n  preinstall: package/preinstall.sh\n"
  },
  {
    "path": "package/nfpm-arm64-deb.yaml",
    "content": "name: \"pg-exporter\"\narch: \"arm64\"\nplatform: \"linux\"\nversion: \"v1.2.2\"\nrelease: \"1\"\nversion_schema: semver\nmaintainer: Ruohang Feng <rh@vonng.com>\ndescription: |\n  Prometheus exporter for PostgreSQL / Pgbouncer server metrics.\n  Supported version: Postgres9.x - 18+ & Pgbouncer 1.8 - 1.25+\n  Part of Project Pigsty -- Battery Included PostgreSQL Distribution\n  with ultimate observability support: https://pigsty.io/docs/pg_exporter\n\nvendor: \"PGSTY\"\nhomepage: \"https://pigsty.io/docs/pg_exporter\"\nlicense: \"Apache-2.0 License\"\n\nrpm:\n  compression: gzip\n  prefixes:\n    - /usr/bin\n\ncontents:\n  - src: pg_exporter\n    dst: /usr/bin/pg_exporter\n    file_info:\n      mode: 0755\n\n  - src: pg_exporter.yml\n    dst: /etc/pg_exporter.yml\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.default\n    dst: /etc/default/pg_exporter\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.service\n    dst: /lib/systemd/system/pg_exporter.service\n    type: config\n\n  - src: LICENSE\n    dst: /usr/share/doc/pg_exporter/LICENSE\n    file_info:\n      mode: 0644\n\nscripts:\n  preinstall: package/preinstall.sh\n"
  },
  {
    "path": "package/nfpm-arm64-rpm.yaml",
    "content": "name: \"pg_exporter\"\narch: \"arm64\"\nplatform: \"linux\"\nversion: \"v1.2.2\"\nrelease: \"1\"\nversion_schema: semver\nmaintainer: Ruohang Feng <rh@vonng.com>\ndescription: |\n  Prometheus exporter for PostgreSQL / Pgbouncer server metrics.\n  Supported version: Postgres9.x - 18+ & Pgbouncer 1.8 - 1.25+\n  Part of Project Pigsty -- Battery Included PostgreSQL Distribution\n  with ultimate observability support: https://pigsty.io/docs/pg_exporter\n\nvendor: \"PGSTY\"\nhomepage: \"https://pigsty.io/docs/pg_exporter\"\nlicense: \"Apache-2.0 License\"\n\nrpm:\n  compression: gzip\n  prefixes:\n    - /usr/bin\n\ncontents:\n  - src: pg_exporter\n    dst: /usr/bin/pg_exporter\n    file_info:\n      mode: 0755\n\n  - src: pg_exporter.yml\n    dst: /etc/pg_exporter.yml\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.default\n    dst: /etc/default/pg_exporter\n    type: config|noreplace\n    file_info:\n      mode: 0700\n      owner: prometheus\n      group: prometheus\n\n  - src: package/pg_exporter.service\n    dst: /usr/lib/systemd/system/pg_exporter.service\n    type: config\n\n  - src: LICENSE\n    dst: /usr/share/doc/pg_exporter/LICENSE\n    file_info:\n      mode: 0644\n\nscripts:\n  preinstall: package/preinstall.sh\n"
  },
  {
    "path": "package/pg_exporter.default",
    "content": "PG_EXPORTER_URL='postgres://:5432/?sslmode=disable'\nPG_EXPORTER_CONFIG=/etc/pg_exporter.yml\nPG_EXPORTER_LABEL=\"\"\nPG_EXPORTER_TAG=\"\"\nPG_EXPORTER_DISABLE_CACHE=false\nPG_EXPORTER_AUTO_DISCOVERY=true\nPG_EXPORTER_EXCLUDE_DATABASE=\"template0,template1,postgres\"\nPG_EXPORTER_INCLUDE_DATABASE=\"\"\nPG_EXPORTER_NAMESPACE=\"pg\"\nPG_EXPORTER_FAIL_FAST=false\nPG_EXPORTER_CONNECT_TIMEOUT=100\nPG_EXPORTER_TELEMETRY_PATH=\"/metrics\"\nPG_EXPORTER_OPTS='--log.level=info'"
  },
  {
    "path": "package/pg_exporter.service",
    "content": "[Unit]\nDescription=Prometheus exporter for PostgreSQL/Pgbouncer server metrics\nDocumentation=https://pigsty.io/docs/pg_exporter\nAfter=network.target\n\n[Service]\nEnvironmentFile=-/etc/default/pg_exporter\nUser=prometheus\nExecStart=/usr/bin/pg_exporter $PG_EXPORTER_OPTS\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target"
  },
  {
    "path": "package/preinstall.sh",
    "content": "#!/bin/bash\n\n# create a group & user named prometheus if not exists\ngetent group prometheus >/dev/null || groupadd -r prometheus ; /bin/true\ngetent passwd prometheus >/dev/null || useradd -r -g prometheus -s /sbin/nologin -c \"Prometheus services\" prometheus\nexit 0"
  },
  {
    "path": "pg_exporter.yml",
    "content": "#==============================================================#\n# Desc      :   pg_exporter metrics collector definition\n# Ver       :   PostgreSQL 10 ~ 18+ and pgbouncer 1.9~1.25+\n# Ctime     :   2019-12-09\n# Mtime     :   2026-03-21\n# Homepage  :   https://pigsty.io\n# Author    :   Ruohang Feng (rh@vonng.com)\n# License   :   Apache-2.0 @ https://github.com/pgsty/pg_exporter\n# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)\n#==============================================================#\n\n\n#==============================================================#\n# 1. Config File\n#==============================================================#\n# The configuration file for pg_exporter is a YAML file.\n# Default configurations are retrieved via following precedence:\n#     1. command line args:      --config=<config path>\n#     2. environment variables:  PG_EXPORTER_CONFIG=<config path>\n#     3. pg_exporter.yml        (Current directory)\n#     4. /etc/pg_exporter.yml   (config file)\n#     5. /etc/pg_exporter       (config dir)\n\n#==============================================================#\n# 2. Config Format\n#==============================================================#\n# pg_exporter config could be a single YAML file, or a directory containing a series of separated YAML files.\n# Each YAML config file consists of one or more metrics Collector definition, which are top-level objects.\n# If a directory is provided, all YAML in that directory will be merged in alphabetic order.\n# Collector definition examples are shown below.\n\n#==============================================================#\n# 3. Collector Example\n#==============================================================#\n#  # Here is an example of a metrics collector definition\n#  pg_primary_only:       # Collector branch name. Must be UNIQUE among the entire configuration\n#    name: pg             # Collector namespace, used as METRIC PREFIX, set to branch name by default, can be override\n#                         # the same namespace may contain multiple collector branches. It`s the user`s responsibility\n#                         # to make sure that AT MOST ONE collector is picked for each namespace.\n#\n#    desc: PostgreSQL basic information (on primary)                 # Collector description\n#    query: |                                                        # Metrics Query SQL\n#\n#      SELECT extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n#             pg_current_wal_lsn() - '0/0'                           AS lsn,\n#             pg_current_wal_insert_lsn() - '0/0'                    AS insert_lsn,\n#             pg_current_wal_lsn() - '0/0'                           AS write_lsn,\n#             pg_current_wal_flush_lsn() - '0/0'                     AS flush_lsn,\n#             extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n#             extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n#             pg_is_in_backup()                                      AS is_in_backup,\n#             extract(EPOCH FROM now() - pg_backup_start_time())     AS backup_time;\n#\n#                             # [OPTIONAL] metadata fields, control collector behavior\n#    ttl: 10                  # Cache TTL: in seconds, how long will pg_exporter cache this collector`s query result.\n#    timeout: 0.1             # Query Timeout: in seconds, queries that exceed this limit will be canceled.\n#    min_version: 100000      # minimal supported version, boundary IS included. In server version number format,\n#    max_version: 130000      # maximal supported version, boundary NOT included, In server version number format\n#    fatal: false             # Collector marked `fatal` fails, the entire scrape will abort immediately and marked as failed\n#    skip: false              # Collector marked `skip` will not be installed during the planning procedure\n#\n#    tags: [cluster, primary] # Collector tags, used for planning and scheduling\n#\n#    # tags are list of strings, which could be:\n#    #   * `cluster` marks this query as cluster level, so it will only execute once for the same PostgreSQL Server\n#    #   * `primary` or `master`  mark this query can only run on a primary instance (WILL NOT execute if pg_is_in_recovery())\n#    #   * `standby` or `replica` mark this query can only run on a replica instance (WILL execute if pg_is_in_recovery())\n#    # some special tag prefix have special interpretation:\n#    #   * `dbname:<dbname>` means this query will ONLY be executed on database with name `<dbname>`\n#    #   * `username:<user>` means this query will only be executed when connect with user `<user>`\n#    #   * `extension:<extname>` means this query will only be executed when extension `<extname>` is installed\n#    #   * `schema:<nspname>` means this query will only by executed when schema `<nspname>` exist\n#    #   * `not:<negtag>` means this query WILL NOT be executed when exporter is tagged with `<negtag>`\n#    #   * `<tag>` means this query WILL be executed when exporter is tagged with `<tag>`\n#    #   ( <tag> could not be cluster,primary,standby,master,replica,etc...)\n#\n#    # One or more \"predicate queries\" may be defined for a metric query. These\n#    # are run before the main metric query (after any cache hit check). If all\n#    # of them, when run sequentially, return a single row with a single column\n#    # boolean true result, the main metric query is executed. If any of them\n#    # return false or return zero rows, the main query is skipped. If any\n#    # predicate query returns more than one row, a non-boolean result, or fails\n#    # with an error, the whole query is marked failed. Predicate queries can be\n#    # used to check for the presence of specific functions, tables, extensions,\n#    # settings, and vendor-specific pg features before running the main query.\n#\n#    predicate_queries:\n#      - name: predicate query name\n#        predicate_query: |\n#          SELECT EXISTS (SELECT 1 FROM information_schema.routines WHERE routine_schema = 'pg_catalog' AND routine_name = 'pg_backup_start_time');\n#\n#    metrics:                 # List of returned columns, each column must have a `name` and `usage`, `rename` and `description` are optional\n#      - timestamp:           # Column name, should be exactly the same as returned column name\n#          usage: GAUGE       # Metric type, `usage` could be\n#                                  * DISCARD: completely ignoring this field\n#                                  * LABEL:   use columnName=columnValue as a label in metric\n#                                  * GAUGE:   Mark column as a gauge metric, full name will be `<query.name>_<column.name>`\n#                                  * COUNTER: Same as above, except it is a counter rather than a gauge.\n#          rename: ts         # [OPTIONAL] Alias, optional, the alias will be used instead of the column name\n#          description: xxxx  # [OPTIONAL] Description of the column, will be used as a metric description\n#          default: 0         # [OPTIONAL] Default value, will be used when column is NULL\n#          scale:   1000      # [OPTIONAL] Scale the value by this factor\n#      - lsn:\n#          usage: COUNTER\n#          description: log sequence number, current write location (on primary)\n#      - insert_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal inserting\n#      - write_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal writing\n#      - flush_lsn:\n#          usage: COUNTER\n#          description: primary only, location of current wal syncing\n#      - uptime:\n#          usage: GAUGE\n#          description: seconds since postmaster start\n#      - conf_reload_time:\n#          usage: GAUGE\n#          description: seconds since last configuration reload\n#      - is_in_backup:\n#          usage: GAUGE\n#          description: 1 if backup is in progress\n#      - backup_time:\n#          usage: GAUGE\n#          description: seconds since the current backup start. null if don`t have one\n#\n#      .... # you can also use rename & scale to customize the metric name and value:\n#      - checkpoint_write_time:\n#          rename: write_time\n#          usage: COUNTER\n#          scale: 1e-3\n#          description: Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\n\n#==============================================================#\n# 4. Collector Presets\n#==============================================================#\n# pg_exporter is shipped with a series of preset collectors (already numbered and ordered by filename)\n#\n# 1xx  Basic metrics:        basic info, metadata, settings\n# 2xx  Replication metrics:  replication, walreceiver, downstream, sync standby, slots, subscription\n# 3xx  Persist metrics:      size, wal, background writer, checkpointer, ssl, checkpoint, recovery, slru cache, shmem usage\n# 4xx  Activity metrics:     backend count group by state, wait event, locks, xacts, queries\n# 5xx  Progress metrics:     clustering, vacuuming, indexing, basebackup, copy\n# 6xx  Database metrics:     pg_database, publication, subscription\n# 7xx  Object metrics:       pg_class, table, index, function, sequence, default partition\n# 8xx  Optional metrics:     optional metrics collector (disable by default, slow queries)\n# 9xx  Pgbouncer metrics:    metrics from pgbouncer admin database `pgbouncer`\n#\n# 100-599 Metrics for entire database cluster  (scrape once)\n# 600-899 Metrics for single database instance (scrape for each database ,except for pg_db itself)\n\n#==============================================================#\n# 5. Cache TTL\n#==============================================================#\n# Cache can be used for reducing query overhead, it can be enabled by setting a non-zero value for `ttl`\n# It is highly recommended to use cache to avoid duplicate scrapes. Especially when you got multiple Prometheus\n# scraping the same instance with slow monitoring queries. Setting `ttl` to zero or leaving blank will disable\n# result caching, which is the default behavior\n#\n# TTL has to be smaller than your scrape interval. 15s scrape interval and 10s TTL is a good start for\n# production environment. Some expensive monitoring queries (such as size/bloat check) will have longer `ttl`\n# which can also be used as a mechanism to achieve `different scrape frequency`\n\n#==============================================================#\n# 6. Query Timeout\n#==============================================================#\n# Collectors can be configured with an optional Timeout. If the collector's query executes more than that\n# timeout, it will be canceled immediately. Setting the `timeout` to 0 or leaving blank will reset it to\n# default timeout 0.1 (100ms). Setting it to any negative number will disable the query timeout feature.\n# All queries have a default timeout of 100ms, if exceeded, the query will be canceled immediately to avoid\n# avalanche. You can explicitly overwrite that option. but beware: in some extreme cases, if all your\n# timeouts sum up greater your scrape/cache interval (usually 15s), the queries may still be jammed.\n# or, you can just disable potential slow queries.\n\n#==============================================================#\n# 7. Version Compatibility\n#==============================================================#\n# Each collector has two optional version compatibility parameters: `min_version` and `max_version`.\n# These two parameters specify the version compatibility of the collector. If target postgres/pgbouncer's\n# version is less than `min_version`, or higher than `max_version`, the collector will not be installed.\n# These two parameters are using PostgreSQL server version number format, which is a 6-digit integer\n# format as <major:2 digit><minor:2 digit>:<release: 2 digit>.\n# For example, 090600 stands for 9.6, and 120100 stands for 12.1\n# And beware that version compatibility range is left-inclusive right exclusive: [min, max), set to zero or\n# leaving blank will affect as -inf or +inf\n\n#==============================================================#\n# 8. Fatality\n#==============================================================#\n# If a collector is marked with `fatal` falls, the entire scrape operation will be marked as fail and key metrics\n# `pg_up` / `pgbouncer_up` will be reset to 0. It is always a good practice to set up AT LEAST ONE fatal\n# collector for pg_exporter. `pg.pg_primary_only` and `pgbouncer_list` are the default fatal collector.\n#\n# If a collector without `fatal` flag fails, it will increase global fail counters. But the scrape operation\n# will carry on. The entire scrape result will not be marked as faile, thus will not affect the `<xx>_up` metric.\n\n#==============================================================#\n# 9. Skip\n#==============================================================#\n# Collector with `skip` flag set to true will NOT be installed.\n# This could be a handy option to disable collectors\n\n#==============================================================#\n# 10. Tags and Planning\n#==============================================================#\n# Tags are designed for collector planning & schedule. It can be handy to customize which queries run\n# on which instances. And thus you can use one-single monolith config for multiple environments\n#\n#  Tags are a list of strings, each string could be:\n#  Pre-defined special tags\n#    * `cluster` marks this collector as cluster level, so it will ONLY BE EXECUTED ONCE for the same PostgreSQL Server\n#    * `primary` or `master` mark this collector as primary-only, so it WILL NOT work iff pg_is_in_recovery()\n#    * `standby` or `replica` mark this collector as replica-only, so it WILL work iff pg_is_in_recovery()\n#  Special tag prefix which have different interpretation:\n#    * `dbname:<dbname>` means this collector will ONLY work on database with name `<dbname>`\n#    * `username:<user>` means this collector will ONLY work when connect with user `<user>`\n#    * `extension:<extname>` means this collector will ONLY work when extension `<extname>` is installed\n#    * `schema:<nspname>` means this collector will only work when schema `<nspname>` exists\n#  Customized positive tags (filter) and negative tags (taint)\n#    * `not:<negtag>` means this collector WILL NOT work when exporter is tagged with `<negtag>`\n#    * `<tag>` means this query WILL work if exporter is tagged with `<tag>` (special tags not included)\n#\n#  pg_exporter will trigger the Planning procedure after connecting to the target. It will gather database facts\n#  and match them with tags and other metadata (such as supported version range). Collector will only\n#  be installed if and only if it is compatible with the target server.\n\n\n#==============================================================#\n# 0110 pg\n#==============================================================#\npg_primary_only:\n  name: pg\n  desc: PostgreSQL basic information (on primary)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      pg_current_wal_lsn() - '0/0'                           AS lsn,\n      pg_current_wal_insert_lsn() - '0/0'                    AS insert_lsn,\n      pg_current_wal_lsn() - '0/0'                           AS write_lsn,\n      pg_current_wal_flush_lsn() - '0/0'                     AS flush_lsn,\n      NULL::BIGINT                                           AS receive_lsn,\n      NULL::BIGINT                                           AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      NULL::FLOAT                                            AS last_replay_time,\n      0::FLOAT                                               AS lag,\n      pg_is_in_recovery()                                    AS is_in_recovery,\n      FALSE                                                  AS is_wal_replay_paused;\n  tags: [ cluster, primary ]\n  ttl: 1\n  min_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\npg_replica_only:\n  name: pg\n  desc: PostgreSQL basic information (on replica)\n  query: |-\n    SELECT \n      extract(EPOCH FROM CURRENT_TIMESTAMP)                  AS timestamp,\n      extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime,\n      extract(EPOCH FROM pg_postmaster_start_time())         AS boot_time,\n      pg_last_wal_replay_lsn() - '0/0'                       AS lsn,\n      NULL::BIGINT                                           AS insert_lsn,\n      NULL::BIGINT                                           AS write_lsn,\n      NULL::BIGINT                                           AS flush_lsn,\n      pg_last_wal_receive_lsn() - '0/0'                      AS receive_lsn,\n      pg_last_wal_replay_lsn() - '0/0'                       AS replay_lsn,\n      extract(EPOCH FROM pg_conf_load_time())                AS reload_time,\n      extract(EPOCH FROM now() - pg_conf_load_time())        AS conf_reload_time,\n      extract(EPOCH FROM pg_last_xact_replay_timestamp())    AS last_replay_time,\n      CASE WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0\n          ELSE EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp()) END AS lag,\n      pg_is_in_recovery() AS is_in_recovery,\n      pg_is_wal_replay_paused() AS is_wal_replay_paused;\n\n  tags: [ cluster, replica ]\n  ttl: 1\n  min_version: 100000\n  fatal: true\n  skip: false\n  metrics:\n    - timestamp:            { usage: GAUGE   ,description: \"current database timestamp in unix epoch\" }\n    - uptime:               { usage: GAUGE   ,description: \"seconds since postmaster start\" }\n    - boot_time:            { usage: GAUGE   ,description: \"postmaster boot timestamp in unix epoch\" }\n    - lsn:                  { usage: COUNTER ,description: \"log sequence number, current write location\" }\n    - insert_lsn:           { usage: COUNTER ,description: \"primary only, location of current wal inserting\" }\n    - write_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal writing\" }\n    - flush_lsn:            { usage: COUNTER ,description: \"primary only, location of current wal syncing\" }\n    - receive_lsn:          { usage: COUNTER ,description: \"replica only, location of wal synced to disk\" }\n    - replay_lsn:           { usage: COUNTER ,description: \"replica only, location of wal applied\" }\n    - reload_time:          { usage: GAUGE   ,description: \"time when configuration was last reloaded\" }\n    - conf_reload_time:     { usage: GAUGE   ,description: \"seconds since last configuration reload\" }\n    - last_replay_time:     { usage: GAUGE   ,description: \"time when last transaction been replayed\" }\n    - lag:                  { usage: GAUGE   ,description: \"replica only, replication lag in seconds\" }\n    - is_in_recovery:       { usage: GAUGE   ,description: \"1 if in recovery mode\" }\n    - is_wal_replay_paused: { usage: GAUGE   ,description: \"1 if wal play is paused\" }\n\n\n#==============================================================#\n# 0120 pg_meta\n#==============================================================#\npg_meta_13:\n  name: pg_meta\n  desc: PostgreSQL meta info for pg 13+, with extra primary conninfo\n  query: |\n    SELECT \n      (SELECT system_identifier FROM pg_control_system()) AS cluster_id,\n      current_setting('cluster_name')                     AS cluster_name,\n      current_setting('port')                             AS listen_port,\n      current_setting('data_directory', true)             AS data_dir,\n      current_setting('config_file', true)                AS conf_path,\n      current_setting('hba_file', true)                   AS hba_path,\n      current_setting('wal_level')                        AS wal_level,\n      current_setting('server_encoding')                  AS encoding,\n      current_setting('server_version')                   AS version,\n      current_setting('server_version_num')               AS ver_num,\n      version()                                           AS ver_str,\n      current_setting('shared_preload_libraries', true)   AS extensions,\n      current_setting('primary_conninfo', true)           AS primary_conninfo,\n      1                                                   AS info\n  ttl: 10\n  min_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\npg_meta_10:\n  name: pg_meta\n  desc: PostgreSQL meta info\n  query: |\n    SELECT \n      (SELECT system_identifier FROM pg_control_system()) AS cluster_id,\n      current_setting('cluster_name')                     AS cluster_name,\n      current_setting('port')                             AS listen_port,\n      current_setting('data_directory', true)             AS data_dir,\n      current_setting('config_file', true)                AS conf_path,\n      current_setting('hba_file', true)                   AS hba_path,\n      current_setting('wal_level')                        AS wal_level,\n      current_setting('server_encoding')                  AS encoding,\n      current_setting('server_version')                   AS version,\n      current_setting('server_version_num')               AS ver_num,\n      version()                                           AS ver_str,\n      current_setting('shared_preload_libraries', true)   AS extensions,\n      'N/A'                                               AS primary_conninfo,\n      1                                                   AS info\n  ttl: 10\n  min_version: 090600\n  max_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - cluster_id:        { usage: LABEL ,description: \"cluster system identifier\" }\n    - cluster_name:      { usage: LABEL ,description: \"cluster name\" }\n    - listen_port:       { usage: LABEL ,description: \"listen port\" }\n    - data_dir:          { usage: LABEL ,description: \"path to data directory\" }\n    - conf_path:         { usage: LABEL ,description: \"path to postgresql.conf\" }\n    - hba_path:          { usage: LABEL ,description: \"path to pg_hba.conf\" }\n    - wal_level:         { usage: LABEL ,description: \"wal level\" }\n    - encoding:          { usage: LABEL ,description: \"server encoding\" }\n    - version:           { usage: LABEL ,description: \"server version in human-readable format\" }\n    - ver_num:           { usage: LABEL ,description: \"server version number in machine-readable format\" }\n    - ver_str:           { usage: LABEL ,description: \"complete version string\" }\n    - extensions:        { usage: LABEL ,description: \"server installed preload libraries\" }\n    - primary_conninfo:  { usage: LABEL ,description: \"connection string to upstream (do not set password here)\" }\n    - info:              { usage: GAUGE ,description: \"constant 1\" }\n\n#==============================================================#\n# 0130 pg_setting\n#==============================================================#\n# Key PostgreSQL configuration parameters\n# All parameters use current_setting(name, missing_ok) for version safety\n# Parameters introduced after PG10 use missing_ok=true to return NULL on older versions\npg_setting:\n  name: pg_setting\n  desc: PostgreSQL shared configuration parameters (shared across all databases)\n  query: |\n    SELECT\n      current_setting('max_connections')::int                          AS max_connections,\n      current_setting('max_prepared_transactions')::int                AS max_prepared_transactions,\n      current_setting('max_locks_per_transaction')::int                AS max_locks_per_transaction,\n      current_setting('max_worker_processes')::int                     AS max_worker_processes,\n      current_setting('max_parallel_workers')::int                     AS max_parallel_workers,\n      current_setting('max_parallel_workers_per_gather')::int          AS max_parallel_workers_per_gather,\n      current_setting('max_parallel_maintenance_workers', true)::int   AS max_parallel_maintenance_workers,\n      current_setting('max_replication_slots')::int                    AS max_replication_slots,\n      current_setting('max_wal_senders')::int                          AS max_wal_senders,\n      current_setting('block_size')::int                               AS block_size,\n      current_setting('wal_block_size')::int                           AS wal_block_size,\n      pg_size_bytes(current_setting('segment_size'))                   AS segment_size,\n      pg_size_bytes(current_setting('wal_segment_size'))               AS wal_segment_size,\n      CASE current_setting('data_checksums') WHEN 'on' THEN 1 ELSE 0 END AS data_checksums,\n      CASE current_setting('wal_log_hints') WHEN 'on' THEN 1 ELSE 0 END AS wal_log_hints,\n      CASE current_setting('fsync') WHEN 'on' THEN 1 ELSE 0 END AS fsync,\n      CASE current_setting('full_page_writes') WHEN 'on' THEN 1 ELSE 0 END AS full_page_writes,\n      CASE current_setting('wal_level') WHEN 'logical' THEN 3 WHEN 'replica' THEN 2 WHEN 'minimal' THEN 1 ELSE 0 END AS wal_level,\n      pg_size_bytes(current_setting('min_wal_size'))                   AS min_wal_size,\n      pg_size_bytes(current_setting('max_wal_size'))                   AS max_wal_size,\n      pg_size_bytes(current_setting('max_slot_wal_keep_size', true))   AS max_slot_wal_keep_size,\n      pg_size_bytes(current_setting('shared_buffers'))                 AS shared_buffers,\n      pg_size_bytes(current_setting('work_mem'))                       AS work_mem,\n      pg_size_bytes(current_setting('maintenance_work_mem'))           AS maintenance_work_mem,\n      pg_size_bytes(current_setting('effective_cache_size'))           AS effective_cache_size,\n      pg_size_bytes(current_setting('shared_memory_size', true))       AS shared_memory_size,\n      CASE current_setting('huge_pages_status', true) WHEN 'on' THEN 1 WHEN 'off' THEN 0 WHEN 'unknown' THEN -1 ELSE NULL END AS hugepage_status,\n      current_setting('shared_memory_size_in_huge_pages', true)::int   AS hugepage_count,\n      CASE current_setting('archive_mode') WHEN 'off' THEN 0 WHEN 'on' THEN 1 WHEN 'always' THEN 2 ELSE -1 END AS archive_mode,\n      CASE current_setting('autovacuum') WHEN 'on' THEN 1 ELSE 0 END AS autovacuum,\n      current_setting('autovacuum_max_workers')::int                   AS autovacuum_max_workers,\n      extract(epoch from current_setting('checkpoint_timeout')::interval)::int AS checkpoint_timeout,\n      current_setting('checkpoint_completion_target')::float           AS checkpoint_completion_target,\n      CASE current_setting('hot_standby') WHEN 'on' THEN 1 ELSE 0 END AS hot_standby,\n      CASE current_setting('synchronous_commit')\n        WHEN 'off' THEN 0 WHEN 'local' THEN 1 WHEN 'remote_write' THEN 2\n        WHEN 'on' THEN 3 WHEN 'remote_apply' THEN 4 ELSE -1 END AS synchronous_commit,\n      CASE current_setting('io_method', true)\n        WHEN 'sync' THEN 0 WHEN 'worker' THEN 1 WHEN 'io_uring' THEN 2 ELSE NULL END AS io_method;\n\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - max_connections:                  { usage: GAUGE ,description: \"maximum number of concurrent connections to the database server\" }\n    - max_prepared_transactions:        { usage: GAUGE ,description: \"maximum number of transactions that can be in the prepared state simultaneously\" }\n    - max_locks_per_transaction:        { usage: GAUGE ,description: \"maximum number of locks per transaction\" }\n    - max_worker_processes:             { usage: GAUGE ,description: \"maximum number of background processes\" }\n    - max_parallel_workers:             { usage: GAUGE ,description: \"maximum number of parallel workers that can be active at one time\" }\n    - max_parallel_workers_per_gather:  { usage: GAUGE ,description: \"maximum number of parallel workers per Gather node\" }\n    - max_parallel_maintenance_workers: { usage: GAUGE ,description: \"maximum number of parallel maintenance workers (PG11+, NULL on older)\" }\n    - max_replication_slots:            { usage: GAUGE ,description: \"maximum number of replication slots\" }\n    - max_wal_senders:                  { usage: GAUGE ,description: \"maximum number of concurrent WAL sender connections\" }\n    - block_size:                       { usage: GAUGE ,description: \"database block size in bytes (default 8192)\" }\n    - wal_block_size:                   { usage: GAUGE ,description: \"WAL block size in bytes\" }\n    - segment_size:                     { usage: GAUGE ,description: \"database file segment size in bytes\" }\n    - wal_segment_size:                 { usage: GAUGE ,description: \"WAL segment size in bytes\" }\n    - data_checksums:                   { usage: GAUGE ,description: \"data checksums enabled, 1=on 0=off\" }\n    - wal_log_hints:                    { usage: GAUGE ,description: \"WAL log hints enabled, 1=on 0=off\" }\n    - fsync:                            { usage: GAUGE ,description: \"fsync enabled (CRITICAL for data safety), 1=on 0=off\" }\n    - full_page_writes:                 { usage: GAUGE ,description: \"full page writes enabled, 1=on 0=off\" }\n    - wal_level:                        { usage: GAUGE ,description: \"WAL level, 1=minimal 2=replica 3=logical\" }\n    - min_wal_size:                     { usage: GAUGE ,description: \"minimum WAL size in bytes\" }\n    - max_wal_size:                     { usage: GAUGE ,description: \"maximum WAL size in bytes\" }\n    - max_slot_wal_keep_size:           { usage: GAUGE ,description: \"maximum WAL size retained by replication slots in bytes (PG13+, NULL on older)\" }\n    - shared_buffers:                   { usage: GAUGE ,description: \"shared buffer size in bytes\" }\n    - work_mem:                         { usage: GAUGE ,description: \"work memory size in bytes\" }\n    - maintenance_work_mem:             { usage: GAUGE ,description: \"maintenance work memory size in bytes\" }\n    - effective_cache_size:             { usage: GAUGE ,description: \"planner's assumption about effective OS cache size in bytes\" }\n    - shared_memory_size:               { usage: GAUGE ,description: \"total shared memory size in bytes (PG13+, NULL on older)\" }\n    - hugepage_status:                  { usage: GAUGE ,description: \"huge pages status, 1=on 0=off -1=unknown NULL=unavailable (PG14+)\" }\n    - hugepage_count:                   { usage: GAUGE ,description: \"number of huge pages needed for shared memory (PG14+, NULL on older)\" }\n    - archive_mode:                     { usage: GAUGE ,description: \"archive mode, 0=off 1=on 2=always\" }\n    - autovacuum:                       { usage: GAUGE ,description: \"autovacuum enabled, 1=on 0=off\" }\n    - autovacuum_max_workers:           { usage: GAUGE ,description: \"maximum number of autovacuum worker processes\" }\n    - checkpoint_timeout:               { usage: GAUGE ,description: \"checkpoint timeout in seconds\" }\n    - checkpoint_completion_target:     { usage: GAUGE ,description: \"checkpoint completion target (0.0-1.0)\" }\n    - hot_standby:                      { usage: GAUGE ,description: \"hot standby mode enabled, 1=on 0=off\" }\n    - synchronous_commit:               { usage: GAUGE ,description: \"synchronous commit level, 0=off 1=local 2=remote_write 3=on 4=remote_apply\" }\n    - io_method:                         { usage: GAUGE ,description: \"I/O method (PG18+), 0=sync 1=worker 2=io_uring NULL=unavailable\" }\n\n\n\n#==============================================================#\n# 0210 pg_repl\n#==============================================================#\npg_repl_12:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics 12+\n  query: |\n    SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n           CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n           CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n           sync_priority, backend_xmin::TEXT::BIGINT AS backend_xmin, current.lsn - '0/0' AS lsn,\n           current.lsn - sent_lsn AS sent_diff, current.lsn - write_lsn AS write_diff, current.lsn - flush_lsn AS flush_diff, current.lsn - replay_lsn AS replay_diff,\n           sent_lsn - '0/0' AS sent_lsn, write_lsn - '0/0' AS write_lsn, flush_lsn - '0/0' AS flush_lsn, replay_lsn - '0/0' AS replay_lsn,\n           coalesce(extract(EPOCH FROM write_lag), 0)  AS write_lag, coalesce(extract(EPOCH FROM flush_lag), 0)  AS flush_lag, coalesce(extract(EPOCH FROM replay_lag), 0) AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time, extract(EPOCH FROM reply_time) AS reply_time\n    FROM pg_stat_replication, (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END AS lsn) current;\n  ttl: 10\n  min_version: 120000\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback.\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n    - reply_time:        { usage: GAUGE   ,description: \"Send time of last reply message received from standby server\" }\n\npg_repl_10:\n  name: pg_repl\n  desc: PostgreSQL replication stat metrics v10 v11\n  query: |\n    SELECT application_name AS appname, usename, coalesce(client_addr::TEXT,'localhost') AS address, pid::TEXT, client_port,\n           CASE state WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n           CASE sync_state WHEN 'async' THEN 0 WHEN 'potential' THEN 1 WHEN 'sync' THEN 2 WHEN 'quorum' THEN 3 ELSE -1 END AS sync_state,\n           sync_priority, backend_xmin::TEXT::BIGINT AS backend_xmin, current.lsn - '0/0' AS lsn,\n           current.lsn - sent_lsn AS sent_diff, current.lsn - write_lsn AS write_diff, current.lsn - flush_lsn AS flush_diff, current.lsn - replay_lsn AS replay_diff,\n           sent_lsn - '0/0' AS sent_lsn, write_lsn - '0/0' AS write_lsn, flush_lsn - '0/0' AS flush_lsn, replay_lsn - '0/0' AS replay_lsn,\n           coalesce(extract(EPOCH FROM write_lag), 0)  AS write_lag, coalesce(extract(EPOCH FROM flush_lag), 0)  AS flush_lag, coalesce(extract(EPOCH FROM replay_lag), 0) AS replay_lag,\n           extract(EPOCH FROM current_timestamp) AS \"time\", extract(EPOCH FROM backend_start) AS launch_time\n    FROM pg_stat_replication, (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END AS lsn) current;\n  ttl: 10\n  min_version: 100000\n  max_version: 120000\n  tags: [ cluster ]\n  metrics:\n    - appname:           { usage: LABEL   ,description: \"Name of the application that is connected to this WAL sender\" }\n    - usename:           { usage: LABEL   ,description: \"Name of the user logged into this WAL sender process\" }\n    - address:           { usage: LABEL   ,description: \"IP address of the client connected to this WAL sender, localhost for unix socket\" }\n    - pid:               { usage: LABEL   ,description: \"Process ID of the WAL sender process\" }\n    - client_port:       { usage: GAUGE   ,description: \"TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used\" }\n    - state:             { usage: GAUGE   ,description: \"Current WAL sender encoded state 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - sync_state:        { usage: GAUGE   ,description: \"Encoded synchronous state of this standby server, 0-3 for async|potential|sync|quorum\" }\n    - sync_priority:     { usage: GAUGE   ,description: \"Priority of this standby server for being chosen as the synchronous standby\" }\n    - backend_xmin:      { usage: COUNTER ,description: \"This standby's xmin horizon reported by hot_standby_feedback.\" }\n    - lsn:               { usage: COUNTER ,description: \"Current log position on this server\" }\n    - sent_diff:         { usage: GAUGE   ,description: \"Last log position sent to this standby server diff with current lsn\" }\n    - write_diff:        { usage: GAUGE   ,description: \"Last log position written to disk by this standby server diff with current lsn\" }\n    - flush_diff:        { usage: GAUGE   ,description: \"Last log position flushed to disk by this standby server diff with current lsn\" }\n    - replay_diff:       { usage: GAUGE   ,description: \"Last log position replayed into the database on this standby server diff with current lsn\" }\n    - sent_lsn:          { usage: COUNTER ,description: \"Last write-ahead log location sent on this connection\" }\n    - write_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location written to disk by this standby server\" }\n    - flush_lsn:         { usage: COUNTER ,description: \"Last write-ahead log location flushed to disk by this standby server\" }\n    - replay_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location replayed into the database on this standby server\" }\n    - write_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it\" }\n    - flush_lag:         { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it\" }\n    - replay_lag:        { usage: GAUGE   ,description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it\" }\n    - time:              { usage: COUNTER ,description: \"Current timestamp in unix epoch\" }\n    - launch_time:       { usage: COUNTER ,description: \"Time when this process was started, i.e., when the client connected to this WAL sender\" }\n\n\n#==============================================================#\n# 0220 pg_sync_standby\n#==============================================================#\npg_sync_standby:\n  name: pg_sync_standby\n  desc: PostgreSQL synchronous standby status and names\n  query: |\n    SELECT CASE WHEN names <> '' THEN names ELSE '<null>' END AS names, CASE WHEN names <> '' THEN 1 ELSE 0 END AS enabled FROM (SELECT current_setting('synchronous_standby_names') AS names) n;\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - names:             { usage: LABEL ,description: \"List of standby servers that can support synchronous replication, <null> if not enabled\" }\n    - enabled:           { usage: GAUGE ,description: \"Synchronous commit enabled, 1 if enabled, 0 if disabled\" }\n\n\n#==============================================================#\n# 0230 pg_downstream\n#==============================================================#\npg_downstream:\n  name: pg_downstream\n  desc: PostgreSQL replication client count group by state\n  query: |\n    SELECT l.state, coalesce(count, 0 ) AS count FROM unnest(ARRAY ['streaming','startup','catchup', 'backup', 'stopping']) l(state) LEFT JOIN (SELECT state, count(*) AS count FROM pg_stat_replication GROUP BY state)r ON l.state =  r.state;\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - state:             { usage: LABEL ,description: \"Replication client state, could be one of startup|catchup|streaming|backup|stopping\" }\n    - count:             { usage: GAUGE ,description: \"Count of corresponding state\" }\n\n\n#==============================================================#\n# 0240 pg_slot\n#==============================================================#\npg_slot_17:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v17, slot also exists on standby\n  query: |-\n    SELECT s.slot_name, s.slot_type, plugin, database AS datname,datoid,active_pid,\n       active,temporary,two_phase,conflicting,failover,synced,\n       xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n       restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n       CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n       safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status,\n       spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,extract(EPOCH FROM stats_reset) AS reset_time,\n       extract(EPOCH FROM inactive_since) AS inactive_since, CASE invalidation_reason WHEN 'wal_removed' THEN 1 WHEN 'rows_removed' THEN 2 WHEN 'wal_level_insufficient' THEN 3 ELSE 0 END AS invalidation_reason \n    FROM pg_replication_slots s LEFT OUTER JOIN pg_stat_replication_slots ss ON s.slot_name = ss.slot_name;\n\n  ttl: 10\n  min_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - two_phase:           { usage: GAUGE    ,description: \"True(1) if the slot is enabled for decoding prepared transactions. Always false for physical slots.\" }\n    - conflicting:         { usage: GAUGE    ,description: \"True(1) if this logical slot conflicted with recovery. Always NULL for physical slots.\" }\n    - failover:            { usage: GAUGE    ,description: \"True(1) if this is a logical slot enabled to be synced to the standbys\" }\n    - synced:              { usage: GAUGE    ,description: \"True(1) if this is a logical slot that was synced from a primary server\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n    - spill_txns:          { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)\" }\n    - spill_count:         { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding\" }\n    - spill_bytes:         { usage: COUNTER  ,description: \"Bytes that spilled to disk due to logical decode mem exceeding\" }\n    - stream_txns:         { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_count:        { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_bytes:        { usage: COUNTER  ,description: \"Bytes that streamed to decoding output plugin after mem exceed\" }\n    - total_txns:          { usage: COUNTER  ,description: \"Number of decoded xacts sent to the decoding output plugin for this slot\" }\n    - total_bytes:         { usage: COUNTER  ,description: \"Number of decoded bytes sent to the decoding output plugin for this slot\" }\n    - reset_time:          { usage: GAUGE    ,description: \"When statistics were last reset\" }\n    - invalidation_reason: { usage: GAUGE    ,description: \"ok=0, wal_removed=1, rows_removed=2, wal_level_insufficient=3\" }\n    - inactive_since:      { usage: GAUGE    ,description: \"The time when the slot became inactive\" }\n\npg_slot_16:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v16 with conflicting, now slot also exists on standby\n  query: |-\n    SELECT s.slot_name, s.slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,two_phase,conflicting,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n      safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status,\n      spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_replication_slots s LEFT OUTER JOIN pg_stat_replication_slots ss ON s.slot_name = ss.slot_name;\n\n  ttl: 10\n  min_version: 160000\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - two_phase:           { usage: GAUGE    ,description: \"True(1) if the slot is enabled for decoding prepared transactions. Always false for physical slots.\" }\n    - conflicting:         { usage: GAUGE    ,description: \"True if this logical slot conflicted with recovery. Always NULL for physical slots.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n    - spill_txns:          { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)\" }\n    - spill_count:         { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding\" }\n    - spill_bytes:         { usage: COUNTER  ,description: \"Bytes that spilled to disk due to logical decode mem exceeding\" }\n    - stream_txns:         { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_count:        { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_bytes:        { usage: COUNTER  ,description: \"Bytes that streamed to decoding output plugin after mem exceed\" }\n    - total_txns:          { usage: COUNTER  ,description: \"Number of decoded xacts sent to the decoding output plugin for this slot\" }\n    - total_bytes:         { usage: COUNTER  ,description: \"Number of decoded bytes sent to the decoding output plugin for this slot\" }\n    - reset_time:          { usage: GAUGE    ,description: \"When statistics were last reset\" }\n\npg_slot_14:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v14 with pg_stat_replication_slots metrics\n  query: |-\n    SELECT s.slot_name, s.slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,two_phase,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n      safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status,\n      spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_replication_slots s LEFT OUTER JOIN pg_stat_replication_slots ss ON s.slot_name = ss.slot_name;\n\n  ttl: 10\n  min_version: 140000\n  max_version: 160000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - two_phase:           { usage: GAUGE    ,description: \"True(1) if the slot is enabled for decoding prepared transactions. Always false for physical slots.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n    - spill_txns:          { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)\" }\n    - spill_count:         { usage: COUNTER  ,description: \"Xacts that spilled to disk due to logical decode mem exceeding\" }\n    - spill_bytes:         { usage: COUNTER  ,description: \"Bytes that spilled to disk due to logical decode mem exceeding\" }\n    - stream_txns:         { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_count:        { usage: COUNTER  ,description: \"Xacts that streamed to decoding output plugin after mem exceed\" }\n    - stream_bytes:        { usage: COUNTER  ,description: \"Bytes that streamed to decoding output plugin after mem exceed\" }\n    - total_txns:          { usage: COUNTER  ,description: \"Number of decoded xacts sent to the decoding output plugin for this slot\" }\n    - total_bytes:         { usage: COUNTER  ,description: \"Number of decoded bytes sent to the decoding output plugin for this slot\" }\n    - reset_time:          { usage: GAUGE    ,description: \"When statistics were last reset\" }\n\npg_slot_13:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics v13 (wal safe size and status)\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes,\n      safe_wal_size, CASE wal_status WHEN 'reserved' THEN 0 WHEN 'extended' THEN 1 WHEN 'unreserved' THEN 2 WHEN 'lost' THEN 3 ELSE -1 END AS wal_status\n    FROM pg_replication_slots;\n\n  ttl: 10\n  min_version: 130000\n  max_version: 140000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n    - safe_wal_size:       { usage: GAUGE    ,description: \"bytes that can be written to WAL which will not make slot into lost\" }\n    - wal_status:          { usage: GAUGE    ,description: \"WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other\" }\n\npg_slot_10:\n  name: pg_slot\n  desc: PostgreSQL replication slot metrics 10 ~ 12\n  query: |-\n    SELECT slot_name, slot_type, plugin, database AS datname,datoid,active_pid,\n      active,temporary,xmin::TEXT::BIGINT AS xmin,catalog_xmin::TEXT::BIGINT  AS catalog_xmin,\n      restart_lsn - '0/0' AS restart_lsn, confirmed_flush_lsn - '0/0' AS confirm_lsn,\n      CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END - restart_lsn AS retained_bytes\n    FROM pg_replication_slots;\n\n  ttl: 10\n  min_version: 100000\n  max_version: 130000\n  tags: [ cluster, primary ]\n  metrics:\n    - slot_name:           { usage: LABEL    ,description: \"A unique, cluster-wide identifier for the replication slot\" }\n    - slot_type:           { usage: LABEL    ,description: \"The slot type, physical or logical\" }\n    - plugin:              { usage: LABEL    ,description: \"The base name of the shared object containing the output plugin this logical slot is using, or null for physical slots.\" }\n    - datname:             { usage: LABEL    ,description: \"The name of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - datoid:              { usage: GAUGE    ,description: \"The OID of the database this slot is associated with, logical slots only, null for physical slot\" }\n    - active_pid:          { usage: GAUGE    ,description: \"The process ID of the session streaming data for this slot. NULL if inactive.\" }\n    - active:              { usage: GAUGE    ,description: \"True(1) if this slot is currently actively being used\" }\n    - temporary:           { usage: GAUGE    ,description: \"True(1) if this is a temporary replication slot.\" }\n    - xmin:                { usage: COUNTER  ,description: \"The oldest transaction that this slot needs the database to retain.\" }\n    - catalog_xmin:        { usage: COUNTER  ,description: \"The oldest transaction affecting the system catalogs that this slot needs the database to retain.\" }\n    - restart_lsn:         { usage: COUNTER  ,description: \"The address (LSN) of oldest WAL which still might be required by the consumer of this slot\" }\n    - confirm_lsn:         { usage: COUNTER  ,description: \"The address (LSN) up to which the logical slot's consumer has confirmed receiving data.\" }\n    - retained_bytes:      { usage: GAUGE    ,description: \"Size of bytes that retained for this slot\" }\n\n\n#==============================================================#\n# 0250 pg_recv\n#==============================================================#\npg_recv_13:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics 13+\n  query: |-\n    SELECT \n      coalesce(sender_host, (regexp_match(conninfo, '.*host=(\\S+).*'))[1]) AS sender_host, coalesce(sender_port::TEXT, (regexp_match(conninfo, '.*port=(\\S+).*'))[1]) AS sender_port, coalesce(slot_name, 'NULL') AS slot_name,\n      pid, CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      receive_start_lsn - '0/0' AS init_lsn,receive_start_tli AS init_tli,\n      flushed_lsn - '0/0' AS flush_lsn,written_lsn - '0/0' AS write_lsn, received_tli AS flush_tli, latest_end_lsn - '0/0' AS reported_lsn,\n      last_msg_send_time AS msg_send_time,last_msg_receipt_time AS msg_recv_time,latest_end_time AS reported_time,now() AS time FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  min_version: 130000\n  tags: [ cluster, replica ]\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - write_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and written to disk, but not flushed.\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\npg_recv_11:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics (11-12)\n  query: |-\n    SELECT \n      coalesce(sender_host, (regexp_match(conninfo, '.*host=(\\S+).*'))[1]) AS sender_host, coalesce(sender_port::TEXT, (regexp_match(conninfo, '.*port=(\\S+).*'))[1]) AS sender_port, coalesce(slot_name, 'NULL') AS slot_name,\n      pid, CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      receive_start_lsn - '0/0' AS init_lsn,receive_start_tli AS init_tli,\n      received_lsn - '0/0' AS flush_lsn, received_tli AS flush_tli, latest_end_lsn - '0/0' AS reported_lsn,\n      last_msg_send_time AS msg_send_time,last_msg_receipt_time AS msg_recv_time,latest_end_time AS reported_time,now() AS time FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  tags: [ cluster, replica ]\n  min_version: 110000\n  max_version: 130000\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\npg_recv_10:\n  name: pg_recv\n  desc: PostgreSQL walreceiver metrics (10)\n  query: |-\n    SELECT \n      (regexp_match(conninfo, '.*host=(\\S+).*'))[1] AS sender_host, (regexp_match(conninfo, '.*port=(\\S+).*'))[1] AS sender_port, coalesce(slot_name, 'NULL') AS slot_name,\n      pid, CASE status WHEN 'streaming' THEN 0 WHEN 'startup' THEN 1 WHEN 'catchup' THEN 2 WHEN 'backup' THEN 3 WHEN 'stopping' THEN 4 ELSE -1 END AS state,\n      receive_start_lsn - '0/0' AS init_lsn,receive_start_tli AS init_tli,\n      received_lsn - '0/0' AS flush_lsn, received_tli AS flush_tli, latest_end_lsn - '0/0' AS reported_lsn,\n      last_msg_send_time AS msg_send_time,last_msg_receipt_time AS msg_recv_time,latest_end_time AS reported_time,now() AS time FROM pg_stat_wal_receiver;\n\n  ttl: 10\n  tags: [ cluster, replica ]\n  min_version: 100000\n  max_version: 110000\n  metrics:\n    - sender_host:         { usage: LABEL   ,description: \"Host of the PostgreSQL instance this WAL receiver is connected to\" }\n    - sender_port:         { usage: LABEL   ,description: \"Port number of the PostgreSQL instance this WAL receiver is connected to.\" }\n    - slot_name:           { usage: LABEL   ,description: \"Replication slot name used by this WAL receiver\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the WAL receiver process\" }\n    - state:               { usage: GAUGE   ,description: \"Encoded activity status of the WAL receiver process 0-4 for streaming|startup|catchup|backup|stopping\" }\n    - init_lsn:            { usage: COUNTER ,description: \"First write-ahead log location used when WAL receiver is started\" }\n    - init_tli:            { usage: COUNTER ,description: \"First timeline number used when WAL receiver is started\" }\n    - flush_lsn:           { usage: COUNTER ,description: \"Last write-ahead log location already received and flushed to disk\" }\n    - flush_tli:           { usage: COUNTER ,description: \"Timeline number of last write-ahead log location received and flushed to disk\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - time:                { usage: GAUGE   ,description: \"Time of current snapshot\" }\n\n#==============================================================#\n# 0260 pg_sub\n#==============================================================#\npg_sub_16:\n  name: pg_sub\n  desc: PostgreSQL subscription statistics (16+)\n  query: |-\n    SELECT \n      s1.subname, subid AS id, pid, received_lsn, reported_lsn,\n      msg_send_time, msg_recv_time, reported_time,\n      apply_error_count, sync_error_count\n    FROM\n      (SELECT\n        subname, subid, pid,\n        received_lsn - '0/0' AS received_lsn, latest_end_lsn - '0/0' AS reported_lsn,\n        extract(epoch from last_msg_send_time) AS msg_send_time,\n        extract(epoch from last_msg_receipt_time) AS msg_recv_time,\n        extract(epoch from latest_end_time) AS reported_time\n      FROM pg_stat_subscription \n      WHERE relid IS NULL AND leader_pid IS NULL) s1\n    LEFT OUTER JOIN pg_stat_subscription_stats s2 USING(subid);\n\n  ttl: 10\n  min_version: 160000\n  tags: [ cluster ]\n  metrics:\n    - subname:             { usage: LABEL   ,description: \"Name of this subscription\" }\n    - id:                  { usage: GAUGE   ,description: \"OID of the subscription\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the subscription leader apply worker\" }\n    - received_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location received\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - apply_error_count:   { usage: COUNTER ,description: \"Number of times an error occurred while applying changes\" }\n    - sync_error_count:    { usage: COUNTER ,description: \"Number of times an error occurred during the initial table synchronization\" }\n\npg_sub_15:\n  name: pg_sub\n  desc: PostgreSQL subscription statistics (15)\n  query: |-\n    SELECT \n      s1.subname, subid AS id, pid, received_lsn, reported_lsn,\n      msg_send_time, msg_recv_time, reported_time,\n      apply_error_count, sync_error_count\n    FROM\n      (SELECT\n        subname, subid, pid,\n        received_lsn - '0/0' AS received_lsn, latest_end_lsn - '0/0' AS reported_lsn,\n        extract(epoch from last_msg_send_time) AS msg_send_time,\n        extract(epoch from last_msg_receipt_time) AS msg_recv_time,\n        extract(epoch from latest_end_time) AS reported_time\n      FROM pg_stat_subscription WHERE relid ISNULL) s1\n    LEFT OUTER JOIN pg_stat_subscription_stats s2 USING(subid);\n\n  ttl: 10\n  min_version: 150000\n  max_version: 160000\n  tags: [ cluster ]\n  metrics:\n    - subname:             { usage: LABEL   ,description: \"Name of this subscription\" }\n    - id:                  { usage: GAUGE   ,description: \"OID of the subscription\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the subscription main apply worker process\" }\n    - received_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location received\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n    - apply_error_count:   { usage: COUNTER ,description: \"Number of times an error occurred while applying changes.\" }\n    - sync_error_count:    { usage: COUNTER ,description: \"Number of times an error occurred during the initial table synchronization\" }\n\npg_sub_10:\n  name: pg_sub\n  desc: PostgreSQL subscription statistics (10-14)\n  query: |-\n    SELECT \n      subname, subid AS id, pid,\n      received_lsn - '0/0' AS received_lsn, latest_end_lsn - '0/0' AS reported_lsn,\n      extract(epoch from last_msg_send_time) AS msg_send_time,\n      extract(epoch from last_msg_receipt_time) AS msg_recv_time,\n      extract(epoch from latest_end_time) AS reported_time\n    FROM pg_stat_subscription WHERE relid ISNULL;\n\n  ttl: 10\n  min_version: 100000\n  max_version: 150000\n  tags: [ cluster ]\n  metrics:\n    - subname:             { usage: LABEL   ,description: \"Name of this subscription\" }\n    - id:                  { usage: GAUGE   ,description: \"OID of the subscription\" }\n    - pid:                 { usage: GAUGE   ,description: \"Process ID of the subscription main apply worker process\" }\n    - received_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location received\" }\n    - reported_lsn:        { usage: COUNTER ,description: \"Last write-ahead log location reported to origin WAL sender\" }\n    - msg_send_time:       { usage: GAUGE   ,description: \"Send time of last message received from origin WAL sender\" }\n    - msg_recv_time:       { usage: GAUGE   ,description: \"Receipt time of last message received from origin WAL sender\" }\n    - reported_time:       { usage: GAUGE   ,description: \"Time of last write-ahead log location reported to origin WAL sender\" }\n\n\n#==============================================================#\n# 0270 pg_origin\n#==============================================================#\n# skip by default, require additional privilege setup\n# GRANT SELECT ON pg_replication_origin, pg_replication_origin_status TO pg_monitor;\npg_origin:\n  name: pg_origin\n  desc: PostgreSQL replay state (approximate) for a certain origin\n  query: SELECT roname, remote_lsn - '0/0' AS remote_lsn, local_lsn - '0/0' AS local_lsn FROM pg_replication_origin o LEFT JOIN pg_replication_origin_status os ON o.roident = os.local_id;\n  ttl: 10\n  min_version: 090500\n  skip: true\n  tags: [ cluster ]\n  metrics:\n    - roname:              { usage: LABEL     ,description: \"The external, user defined, name of a replication origin.\" }\n    - remote_lsn:          { usage: COUNTER   ,description: \"The origin node's LSN up to which data has been replicated.\" }\n    - local_lsn:           { usage: COUNTER   ,description: \"This node's LSN at which remote_lsn has been replicated.\" }\n\n\n#==============================================================#\n# 0300 pg_io\n#==============================================================#\npg_io_18:\n  name: pg_io\n  desc: PostgreSQL I/O stats since v18\n  query: |-\n    SELECT backend_type AS \"type\",object,context,reads,read_bytes,read_time,writes,write_bytes,write_time,writebacks,writeback_time,\n    extends,extend_bytes,extend_time,hits,evictions,reuses,fsyncs,fsync_time,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_io;\n\n  ttl: 10\n  timeout: 1\n  min_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - type:               { usage: LABEL                              ,description: \"Type of backend\" }\n    - object:             { usage: LABEL                              ,description: \"Target object of an I/O operation, relation or temp\" }\n    - context:            { usage: LABEL                              ,description: \"The context of an I/O operation. normal,vacuum,bulkread,bulkwrite\" }\n    - reads:              { usage: COUNTER ,default: 0                ,description: \"Number of read operations, each of the size specified in op_bytes.\" }\n    - read_bytes:         { usage: COUNTER ,default: 0                ,description: \"Number of read bytes\" }\n    - read_time:          { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in read operations in seconds\" }\n    - writes:             { usage: COUNTER ,default: 0                ,description: \"Number of write operations, each of the size specified in op_bytes.\" }\n    - write_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in write operations in seconds\" }\n    - write_bytes:        { usage: COUNTER ,default: 0                ,description: \"Number of write bytes\" }\n    - writebacks:         { usage: COUNTER ,default: 0                ,description: \"Number of units of size op_bytes which the process requested the kernel write out to permanent storage.\" }\n    - writeback_time:     { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in writeback operations in seconds\" }\n    - extends:            { usage: COUNTER ,default: 0                ,description: \"Number of relation extend operations, each of the size specified in op_bytes.\" }\n    - extend_bytes:       { usage: COUNTER ,default: 0                ,description: \"Number of extend bytes\" }\n    - extend_time:        { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in extend operations in seconds\" }\n    - hits:               { usage: COUNTER ,default: 0                ,description: \"The number of times a desired block was found in a shared buffer.\" }\n    - evictions:          { usage: COUNTER ,default: 0                ,description: \"Number of times a block has been written out from a shared or local buffer\" }\n    - reuses:             { usage: COUNTER ,default: 0                ,description: \"The number of times an existing buffer is reused\" }\n    - fsyncs:             { usage: COUNTER ,default: 0                ,description: \"Number of fsync calls. These are only tracked in context normal\" }\n    - fsync_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in fsync operations in seconds\" }\n    - reset_time:         { usage: GAUGE                              ,description: \"Timestamp at which these statistics were last reset\" }\n\npg_io_16:\n  name: pg_io\n  desc: PostgreSQL I/O stats\n  query: |-\n    SELECT backend_type AS \"type\", object, context, reads, read_time,writes,write_time,writebacks,writeback_time,extends,\n      extend_time,hits,evictions,reuses,fsyncs,fsync_time,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_io;\n\n  ttl: 10\n  timeout: 1\n  min_version: 160000\n  max_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - type:               { usage: LABEL                              ,description: \"Type of backend\" }\n    - object:             { usage: LABEL                              ,description: \"Target object of an I/O operation, relation or temp\" }\n    - context:            { usage: LABEL                              ,description: \"The context of an I/O operation. normal,vacuum,bulkread,bulkwrite\" }\n    - reads:              { usage: COUNTER ,default: 0                ,description: \"Number of read operations, each of the size specified in op_bytes.\" }\n    - read_time:          { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in read operations in seconds\" }\n    - writes:             { usage: COUNTER ,default: 0                ,description: \"Number of write operations, each of the size specified in op_bytes.\" }\n    - write_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in write operations in seconds\" }\n    - writebacks:         { usage: COUNTER ,default: 0                ,description: \"Number of units of size op_bytes which the process requested the kernel write out to permanent storage.\" }\n    - writeback_time:     { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in writeback operations in seconds\" }\n    - extends:            { usage: COUNTER ,default: 0                ,description: \"Number of relation extend operations, each of the size specified in op_bytes.\" }\n    - extend_time:        { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in extend operations in seconds\" }\n    - hits:               { usage: COUNTER ,default: 0                ,description: \"The number of times a desired block was found in a shared buffer.\" }\n    - evictions:          { usage: COUNTER ,default: 0                ,description: \"Number of times a block has been written out from a shared or local buffer\" }\n    - reuses:             { usage: COUNTER ,default: 0                ,description: \"The number of times an existing buffer is reused\" }\n    - fsyncs:             { usage: COUNTER ,default: 0                ,description: \"Number of fsync calls. These are only tracked in context normal\" }\n    - fsync_time:         { usage: COUNTER ,default: 0  ,scale: 1e-3  ,description: \"Time spent in fsync operations in seconds\" }\n    - reset_time:         { usage: GAUGE                              ,description: \"Timestamp at which these statistics were last reset\" }\n\n\n#==============================================================#\n# 0310 pg_size\n#==============================================================#\npg_size:\n  name: pg_size\n  desc: PostgreSQL Database, WAL, Log size since v10\n  query: |-\n    SELECT datname, pg_database_size(oid) AS bytes FROM pg_database\n    UNION ALL SELECT 'log', CASE WHEN current_setting('logging_collector') = 'on' THEN COALESCE((SELECT SUM(size) FROM pg_catalog.pg_ls_logdir()), 0) ELSE 0 END\n    UNION ALL SELECT 'wal', COALESCE((SELECT SUM(size) FROM pg_catalog.pg_ls_waldir()), 0);\n\n  ttl: 60\n  timeout: 1\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Database name, or special category wal, or log\" }\n    - bytes:               { usage: GAUGE   ,description: \"File size in bytes\" }\n\n\n#==============================================================#\n# 0320 pg_archiver\n#==============================================================#\npg_archiver:\n  name: pg_archiver\n  desc: PostgreSQL archiver process statistics\n  query: |-\n    SELECT archived_count AS finish_count,failed_count,\n      extract(epoch FROM last_archived_time) AS finish_time,\n      extract(epoch FROM last_failed_time) AS failed_time,\n      extract(epoch FROM stats_reset) AS reset_time\n    FROM pg_stat_archiver;\n\n  ttl: 60\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - finish_count:        { usage: COUNTER ,description: \"Number of WAL files that have been successfully archived\" }\n    - failed_count:        { usage: COUNTER ,description: \"Number of failed attempts for archiving WAL files\" }\n    - finish_time:         { usage: GAUGE   ,description: \"Time of the last successful archive operation\" }\n    - failed_time:         { usage: GAUGE   ,description: \"Time of the last failed archival operation\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which archive statistics were last reset\" }\n\n\n#==============================================================#\n# 0330 pg_bgwriter\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_bgwriter.html\npg_bgwriter_17:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics PG 17+\"\n  query: SELECT buffers_clean, maxwritten_clean, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - buffers_clean:       { usage: COUNTER ,description: \"Number of buffers written by the background writer\" }\n    - maxwritten_clean:    { usage: COUNTER ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_alloc:       { usage: COUNTER ,description: \"Number of buffers allocated\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which bgwriter statistics were last reset\" }\n\npg_bgwriter_10:\n  name: pg_bgwriter\n  desc: \"PostgreSQL background writer metrics (PG 9.4-16)\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, buffers_clean, buffers_backend, maxwritten_clean, buffers_backend_fsync, buffers_alloc, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 090400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER              ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER              ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER              ,description: \"Number of buffers written during checkpoints\" }\n    - buffers_clean:         { usage: COUNTER              ,description: \"Number of buffers written by the background writer\" }\n    - buffers_backend:       { usage: COUNTER              ,description: \"Number of buffers written directly by a backend\" }\n    - maxwritten_clean:      { usage: COUNTER              ,description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\" }\n    - buffers_backend_fsync: { usage: COUNTER              ,description: \"Number of times a backend had to execute its own fsync call\" }\n    - buffers_alloc:         { usage: COUNTER              ,description: \"Number of buffers allocated\" }\n    - reset_time:            { usage: GAUGE                ,description: \"Time at which bgwriter statistics were last reset\" }\n\n#==============================================================#\n# 0331 pg_checkpointer\n#==============================================================#\npg_checkpointer_18:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 18+\"\n  query: SELECT num_timed, num_requested, num_done, restartpoints_timed, restartpoints_req, restartpoints_done, write_time, sync_time, buffers_written, slru_written, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_checkpointer;\n  ttl: 10\n  min_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - num_timed:             { usage: COUNTER ,rename: timed ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - num_requested:         { usage: COUNTER ,rename: req   ,description: \"Number of requested checkpoints that have been performed\" }\n    - num_done:              { usage: COUNTER ,rename: done  ,description: \"Number of checkpoints that have been performed\" }\n    - restartpoints_timed:   { usage: COUNTER                ,description: \"Number of scheduled restartpoints due to timeout or after a failed attempt to perform it\" }\n    - restartpoints_req:     { usage: COUNTER                ,description: \"Number of requested restartpoints\" }\n    - restartpoints_done:    { usage: COUNTER                ,description: \"Number of restartpoints that have been performed\" }\n    - write_time:            { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - sync_time:             { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_written:       { usage: COUNTER                ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - slru_written:          { usage: COUNTER                ,description: \"Number of SLRU buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                  ,description: \"Time at which checkpointer statistics were last reset\" }\n\npg_checkpointer_17:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 17\"\n  query: SELECT num_timed, num_requested, restartpoints_timed, restartpoints_req, restartpoints_done, write_time, sync_time, buffers_written, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_checkpointer;\n  ttl: 10\n  min_version: 170000\n  max_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - num_timed:             { usage: COUNTER ,rename: timed ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - num_requested:         { usage: COUNTER ,rename: req   ,description: \"Number of requested checkpoints that have been performed\" }\n    - restartpoints_timed:   { usage: COUNTER                ,description: \"Number of scheduled restartpoints due to timeout or after a failed attempt to perform it\" }\n    - restartpoints_req:     { usage: COUNTER                ,description: \"Number of requested restartpoints\" }\n    - restartpoints_done:    { usage: COUNTER                ,description: \"Number of restartpoints that have been performed\" }\n    - write_time:            { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - sync_time:             { usage: COUNTER ,scale: 1e-3   ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_written:       { usage: COUNTER                ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                  ,description: \"Time at which checkpointer statistics were last reset\" }\n\npg_checkpointer_10:\n  name: pg_checkpointer\n  desc: \"PostgreSQL checkpointer stat metrics for pg 9.4-16\"\n  query: SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time, buffers_checkpoint, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_bgwriter;\n  ttl: 10\n  min_version: 090400\n  max_version: 170000\n  tags: [ cluster ]\n  metrics:\n    - checkpoints_timed:     { usage: COUNTER ,rename: timed                   ,description: \"Number of scheduled checkpoints that have been performed\" }\n    - checkpoints_req:       { usage: COUNTER ,rename: req                     ,description: \"Number of requested checkpoints that have been performed\" }\n    - checkpoint_write_time: { usage: COUNTER ,rename: write_time ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds\" }\n    - checkpoint_sync_time:  { usage: COUNTER ,rename: sync_time  ,scale: 1e-3 ,description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds\" }\n    - buffers_checkpoint:    { usage: COUNTER ,rename: buffers_written         ,description: \"Number of buffers written during checkpoints and restartpoints\" }\n    - reset_time:            { usage: GAUGE                                    ,description: \"Time at which checkpointer statistics were last reset\" }\n\n#==============================================================#\n# 0340 pg_ssl\n#==============================================================#\npg_ssl:\n  name: pg_ssl\n  desc: PostgreSQL SSL client connection count\n  query: |\n    SELECT count(*) FILTER (WHERE ssl) AS enabled, count(*) FILTER ( WHERE NOT ssl) AS disabled FROM pg_stat_ssl;\n  ttl: 10\n  min_version: 090500\n  tags: [ cluster ]\n  metrics:\n    - enabled:            { usage: GAUGE   ,description: \"Number of client connection that use ssl\" }\n    - disabled:           { usage: GAUGE   ,description: \"Number of client connection that does not use ssl\" }\n\n\n#==============================================================#\n# 0350 pg_checkpoint\n#==============================================================#\npg_checkpoint:\n  name: pg_checkpoint\n  desc: checkpoint information from pg_control_checkpoint since 10\n  query: |-\n    SELECT \n      checkpoint_lsn - '0/0' AS checkpoint_lsn,\n      redo_lsn - '0/0' AS redo_lsn,\n      timeline_id AS tli,\n      prev_timeline_id AS prev_tli,\n      full_page_writes,\n      split_part(next_xid, ':', 1) AS next_xid_epoch,\n      split_part(next_xid, ':', 2) AS next_xid,\n      next_oid::BIGINT,\n      next_multixact_id::text::BIGINT,\n      next_multi_offset::text::BIGINT,\n      oldest_xid::text::BIGINT,\n      oldest_xid_dbid::text::BIGINT,\n      oldest_active_xid::text::BIGINT,\n      oldest_multi_xid::text::BIGINT,\n      oldest_multi_dbid::BIGINT,\n      oldest_commit_ts_xid::text::BIGINT,\n      newest_commit_ts_xid::text::BIGINT,\n      checkpoint_time                             AS time,\n      extract(epoch from now() - checkpoint_time) AS elapse\n    FROM pg_control_checkpoint();\n\n  ttl: 60\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - checkpoint_lsn:       { usage: COUNTER ,description: \"Latest checkpoint location\" }\n    - redo_lsn:             { usage: COUNTER ,description: \"Latest checkpoint's REDO location\" }\n    - tli:                  { usage: COUNTER ,description: \"Latest checkpoint's TimeLineID\" }\n    - prev_tli:             { usage: COUNTER ,description: \"Latest checkpoint's PrevTimeLineID\" }\n    - full_page_writes:     { usage: GAUGE   ,description: \"Latest checkpoint's full_page_writes enabled\" }\n    - next_xid_epoch:       { usage: COUNTER ,description: \"Latest checkpoint's NextXID epoch\" }\n    - next_xid:             { usage: COUNTER ,description: \"Latest checkpoint's NextXID xid\" }\n    - next_oid:             { usage: COUNTER ,description: \"Latest checkpoint's NextOID\" }\n    - next_multixact_id:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiXactId\" }\n    - next_multi_offset:    { usage: COUNTER ,description: \"Latest checkpoint's NextMultiOffset\" }\n    - oldest_xid:           { usage: COUNTER ,description: \"Latest checkpoint's oldestXID\" }\n    - oldest_xid_dbid:      { usage: GAUGE   ,description: \"Latest checkpoint's oldestXID's DB OID\" }\n    - oldest_active_xid:    { usage: COUNTER ,description: \"Latest checkpoint's oldestActiveXID\" }\n    - oldest_multi_xid:     { usage: COUNTER ,description: \"Latest checkpoint's oldestMultiXid\" }\n    - oldest_multi_dbid:    { usage: GAUGE   ,description: \"Latest checkpoint's oldestMulti's DB OID\" }\n    - oldest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's oldestCommitTsXid\" }\n    - newest_commit_ts_xid: { usage: COUNTER ,description: \"Latest checkpoint's newestCommitTsXid\" }\n    - time:                 { usage: COUNTER ,description: \"Time of latest checkpoint\" }\n    - elapse:               { usage: GAUGE   ,description: \"Seconds elapsed since latest checkpoint in seconds\" }\n\n\n#==============================================================#\n# 0355 pg_timeline\n#==============================================================#\npg_timeline:\n  name: pg_timeline\n  desc: Current timeline ID from primary or replica\n  query: |\n    SELECT COALESCE(\n      (SELECT received_tli FROM pg_stat_wal_receiver),\n      (SELECT timeline_id FROM pg_control_checkpoint())\n    ) AS id;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - id: { usage: GAUGE ,description: \"Current timeline ID\" }\n\n\n#==============================================================#\n# 0360 pg_recovery\n#==============================================================#\npg_recovery:\n  name: pg_recovery\n  desc: PostgreSQL control recovery metrics (9.6+)\n  query: |\n    SELECT min_recovery_end_timeline    AS min_timeline,\n      min_recovery_end_lsn - '0/0' AS min_lsn,\n      backup_start_lsn - '0/0'     AS backup_start_lsn,\n      backup_end_lsn - '0/0'       AS backup_end_lsn,\n      end_of_backup_record_required AS require_record\n    FROM pg_control_recovery();\n  ttl: 10\n  min_version: 090600\n  tags: [ cluster, replica ]\n  metrics:\n    - min_timeline:      { usage: COUNTER ,description: \"Min recovery ending loc's timeline\" }\n    - min_lsn:           { usage: COUNTER ,description: \"Minimum recovery ending location\" }\n    - backup_start_lsn:  { usage: COUNTER ,description: \"Backup start location\" }\n    - backup_end_lsn:    { usage: COUNTER ,description: \"Backup end location\" }\n    - require_record:    { usage: GAUGE   ,description: \"End-of-backup record required\" }\n\npg_recovery_prefetch:\n  name: pg_recovery_prefetch\n  desc: PostgreSQL recovery prefetch metrics (15+)\n  query: SELECT prefetch,hit,skip_init,skip_new,skip_fpw,skip_rep,wal_distance,block_distance,io_depth,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_recovery_prefetch;\n  ttl: 10\n  min_version: 150000\n  tags: [ cluster, replica ]\n  metrics:\n    - prefetch:       { usage: COUNTER ,description: \"Number of blocks prefetched because they were not in the buffer pool\" }\n    - hit:            { usage: COUNTER ,description: \"Number of blocks not prefetched because they were already in the buffer pool\" }\n    - skip_init:      { usage: COUNTER ,description: \"Number of blocks not prefetched because they would be zero-initialized\" }\n    - skip_new:       { usage: COUNTER ,description: \"Number of blocks not prefetched because they didn't exist yet\" }\n    - skip_fpw:       { usage: COUNTER ,description: \"Number of blocks not prefetched because a full page image was included in the WAL\" }\n    - skip_rep:       { usage: COUNTER ,description: \"Number of blocks not prefetched because they were already recently prefetched\" }\n    - wal_distance:   { usage: GAUGE   ,description: \"How many bytes ahead the prefetcher is looking\" }\n    - block_distance: { usage: GAUGE   ,description: \"How many blocks ahead the prefetcher is looking\" }\n    - io_depth:       { usage: GAUGE   ,description: \"How many prefetches have been initiated but are not yet known to have completed\" }\n    - reset_time:     { usage: GAUGE   ,description: \"Time at which these recovery prefetch statistics were last reset\" }\n\n\n#==============================================================#\n# 0370 pg_slru\n#==============================================================#\npg_slru_13:\n  name: pg_slru\n  desc: PostgreSQL simple-least-recently-used (SLRU) cache statistics v13\n  query: SELECT name, blks_zeroed, blks_hit, blks_read, blks_written, blks_exists, flushes, truncates, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_slru;\n  ttl: 60\n  min_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - name:         { usage: LABEL   ,description: \"Name of the SLRU\" }\n    - blks_zeroed:  { usage: COUNTER ,description: \"Number of blocks zeroed during initializations\" }\n    - blks_hit:     { usage: COUNTER ,description: \"Number of times disk blocks were found already in the SLRU, so that a read was not necessary\" }\n    - blks_read:    { usage: COUNTER ,description: \"Number of disk blocks read for this SLRU\" }\n    - blks_written: { usage: COUNTER ,description: \"Number of disk blocks written for this SLRU\" }\n    - blks_exists:  { usage: COUNTER ,description: \"Number of blocks checked for existence for this SLRU\" }\n    - flushes:      { usage: COUNTER ,description: \"Number of flushes of dirty data for this SLRU\" }\n    - truncates:    { usage: COUNTER ,description: \"Number of truncates for this SLRU\" }\n    - reset_time:   { usage: GAUGE   ,description: \"Time at which these statistics were last reset\" }\n\n\n#==============================================================#\n# 0380 pg_shmem\n#==============================================================#\n# pg_shmem require su privilege to work. Disable it or create auxiliary function with su before use:\n# CREATE OR REPLACE FUNCTION monitor.pg_shmem() RETURNS SETOF pg_shmem_allocations AS $$ SELECT * FROM pg_shmem_allocations;$$ LANGUAGE SQL SECURITY DEFINER;\npg_shmem:\n  name: pg_shmem\n  desc: Allocations made from the server's main shared memory segment\n  query: SELECT coalesce(name, 'Free') AS name, off AS offset, size, allocated_size FROM monitor.pg_shmem();\n  ttl: 60\n  min_version: 130000\n  skip: true            # disable it by default\n  tags: [cluster, \"schema:monitor\" ]\n  metrics:\n    - name:            { usage: LABEL ,description: \"Name of the shared memory allocation\" }\n    - offset:          { usage: GAUGE ,description: \"The offset at which the allocation starts\" }\n    - size:            { usage: GAUGE ,description: \"Size of the allocation\" }\n    - allocated_size:  { usage: GAUGE ,description: \"Size of the allocation including padding\" }\n\n\n#==============================================================#\n# 0390 pg_wal\n#==============================================================#\npg_wal_18:\n  name: pg_wal\n  desc: PostgreSQL WAL statistics since v18 with some col removed\n  query: SELECT wal_records AS records, wal_fpi AS fpi, wal_bytes AS bytes, wal_buffers_full AS buffers_full,extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_wal;\n  ttl: 10\n  tags: [ cluster ]\n  min_version: 180000\n  metrics:\n    - records:      { usage: COUNTER              ,description: \"Total number of WAL records generated\" }\n    - fpi:          { usage: COUNTER              ,description: \"Total number of WAL full page images generated\" }\n    - bytes:        { usage: COUNTER              ,description: \"Total amount of WAL generated in bytes\" }\n    - buffers_full: { usage: COUNTER              ,description: \"Number of times WAL data was written to disk because WAL buffers became full\" }\n    - reset_time:   { usage: GAUGE                ,description: \"When statistics were last reset\" }\n\npg_wal_14:\n  name: pg_wal\n  desc: PostgreSQL WAL statistics since v14\n  query: SELECT wal_records AS records, wal_fpi AS fpi, wal_bytes AS bytes, wal_buffers_full AS buffers_full, wal_write AS write, wal_sync AS sync, wal_write_time AS write_time, wal_sync_time AS sync_time, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_stat_wal;\n  ttl: 10\n  tags: [ cluster ]\n  min_version: 140000\n  max_version: 180000\n  metrics:\n    - records:      { usage: COUNTER              ,description: \"Total number of WAL records generated\" }\n    - fpi:          { usage: COUNTER              ,description: \"Total number of WAL full page images generated\" }\n    - bytes:        { usage: COUNTER              ,description: \"Total amount of WAL generated in bytes\" }\n    - buffers_full: { usage: COUNTER              ,description: \"Number of times WAL data was written to disk because WAL buffers became full\" }\n    - write:        { usage: COUNTER              ,description: \"Number of times WAL buffers were written out to disk via XLogWrite request.\" }\n    - sync:         { usage: COUNTER              ,description: \"Number of times WAL files were synced to disk via issue_xlog_fsync request\" }\n    - write_time:   { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent writing WAL buffers to disk via XLogWrite request in seconds\" }\n    - sync_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total amount of time spent syncing WAL files to disk via issue_xlog_fsync request, in seconds\" }\n    - reset_time:   { usage: GAUGE                ,description: \"When statistics were last reset\" }\n\n\n#==============================================================#\n# 0410 pg_activity\n#==============================================================#\npg_activity:\n  name: pg_activity\n  desc: PostgreSQL backend activity group by database and state\n  query: |-\n    SELECT datname, state, coalesce(count, 0) AS count, coalesce(max_duration, 0) AS max_duration, coalesce(max_tx_duration, 0) AS max_tx_duration, coalesce(max_conn_duration, 0) AS max_conn_duration FROM\n        (SELECT d.datname, a.state FROM pg_database d, unnest(ARRAY ['active','idle','idle in transaction','idle in transaction (aborted)','fastpath function call','disabled']) a(state) WHERE d.datallowconn AND NOT d.datistemplate) base\n          LEFT JOIN (SELECT datname, state, count(*) AS count, max(extract(epoch from now() - state_change)) AS max_duration, max(extract(epoch from now() - xact_start))\n          AS max_tx_duration, max(extract(epoch from now() - backend_start)) AS max_conn_duration FROM pg_stat_activity WHERE pid <> pg_backend_pid() GROUP BY 1,2) data USING (datname,state);\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - state:             { usage: LABEL ,description: \"Current overall state of this backend.\" }\n    - count:             { usage: GAUGE ,description: \"Count of connection among (datname,state)\" }\n    - max_duration:      { usage: GAUGE ,description: \"Max duration since last state change among (datname, state)\" }\n    - max_tx_duration:   { usage: GAUGE ,description: \"Max transaction duration since state change among (datname, state)\" }\n    - max_conn_duration: { usage: GAUGE ,description: \"Max backend session duration since state change among (datname, state)\" }\n\n\n#==============================================================#\n# 0420 pg_wait\n#==============================================================#\npg_wait:\n  name: pg_wait\n  desc: PostgreSQL backend client count group by wait event type since 9.6\n  query: |\n    SELECT coalesce(datname, '_system') AS datname, coalesce(wait_event_type, 'Running') AS event, count(*) AS count FROM pg_stat_activity GROUP BY 1, 2;\n  ttl: 10\n  min_version: 090600\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database, _system for global process\" }\n    - event:   { usage: LABEL ,description: \"Wait event type\" }\n    - count:   { usage: GAUGE ,description: \"Count of WaitEvent on target database\" }\n\n\n#==============================================================#\n# 0430 pg_backend\n#==============================================================#\npg_backend:\n  name: pg_backend\n  desc: PostgreSQL backend client count group by wait event type since 10\n  query: SELECT backend_type AS \"type\", count(*) AS count FROM pg_stat_activity GROUP BY backend_type;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster ]\n  metrics:\n    - type:  { usage: LABEL ,description: \"Database backend process type\" }\n    - count: { usage: GAUGE ,description: \"Database backend process count by backend_type\" }\n\n\n#==============================================================#\n# 0440 pg_xact\n#==============================================================#\npg_xact:\n  name: pg_xact\n  desc: PostgreSQL transaction identifier metrics\n  query: WITH snap(v) AS (SELECT txid_current_snapshot()), xset(v) AS  (SELECT txid_snapshot_xip(v) FROM snap), xnum(v) AS (SELECT count(*) from xset), xmin(v) AS (SELECT txid_snapshot_xmin(v) FROM snap), xmax(v) AS (SELECT txid_snapshot_xmax(v) FROM snap) SELECT xmin.v AS xmin, xmax.v AS xmax, xnum.v AS xnum FROM xmin, xmax, xnum;\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - xmin: { usage: COUNTER ,description: \"Earliest txid that is still active\" }\n    - xmax: { usage: COUNTER ,description: \"First as-yet-unassigned txid. txid >= this are invisible.\" }\n    - xnum: { usage: GAUGE   ,description: \"Current active transaction count\" }\n\n\n#==============================================================#\n# 0450 pg_lock\n#==============================================================#\npg_lock:\n  name: pg_lock\n  desc: PostgreSQL lock distribution by mode and database\n  query: |\n    SELECT datname, mode, coalesce(count, 0) AS count\n      FROM (SELECT d.oid AS database, d.datname, l.mode FROM pg_database d, unnest(ARRAY ['AccessShareLock','RowShareLock','RowExclusiveLock','ShareUpdateExclusiveLock', 'ShareLock','ShareRowExclusiveLock','ExclusiveLock','AccessExclusiveLock']) l(mode) WHERE d.datallowconn AND NOT d.datistemplate) base\n      LEFT JOIN (SELECT database, mode, count(*) AS count FROM pg_locks WHERE database IS NOT NULL GROUP BY 1, 2) cnt USING (database, mode);\n  ttl: 10\n  min_version: 090400\n  tags: [ cluster ]\n  metrics:\n    - datname: { usage: LABEL ,description: \"Name of the database this backend is connected to\" }\n    - mode:    { usage: LABEL ,description: \"Name of the lock mode held or desired by this process\" }\n    - count:   { usage: GAUGE ,description: \"Number of locks of corresponding mode and database\" }\n\n\n#==============================================================#\n# 0460 pg_query\n#==============================================================#\npg_query_17:\n  name: pg_query\n  desc: PostgreSQL Query metrics, require pg_stat_statements installed, 17+\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_exec_time) AS exec_time, sum(shared_blk_read_time) + sum(shared_blk_write_time) AS io_time, sum(wal_bytes) AS wal_bytes\n    ,sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n      FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 170000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - wal_bytes:    { usage: COUNTER ,description: \"Total amount of WAL bytes generated by the statement\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\npg_query_13:\n  name: pg_query\n  desc: PostgreSQL Query metrics, require pg_stat_statements installed, 13 - 16\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_exec_time) AS exec_time, sum(blk_read_time) + sum(blk_write_time) AS io_time, sum(wal_bytes) AS wal_bytes\n    ,sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n      FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 130000\n  max_version: 170000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - wal_bytes:    { usage: COUNTER ,description: \"Total amount of WAL bytes generated by the statement\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\npg_query_10:\n  name: pg_query\n  desc: PostgreSQL query statement metrics, require pg_stat_statements installed, 9.4 ~ 12\n  query: |-\n    SELECT datname, queryid AS query, sum(calls) AS calls, sum(rows) AS rows, sum(total_time) AS exec_time, sum(blk_read_time) + sum(blk_write_time) AS io_time,\n    sum(shared_blks_hit) AS sblk_hit, sum(shared_blks_read) AS sblk_read, sum(shared_blks_dirtied) AS sblk_dirtied, sum(shared_blks_written) AS sblk_written\n    FROM pg_stat_statements(false) s JOIN pg_database d ON s.dbid = d.oid WHERE userid != 10 AND calls > 4 GROUP BY 1, 2 ORDER BY 3 DESC LIMIT 128;\n\n  ttl: 10\n  timeout: 2\n  min_version: 090400\n  max_version: 130000\n  tags: [ cluster, \"extension:pg_stat_statements\" ]\n  metrics:\n    - datname:      { usage: LABEL   ,description: \"Name of database\" }\n    - query:        { usage: LABEL   ,description: \"QueryID generated from internal hash code, computed from the statement's parse tree\" }\n    - calls:        { usage: COUNTER ,description: \"Number of times the statement was executed\" }\n    - rows:         { usage: COUNTER ,description: \"Total number of rows retrieved or affected by the statement\" }\n    - exec_time:    { usage: COUNTER ,scale: 1e-3 ,description: \"Total time spent executing the statement, in seconds\" }\n    - io_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Total time the statement spent reading and writing blocks, in seconds\" }\n    - sblk_hit:     { usage: COUNTER ,description: \"Total number of shared block cache hits by the statement\" }\n    - sblk_read:    { usage: COUNTER ,description: \"Total number of shared blocks read by the statement\" }\n    - sblk_dirtied: { usage: COUNTER ,description: \"Total number of shared blocks dirtied by the statement\" }\n    - sblk_written: { usage: COUNTER ,description: \"Total number of shared blocks written by the statement\" }\n\n\n#==============================================================#\n# 0510 pg_vacuuming\n#==============================================================#\npg_vacuuming_18:\n  name: pg_vacuuming\n  desc: PostgreSQL vacuum progress 18+\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      CASE phase WHEN 'scanning heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_scanned / heap_blks_total ELSE 0.0 END)\n        WHEN 'vacuuming heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_vacuumed / heap_blks_total ELSE 0 END) ELSE NULL END AS progress,\n      indexes_total, indexes_processed, dead_tuple_bytes, delay_time\n    FROM pg_stat_progress_vacuum;\n\n  ttl: 10\n  min_version: 180000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:           { usage: LABEL   ,description: \"database name\" }\n    - pid:               { usage: LABEL   ,description: \"process id of vacuum worker\" }\n    - relname:           { usage: LABEL   ,description: \"relation name of vacuuming table\" }\n    - progress:          { usage: GAUGE   ,description: \"vacuum progress ratio (0-1) based on heap blocks scanned/vacuumed\" }\n    - indexes_total:     { usage: GAUGE   ,description: \"total number of indexes that will be vacuumed or cleaned up\" }\n    - indexes_processed: { usage: GAUGE   ,description: \"number of indexes that have been vacuumed or cleaned up\" }\n    - dead_tuple_bytes:  { usage: GAUGE   ,description: \"total size of dead tuples collected since the beginning of vacuum in bytes\" }\n    - delay_time:        { usage: COUNTER ,scale: 1e-3 ,description: \"total time spent sleeping due to cost-based delay in seconds\" }\n\npg_vacuuming_17:\n  name: pg_vacuuming\n  desc: PostgreSQL vacuum progress 17 (with index progress tracking)\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      CASE phase WHEN 'scanning heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_scanned / heap_blks_total ELSE 0.0 END)\n        WHEN 'vacuuming heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_vacuumed / heap_blks_total ELSE 0 END) ELSE NULL END AS progress,\n      indexes_total, indexes_processed, dead_tuple_bytes\n    FROM pg_stat_progress_vacuum;\n\n  ttl: 10\n  min_version: 170000\n  max_version: 180000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:           { usage: LABEL ,description: \"database name\" }\n    - pid:               { usage: LABEL ,description: \"process id of vacuum worker\" }\n    - relname:           { usage: LABEL ,description: \"relation name of vacuuming table\" }\n    - progress:          { usage: GAUGE ,description: \"vacuum progress ratio (0-1) based on heap blocks scanned/vacuumed\" }\n    - indexes_total:     { usage: GAUGE ,description: \"total number of indexes that will be vacuumed or cleaned up\" }\n    - indexes_processed: { usage: GAUGE ,description: \"number of indexes that have been vacuumed or cleaned up\" }\n    - dead_tuple_bytes:  { usage: GAUGE ,description: \"total size of dead tuples collected since the beginning of vacuum in bytes\" }\n\npg_vacuuming_12:\n  name: pg_vacuuming\n  desc: PostgreSQL vacuum progress 12-16\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      CASE phase WHEN 'scanning heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_scanned / heap_blks_total ELSE 0.0 END)\n        WHEN 'vacuuming heap' THEN (CASE WHEN heap_blks_total > 0 THEN 1.0 * heap_blks_vacuumed / heap_blks_total ELSE 0 END) ELSE NULL END AS progress\n    FROM pg_stat_progress_vacuum;\n\n  ttl: 10\n  min_version: 120000\n  max_version: 170000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:   { usage: LABEL ,description: \"database name\" }\n    - pid:       { usage: LABEL ,description: \"process id of vacuum worker\" }\n    - relname:   { usage: LABEL ,description: \"relation name of vacuuming table\" }\n    - progress:  { usage: GAUGE ,description: \"vacuum progress ratio (0-1) based on heap blocks scanned/vacuumed\" }\n\n\n#==============================================================#\n# 0520 pg_indexing\n#==============================================================#\npg_indexing:\n  name: pg_indexing\n  desc: PostgreSQL index creating progress (v12+)\n  query: |-\n    SELECT datname, pid, relid::RegClass AS relname,\n      (CASE WHEN blocks_total > 0 THEN 1.0 * blocks_done / blocks_total ELSE NULL END) AS blocks,\n      (CASE WHEN tuples_total > 0 THEN 1.0 * tuples_done / tuples_total ELSE NULL END) AS tuples,\n      (CASE WHEN partitions_total > 0 THEN 1.0 * partitions_done / partitions_total ELSE NULL END) AS partitions,\n      (CASE WHEN lockers_total > 0 THEN 1.0 * lockers_done / lockers_total ELSE NULL END) AS lockers\n    FROM pg_stat_progress_create_index pspci;\n\n  ttl: 10\n  min_version: 120000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:     { usage: LABEL ,description: \"Name of the database\" }\n    - pid:         { usage: LABEL ,description: \"Process id of indexing table\" }\n    - relname:     { usage: LABEL ,description: \"Relation name of indexed table\" }\n    - blocks:      { usage: GAUGE ,description: \"Percent of blocks been proceeded\" }\n    - tuples:      { usage: GAUGE ,description: \"Percent of tuples been proceeded\" }\n    - partitions:  { usage: GAUGE ,description: \"Percent of partitions been proceeded\" }\n    - lockers:     { usage: GAUGE ,description: \"Percent of lockers been proceeded\" }\n\n\n#==============================================================#\n# 0530 pg_clustering\n#==============================================================#\npg_clustering:\n  name: pg_clustering\n  desc: PostgreSQL cluster or vacuum full progress (v12+)\n  query: SELECT datname, pid, relid::RegClass AS relname, param4 AS tup_scan, CASE WHEN param6 > 0 THEN 1.0 * param7 / param6 ELSE 0 END AS progress FROM pg_stat_get_progress_info('cluster') s LEFT JOIN pg_database d ON s.datid = d.oid;\n  ttl: 10\n  min_version: 120000\n  tags: [ cluster, primary ]\n  metrics:\n    - datname:     { usage: LABEL ,description: \"Name of database been clustering\" }\n    - pid:         { usage: LABEL ,description: \"Process id of indexing table\" }\n    - relname:     { usage: LABEL ,description: \"Relation name of indexed table\" }\n    - tup_scan:    { usage: GAUGE ,description: \"How much tuple been scanned\" }\n    - progress:    { usage: GAUGE ,description: \"Progress of heap been processed\" }\n\n\n#==============================================================#\n# 0540 pg_backup\n#==============================================================#\npg_backup:\n  name: pg_backup\n  desc: PostgreSQL basebackup progress since 13\n  query: SELECT pid, param1 AS phase, CASE param2 WHEN -1::integer THEN NULL::bigint ELSE param2 END AS total_bytes, param3 AS sent_bytes FROM pg_stat_get_progress_info('BASEBACKUP');\n  ttl: 10\n  min_version: 130000\n  tags: [ cluster ]\n  metrics:\n    - pid:           { usage: LABEL ,description: \"process id of basebackup sender\" }\n    - phase:         { usage: GAUGE ,description: \"Phase encoded in 0~5 initial, wait checkpoint, estimate, streaming, waiting archive, transfer archive\" }\n    - total_bytes:   { usage: GAUGE ,description: \"Total amount of data that will be streamed\" }\n    - sent_bytes:    { usage: GAUGE ,description: \"Amount of data streamed\" }\n\n\n#==============================================================#\n# 0610 pg_db\n#==============================================================#\npg_db_18:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v18\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total,blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,coalesce(checksum_failures, -1) AS cks_fails, checksum_last_failure AS cks_fail_time,blk_read_time,blk_write_time,\n      session_time,active_time,idle_in_transaction_time AS ixact_time,sessions,sessions_abandoned,sessions_fatal,sessions_killed,parallel_workers_to_launch,parallel_workers_launched,\n      extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n\n  ttl: 10\n  min_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - cks_fails:           { usage: COUNTER ,description: \"Number of data page checksum failures detected in this database, -1 for not enabled\" }\n    - cks_fail_time:       { usage: GAUGE   ,description: \"Time at which the last data page checksum failure was detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - session_time:        { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent by database sessions in this database, in seconds\" }\n    - active_time:         { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent executing SQL statements in this database, in seconds\" }\n    - ixact_time:          { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent idling while in a transaction in this database, in seconds\" }\n    - sessions:            { usage: COUNTER ,description: \"Total number of sessions established to this database\" }\n    - sessions_abandoned:  { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated because connection to the client was lost\" }\n    - sessions_fatal:      { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by fatal errors\" }\n    - sessions_killed:     { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by operator intervention\" }\n    - parallel_workers_to_launch: { usage: COUNTER ,description: \"Number of parallel workers planned to be launched by queries on this database\" }\n    - parallel_workers_launched:  { usage: COUNTER ,description: \"Number of parallel workers launched by queries on this database\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\npg_db_14:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v14 (with 7 new time & session metrics)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total,blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,coalesce(checksum_failures, -1) AS cks_fails, checksum_last_failure AS cks_fail_time,blk_read_time,blk_write_time,\n      session_time,active_time,idle_in_transaction_time AS ixact_time,sessions,sessions_abandoned,sessions_fatal,sessions_killed,extract(EPOCH FROM stats_reset) AS reset_time\n    FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n\n  ttl: 10\n  min_version: 140000\n  max_version: 180000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - cks_fails:           { usage: COUNTER ,description: \"Number of data page checksum failures detected in this database, -1 for not enabled\" }\n    - cks_fail_time:       { usage: GAUGE   ,description: \"Time at which the last data page checksum failure was detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - session_time:        { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent by database sessions in this database, in seconds\" }\n    - active_time:         { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent executing SQL statements in this database, in seconds\" }\n    - ixact_time:          { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent idling while in a transaction in this database, in seconds\" }\n    - sessions:            { usage: COUNTER ,description: \"Total number of sessions established to this database\" }\n    - sessions_abandoned:  { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated because connection to the client was lost\" }\n    - sessions_fatal:      { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by fatal errors\" }\n    - sessions_killed:     { usage: COUNTER ,description: \"Number of database sessions to this database that were terminated by operator intervention\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\n\npg_db_12:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v12 v13 (with 2 new checksum metrics)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total,blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,coalesce(checksum_failures, -1) AS cks_fails, checksum_last_failure AS cks_fail_time,blk_read_time,blk_write_time,\n      extract(EPOCH FROM stats_reset) AS reset_time FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n\n  ttl: 10\n  min_version: 120000\n  max_version: 140000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - cks_fails:           { usage: COUNTER ,description: \"Number of data page checksum failures detected in this database, -1 for not enabled\" }\n    - cks_fail_time:       { usage: GAUGE   ,description: \"Time at which the last data page checksum failure was detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\npg_db_10:\n  name: pg_db\n  desc: PostgreSQL database stats from pg_stat_database v10 v11 (actually since 9.2)\n  query: |-\n    SELECT d.datname, datid,age(datfrozenxid) AS age, datistemplate AS is_template, datallowconn AS allow_conn, datconnlimit AS conn_limit, datfrozenxid::TEXT::BIGINT as frozen_xid,\n      numbackends,xact_commit,xact_rollback,xact_rollback + xact_commit AS xact_total, blks_read,blks_hit,blks_read + blks_hit AS blks_access,tup_returned,tup_fetched,tup_inserted,tup_updated,tup_deleted,tup_inserted + tup_updated + tup_deleted AS tup_modified,\n      conflicts,temp_files,temp_bytes,deadlocks,blk_read_time,blk_write_time, extract(EPOCH FROM stats_reset) AS reset_time FROM pg_database d JOIN pg_stat_database sd ON d.oid = sd.datid;\n  ttl: 10\n  min_version: 090200\n  max_version: 120000\n  tags: [ cluster ]\n  metrics:\n    - datname:             { usage: LABEL   ,description: \"Name of the database\" }\n    - datid:               { usage: GAUGE   ,description: \"OID of the database\" }\n    - age:                 { usage: GAUGE   ,description: \"Age of database calculated from datfrozenxid\" }\n    - is_template:         { usage: GAUGE   ,description: \"If true(1), then this database can be cloned by any user with CREATEDB privileges\" }\n    - allow_conn:          { usage: GAUGE   ,description: \"If false(0) then no one can connect to this database.\" }\n    - conn_limit:          { usage: GAUGE   ,description: \"Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.\" }\n    - frozen_xid:          { usage: GAUGE   ,description: \"All transaction IDs before this one have been frozen\" }\n    - numbackends:         { usage: GAUGE   ,description: \"Number of backends currently connected to this database\" }\n    - xact_commit:         { usage: COUNTER ,description: \"Number of transactions in this database that have been committed\" }\n    - xact_rollback:       { usage: COUNTER ,description: \"Number of transactions in this database that have been rolled back\" }\n    - xact_total:          { usage: COUNTER ,description: \"Number of transactions in this database\" }\n    - blks_read:           { usage: COUNTER ,description: \"Number of disk blocks read in this database\" }\n    - blks_hit:            { usage: COUNTER ,description: \"Number of times disk blocks were found already in the buffer cache\" }\n    - blks_access:         { usage: COUNTER ,description: \"Number of times disk blocks that accessed read+hit\" }\n    - tup_returned:        { usage: COUNTER ,description: \"Number of rows returned by queries in this database\" }\n    - tup_fetched:         { usage: COUNTER ,description: \"Number of rows fetched by queries in this database\" }\n    - tup_inserted:        { usage: COUNTER ,description: \"Number of rows inserted by queries in this database\" }\n    - tup_updated:         { usage: COUNTER ,description: \"Number of rows updated by queries in this database\" }\n    - tup_deleted:         { usage: COUNTER ,description: \"Number of rows deleted by queries in this database\" }\n    - tup_modified:        { usage: COUNTER ,description: \"Number of rows modified by queries in this database\" }\n    - conflicts:           { usage: COUNTER ,description: \"Number of queries canceled due to conflicts with recovery in this database\" }\n    - temp_files:          { usage: COUNTER ,description: \"Number of temporary files created by queries in this database\" }\n    - temp_bytes:          { usage: COUNTER ,description: \"Total amount of data written to temporary files by queries in this database.\" }\n    - deadlocks:           { usage: COUNTER ,description: \"Number of deadlocks detected in this database\" }\n    - blk_read_time:       { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent reading data file blocks by backends in this database, in seconds\" }\n    - blk_write_time:      { usage: COUNTER ,scale: 1e-3 ,description: \"Time spent writing data file blocks by backends in this database, in seconds\" }\n    - reset_time:          { usage: GAUGE   ,description: \"Time at which database statistics were last reset\" }\n\n\n#==============================================================#\n# 0620 pg_db_confl\n#==============================================================#\n# https://pgpedia.info/p/pg_stat_database_conflicts.html\n\npg_db_confl_16:\n  name: pg_db_confl\n  desc: PostgreSQL database conflicts metrics for PG16+\n  query: SELECT * FROM pg_stat_database_conflicts;\n  ttl: 10\n  min_version: 160000\n  tags: [ cluster, replica ]\n  metrics:\n    - datid:                { usage: DISCARD }\n    - datname:              { usage: LABEL   ,description: \"Name of this database\" }\n    - confl_tablespace:     { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to dropped tablespaces\" }\n    - confl_lock:           { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to lock timeouts\" }\n    - confl_snapshot:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to old snapshots\" }\n    - confl_bufferpin:      { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to pinned buffers\" }\n    - confl_deadlock:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to deadlocks\" }\n    - confl_active_logicalslot: { usage: COUNTER ,description: \"Number of uses of logical slots in this database that have been canceled due to old snapshots or too low a wal_level on the primary\" }\n\npg_db_confl_15:\n  name: pg_db_confl\n  desc: PostgreSQL database conflicts metrics for pg 9.1 - 15\n  query: SELECT * FROM pg_stat_database_conflicts;\n  ttl: 10\n  min_version: 90100\n  max_version: 160000\n  tags: [ cluster, replica ]\n  metrics:\n    - datid:                { usage: DISCARD }\n    - datname:              { usage: LABEL   ,description: \"Name of this database\" }\n    - confl_tablespace:     { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to dropped tablespaces\" }\n    - confl_lock:           { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to lock timeouts\" }\n    - confl_snapshot:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to old snapshots\" }\n    - confl_bufferpin:      { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to pinned buffers\" }\n    - confl_deadlock:       { usage: COUNTER ,description: \"Number of queries in this database that have been canceled due to deadlocks\" }\n\n\n#==============================================================#\n# 0640 pg_pubrel\n#==============================================================#\npg_pubrel:\n  name: pg_pubrel\n  desc: PostgreSQL publication and relation count\n  query: SELECT CURRENT_CATALOG AS datname, pubname, count(*) AS count FROM pg_publication p, LATERAL pg_get_publication_tables(pubname) GROUP BY pubname;\n  ttl: 10\n  min_version: 100000\n  metrics:\n    - datname:              { usage: LABEL  ,description: \"Name of the database which publication belonged\" }\n    - pubname:              { usage: LABEL  ,description: \"Name of the publication\" }\n    - count:                { usage: GAUGE  ,description: \"Count of relation in the publication\" }\n\n\n#==============================================================#\n# 0650 pg_subrel\n#==============================================================#\npg_subrel:\n  name: pg_subrel\n  desc: PostgreSQL subscripted relation group by state\n  query: SELECT CURRENT_CATALOG AS datname, subname, srsubstate::TEXT AS state, count(*) AS count FROM pg_subscription_rel sr LEFT JOIN pg_stat_subscription  ss ON sr.srsubid = ss.subid GROUP BY 2, 3;\n  ttl: 10\n  min_version: 100000\n  metrics:\n    - datname:              { usage: LABEL  ,description: \"Name of the database which publication belonged\" }\n    - subname:              { usage: LABEL  ,description: \"Name of the subscription\" }\n    - state:                { usage: LABEL  ,description: \"State of table in subscription, i=initialize, d=data copy, s=sync, r=ready\" }\n    - count:                { usage: GAUGE  ,description: \"Count of relation in this subscription and corresponding state\" }\n\n\n#==============================================================#\n# 0700 pg_table\n#==============================================================#\npg_table_18:\n  name: pg_table\n  desc: PostgreSQL table metrics v18+\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_tup_newpage_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.n_ins_since_vacuum,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,psut.last_seq_scan,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psut.total_vacuum_time AS vacuum_time,psut.total_autovacuum_time AS autovacuum_time,psut.total_analyze_time AS analyze_time,psut.total_autoanalyze_time AS autoanalyze_time,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 180000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_tup_newpage_upd:   { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated where the successor version goes onto a new heap page\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - n_ins_since_vacuum:  { usage: GAUGE                 ,description: \"Estimated number of rows inserted since this table was last vacuumed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - last_seq_scan:       { usage: DISCARD               ,description: \"The timestamp of the last seq scan on this table\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - vacuum_time:        { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been manually vacuumed, in seconds\" }\n    - autovacuum_time:    { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been vacuumed by the autovacuum daemon, in seconds\" }\n    - analyze_time:       { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been manually analyzed, in seconds\" }\n    - autoanalyze_time:   { usage: COUNTER   ,default: 0  ,scale: 1e-3 ,description: \"Total time this table has been analyzed by the autovacuum daemon, in seconds\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_16:\n  name: pg_table\n  desc: PostgreSQL table metrics 16-17\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_tup_newpage_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.n_ins_since_vacuum,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,psut.last_seq_scan,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 160000\n  max_version: 180000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_tup_newpage_upd:   { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated where the successor version goes onto a new heap page\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - n_ins_since_vacuum:  { usage: GAUGE                 ,description: \"Estimated number of rows inserted since this table was last vacuumed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - last_seq_scan:       { usage: DISCARD               ,description: \"The timestamp of the last seq scan on this table\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_13:\n  name: pg_table\n  desc: PostgreSQL table metrics 13-15 (with n_ins_since_vacuum)\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.n_ins_since_vacuum,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 130000\n  max_version: 160000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - n_ins_since_vacuum:  { usage: GAUGE                 ,description: \"Estimated number of rows inserted since this table was last vacuumed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\npg_table_10:\n  name: pg_table\n  desc: PostgreSQL table metrics 9.4-12\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || c.relname AS relname, c.oid AS relid, ascii(c.relkind) AS kind,\n       c.relpages AS pages, c.reltuples AS tuples, c.relfrozenxid AS frozenxid, age(c.relfrozenxid) AS age, c.relnatts AS ncols,\n       psut.seq_scan,psut.seq_tup_read,psut.idx_scan,psut.idx_tup_fetch,psut.seq_scan + psut.idx_scan AS tbl_scan, psut.seq_tup_read + psut.idx_tup_fetch AS tup_read,\n       psut.n_tup_ins,psut.n_tup_upd,psut.n_tup_del,(psut.n_tup_ins + psut.n_tup_upd + psut.n_tup_del) AS n_tup_mod,psut.n_tup_hot_upd,psut.n_live_tup,psut.n_dead_tup,\n       psut.n_mod_since_analyze,psut.last_vacuum,psut.last_autovacuum,psut.last_analyze,psut.last_autoanalyze,\n       psut.vacuum_count,psut.autovacuum_count,psut.analyze_count,psut.autoanalyze_count,\n       psio.heap_blks_read,psio.heap_blks_hit,psio.idx_blks_read,psio.idx_blks_hit,psio.toast_blks_read,psio.toast_blks_hit,psio.tidx_blks_read,psio.tidx_blks_hit\n    FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid\n        LEFT JOIN pg_stat_user_tables psut ON psut.relid = c.oid LEFT JOIN pg_statio_user_tables psio ON psio.relid = c.oid\n    WHERE nsp.nspname !~ '^pg_' AND nsp.nspname !~ '^_' AND nsp.nspname !~ '^timescaledb' AND nsp.nspname !~ '^citus' AND nsp.nspname !~ '^columnar'\n        AND nsp.nspname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor') AND c.relkind = ANY (ARRAY ['r','m','t','p'])\n    ORDER BY c.relpages DESC LIMIT 256;\n\n  ttl: 10\n  timeout: 2\n  min_version: 090400\n  max_version: 130000\n  metrics:\n    - datname:             { usage: LABEL                 ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL                 ,description: \"Relation name of this table\" }\n    - relid:               { usage: GAUGE                 ,description: \"Relation oid of this table\" }\n    - kind:                { usage: GAUGE                 ,description: \"Relation kind r/table/114,m/mview/109,t/toast/116,p/partitioned/112\" }\n    - pages:               { usage: GAUGE                 ,description: \"Size of the on-disk representation of this table in pages\" }\n    - tuples:              { usage: GAUGE                 ,description: \"Estimated number of rows in this table\" }\n    - frozenxid:           { usage: GAUGE                 ,description: \"All txid before this have been frozen on this table\" }\n    - age:                 { usage: GAUGE                 ,description: \"Age of this table in vacuum cycles\" }\n    - ncols:               { usage: GAUGE                 ,description: \"Number of columns in the table\" }\n    - seq_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of sequential scans initiated on this table\" }\n    - seq_tup_read:        { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by sequential scans\" }\n    - idx_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of index scans initiated on this table\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by index scans\" }\n    - tbl_scan:            { usage: COUNTER  ,default: 0  ,description: \"Number of scans initiated on this table\" }\n    - tup_read:            { usage: COUNTER  ,default: 0  ,description: \"Number of live rows fetched by scans\" }\n    - n_tup_ins:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows inserted\" }\n    - n_tup_upd:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows updated (includes HOT updated rows)\" }\n    - n_tup_del:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows deleted\" }\n    - n_tup_mod:           { usage: COUNTER  ,default: 0  ,description: \"Number of rows modified (insert + update + delete)\" }\n    - n_tup_hot_upd:       { usage: COUNTER  ,default: 0  ,description: \"Number of rows HOT updated (i.e with no separate index update required)\" }\n    - n_live_tup:          { usage: GAUGE                 ,description: \"Estimated number of live rows\" }\n    - n_dead_tup:          { usage: GAUGE                 ,description: \"Estimated number of dead rows\" }\n    - n_mod_since_analyze: { usage: GAUGE                 ,description: \"Estimated number of rows modified since this table was last analyzed\" }\n    - last_vacuum:         { usage: DISCARD               ,description: \"Last time at which this table was manually vacuumed (not counting VACUUM FULL)\" }\n    - last_autovacuum:     { usage: DISCARD               ,description: \"Last time at which this table was vacuumed by the autovacuum daemon\" }\n    - last_analyze:        { usage: DISCARD               ,description: \"Last time at which this table was manually analyzed\" }\n    - last_autoanalyze:    { usage: DISCARD               ,description: \"Last time at which this table was analyzed by the autovacuum daemon\" }\n    - vacuum_count:        { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually vacuumed (not counting VACUUM FULL)\" }\n    - autovacuum_count:    { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been vacuumed by the autovacuum daemon\" }\n    - analyze_count:       { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been manually analyzed\" }\n    - autoanalyze_count:   { usage: COUNTER  ,default: 0  ,description: \"Number of times this table has been analyzed by the autovacuum daemon\" }\n    - heap_blks_read:      { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from this table\" }\n    - heap_blks_hit:       { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in this table\" }\n    - idx_blks_read:       { usage: COUNTER  ,default: 0  ,description: \"Number of disk blocks read from all indexes on this table\" }\n    - idx_blks_hit:        { usage: COUNTER  ,default: 0  ,description: \"Number of buffer hits in all indexes on this table\" }\n    - toast_blks_read:     { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table (if any)\" }\n    - toast_blks_hit:      { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table (if any)\" }\n    - tidx_blks_read:      { usage: DISCARD  ,default: 0  ,description: \"Number of disk blocks read from this table's TOAST table indexes (if any)\" }\n    - tidx_blks_hit:       { usage: DISCARD  ,default: 0  ,description: \"Number of buffer hits in this table's TOAST table indexes (if any)\" }\n\n\n#==============================================================#\n# 0710 pg_index\n#==============================================================#\npg_index:\n  name: pg_index\n  desc: PostgreSQL index metrics\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, schemaname || '.' || indexrelname AS idxname, schemaname || '.' || relname AS relname ,indexrelid AS relid,\n        relpages, reltuples, idx_scan, idx_tup_read, idx_tup_fetch, idx_blks_read, idx_blks_hit\n    FROM pg_stat_user_indexes psui, LATERAL (SELECT idx_blks_read, idx_blks_hit FROM pg_statio_user_indexes psio WHERE psio.indexrelid = psui.indexrelid LIMIT 1) p2,\n        LATERAL (SELECT relpages,reltuples FROM pg_class c WHERE c.oid = psui.indexrelid LIMIT 1) p3\n    WHERE schemaname !~ '^pg_' AND schemaname !~ '^_' AND schemaname !~ '^timescaledb' AND schemaname !~ '^citus' AND schemaname !~ '^columnar' AND schemaname NOT IN ('pg_catalog','information_schema','pg_toast','repack','monitor')\n    ORDER BY idx_tup_read DESC LIMIT 512;\n\n  ttl: 10\n  timeout: 1\n  min_version: 090400\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - idxname:             { usage: LABEL    ,description: \"Name of this index (full-qualified schema name)\" }\n    - relname:             { usage: LABEL    ,description: \"Name of the table for this index (full-qualified schema name)\" }\n    - relid:               { usage: LABEL    ,description: \"Relation oid of this index\" }\n    - relpages:            { usage: GAUGE    ,description: \"Size of the on-disk representation of this index in pages\" }\n    - reltuples:           { usage: GAUGE    ,description: \"Estimate relation tuples\" }\n    - idx_scan:            { usage: COUNTER  ,description: \"Number of index scans initiated on this index\" }\n    - idx_tup_read:        { usage: COUNTER  ,description: \"Number of index entries returned by scans on this index\" }\n    - idx_tup_fetch:       { usage: COUNTER  ,description: \"Number of live table rows fetched by simple index scans using this index\" }\n    - idx_blks_read:       { usage: COUNTER  ,description: \"Number of disk blocks read from this index\" }\n    - idx_blks_hit:        { usage: COUNTER  ,description: \"Number of buffer hits in this index\" }\n\n\n#==============================================================#\n# 0720 pg_func\n#==============================================================#\npg_func:\n  desc: PostgreSQL function metrics\n  query: SELECT CURRENT_CATALOG AS datname, schemaname || '.' || funcname AS funcname, sum(calls) AS calls, sum(total_time) AS total_time, sum(self_time) AS self_time FROM pg_stat_user_functions GROUP BY 2 ORDER BY 4 DESC LIMIT 128;\n  ttl: 10\n  min_version: 090400\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Name of belonged database\" }\n    - funcname:            { usage: LABEL    ,description: \"Name of this function, may have multiple override\" }\n    - calls:               { usage: COUNTER  ,description: \"Number of times this function has been called\" }\n    - total_time:          { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function and all other functions called by it, in seconds\" }\n    - self_time:           { usage: COUNTER  ,scale: 1e-3 ,description: \"Total time spent in this function itself, not including other functions called by it, in seconds\" }\n\n\n#==============================================================#\n# 0730 pg_seq\n#==============================================================#\npg_seq:\n  desc: PostgreSQL sequence metrics\n  query: SELECT CURRENT_CATALOG AS datname, schemaname || '.' || sequencename AS seqname, last_value, blks_read, blks_hit FROM pg_sequences s, LATERAL (SELECT relid, blks_read, blks_hit FROM pg_statio_all_sequences sio WHERE s.schemaname = sio.schemaname AND s.sequencename = sio.relname LIMIT 1) d LIMIT 128;\n  ttl: 10\n  min_version: 100000\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this sequence\" }\n    - seqname:             { usage: LABEL    ,description: \"Fully schema qualified sequence name\" }\n    - last_value:          { usage: COUNTER  ,description: \"The last sequence value written to disk\" }\n    - blks_read:           { usage: COUNTER  ,description: \"Number of disk blocks read from this sequence\" }\n    - blks_hit:            { usage: COUNTER  ,description: \"Number of buffer hits in this sequence\" }\n\n\n#==============================================================#\n# 0740 pg_relkind\n#==============================================================#\npg_relkind:\n  name: pg_relkind\n  desc: Postgres relation count by kind (category, r,i,m,t,...)\n  query: SELECT CURRENT_CATALOG AS datname, relkind, count(*) AS count FROM pg_class GROUP BY relkind;\n  ttl: 60\n  timeout: 1\n  min_version: 090400\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Name of database\" }\n    - relkind:             { usage: LABEL    ,description: \"Kind of this relation, could be r,i,S,t,v,m,c,f,p,I\" }\n    - count:               { usage: GAUGE    ,description: \"Number of relations of corresponding relkind\" }\n\n\n#==============================================================#\n# 0750 pg_defpart\n#==============================================================#\npg_defpart:\n  name: pg_defpart\n  desc: PostgreSQL default partition tuples\n  query: SELECT CURRENT_CATALOG AS datname, relnamespace::RegNamespace || '.' || relname AS relname, reltuples AS tuples FROM pg_class WHERE relpartbound IS NOT NULL AND pg_catalog.pg_get_expr(relpartbound, oid) = 'DEFAULT' ORDER BY reltuples DESC LIMIT 64;\n  ttl: 60\n  timeout: 1\n  min_version: 110000\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this default partition\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified default partition relation name\" }\n    - tuples:              { usage: GAUGE    ,description: \"Number of tuples in this default partition\" }\n\n\n#==============================================================#\n# 0810 pg_table_size\n#==============================================================#\npg_table_size:\n  desc: PostgreSQL table size metrics, quite slow\n  query: |-\n    SELECT CURRENT_CATALOG AS datname, nsp.nspname || '.' || rel.relname AS relname,\n       pg_total_relation_size(rel.oid)       AS bytes,\n       pg_relation_size(rel.oid)             AS relsize,\n       pg_indexes_size(rel.oid)              AS indexsize,\n       pg_total_relation_size(reltoastrelid) AS toastsize\n    FROM pg_namespace nsp JOIN pg_class rel ON nsp.oid = rel.relnamespace\n    WHERE nspname <> ALL(ARRAY['pg_catalog', 'information_schema']) AND rel.relkind = 'r'\n    ORDER BY 3 DESC NULLS LAST LIMIT 256;\n\n  ttl: 300\n  timeout: 2\n  min_version: 100000\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified table name\" }\n    - bytes:               { usage: GAUGE    ,default: 0  ,description: \"Total bytes of this table (including toast, index, toast index)\" }\n    - relsize:             { usage: GAUGE    ,default: 0  ,description: \"Bytes of this table itself (main, vm, fsm)\" }\n    - indexsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of all related indexes of this table\" }\n    - toastsize:           { usage: GAUGE    ,default: 0  ,description: \"Bytes of toast tables of this table\" }\n\n\n#==============================================================#\n# 0820 pg_table_bloat\n#==============================================================#\n# pg_table_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_table_bloat:\n  name: pg_table_bloat\n  desc: PostgreSQL table bloat metrics, require auxiliary view pg_table_bloat to work\n  query: SELECT datname, nspname || '.' || relname AS relname, size, ratio FROM pg_table_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 090400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this table\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified name of this table\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this table\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this table from 0 to 1\" }\n\n\n#==============================================================#\n# 0830 pg_index_bloat\n#==============================================================#\n# pg_index_bloat require auxiliary view to work. Disable it or create auxiliary view before use:\npg_index_bloat:\n  name: pg_index_bloat\n  desc: PostgreSQL index bloat metrics (btree only), require pg_index_bloat\n  query: SELECT datname, nspname || '.' || relname AS relname, size, ratio FROM pg_index_bloat ORDER BY size DESC LIMIT 64;\n  ttl: 300\n  timeout: 2\n  min_version: 090400\n  skip: true\n  metrics:\n    - datname:             { usage: LABEL    ,description: \"Database name of this index\" }\n    - relname:             { usage: LABEL    ,description: \"Schema qualified index name\" }\n    - size:                { usage: GAUGE    ,description: \"Total bytes of this index\" }\n    - ratio:               { usage: GAUGE    ,description: \"Estimated bloat ratio of this index, 0~1\" }\n\n\n#==============================================================#\n# 0910 pgbouncer_list\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-lists\npgbouncer_list:\n  name: pgbouncer_list\n  desc: Pgbouncer entry list\n  query: SHOW LISTS;\n  ttl: 10\n  min_version: 10800\n  fatal: true\n  tags: [ pgbouncer ]\n  metrics:\n    - list:                { usage: LABEL                 ,description: \"Pgbouncer internal list name\" }\n    - items:               { usage: GAUGE                 ,description: \"Number of corresponding pgbouncer object\" }\n\n\n#==============================================================#\n# 0920 pgbouncer_database\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-databases\npgbouncer_database_124:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (since 1.24)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                       { usage: LABEL  ,rename: datname       ,description: \"Name of configured database entry\" }\n    - host:                       { usage: LABEL                         ,description: \"Host that pgbouncer will connects to\" }\n    - port:                       { usage: LABEL                         ,description: \"Port that pgbouncer will connects to\" }\n    - database:                   { usage: LABEL  ,rename: real_datname  ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:                 { usage: DISCARD }\n    - pool_size:                  { usage: GAUGE                         ,description: \"Maximum number of server connections\" }\n    - min_pool_size:              { usage: GAUGE                         ,description: \"Minimum number of server connections\" }\n    - reserve_pool_size:          { usage: GAUGE  ,rename: reserve_pool  ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:            { usage: GAUGE                         ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:                  { usage: DISCARD }\n    - load_balance_hosts:         { usage: DISCARD }\n    - max_connections:            { usage: GAUGE                         ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections:        { usage: GAUGE                         ,description: \"Current number of connections for this database\" }\n    - max_client_connections:     { usage: GAUGE                         ,description: \"Maximum number of allowed client connections for this pgbouncer instance\" }\n    - current_client_connections: { usage: GAUGE                         ,description: \"Current number of client connections for this database\" }\n    - paused:                     { usage: GAUGE                         ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:                   { usage: GAUGE                         ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_123:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats 1.23\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - server_lifetime:     { usage: GAUGE                       ,description: \"The maximum lifetime of a server connection for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_116:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.16-1.22)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 11600\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - min_pool_size:       { usage: GAUGE                       ,description: \"Minimum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\npgbouncer_database_108:\n  name: pgbouncer_database\n  desc: Pgbouncer database stats (1.08-1.15)\n  query: SHOW DATABASES;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - name:                { usage: LABEL ,rename: datname      ,description: \"Name of configured database entry\" }\n    - host:                { usage: LABEL                       ,description: \"Host that pgbouncer will connects to\" }\n    - port:                { usage: LABEL                       ,description: \"Port that pgbouncer will connects to\" }\n    - database:            { usage: LABEL ,rename: real_datname ,description: \"The real database name pgbouncer connects to\" }\n    - force_user:          { usage: DISCARD }\n    - pool_size:           { usage: GAUGE                       ,description: \"Maximum number of server connections\" }\n    - reserve_pool:        { usage: GAUGE                       ,description: \"Maximum number of additional connections for this database\" }\n    - pool_mode:           { usage: DISCARD }\n    - max_connections:     { usage: GAUGE                       ,description: \"Maximum number of allowed connections for this database\" }\n    - current_connections: { usage: GAUGE                       ,description: \"Current number of connections for this database\" }\n    - paused:              { usage: GAUGE                       ,description: \"True(1) if this database is currently paused, else 0\" }\n    - disabled:            { usage: GAUGE                       ,description: \"True(1) if this database is currently disabled, else 0\" }\n\n\n#==============================================================#\n# 0930 pgbouncer_stat\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-stats\npgbouncer_stat_124:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (since 1.24)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - total_client_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created by clients\" }\n    - total_server_parse_count:      { usage: COUNTER                  ,description: \"Total number of prepared statements created on a server.\" }\n    - total_bind_count:              { usage: COUNTER                  ,description: \"Total number of prepared statements readied for execution by clients and forwarded to postgres\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n    - avg_client_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created by clients\" }\n    - avg_server_parse_count:        { usage: GAUGE                    ,description: \"Average number of prepared statements created on a server.\" }\n    - avg_bind_count:                { usage: GAUGE                    ,description: \"Average number of prepared statements readied for execution by clients and forwarded to postgres\" }\n\npgbouncer_stat_123:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.23)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 12300\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_server_assignment_count: { usage: COUNTER                  ,description: \"Total times a server was assigned to a client\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_server_assignment_count:   { usage: GAUGE                    ,description: \"Average number of times a server as assigned to a client per second in the last stat period.\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\npgbouncer_stat_108:\n  name: pgbouncer_stat\n  desc: Pgbouncer stats per database (1.08 - 1.22)\n  query: SHOW STATS;\n  ttl: 10\n  min_version: 10800\n  max_version: 12300\n  tags: [ pgbouncer ]\n  metrics:\n    - database:                      { usage: LABEL   ,rename: datname ,description: \"Name of database\" }\n    - total_xact_count:              { usage: COUNTER                  ,description: \"Total number of SQL transactions pooled by pgbouncer\" }\n    - total_query_count:             { usage: COUNTER                  ,description: \"Total number of SQL queries pooled by pgbouncer\" }\n    - total_received:                { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic received by pgbouncer\" }\n    - total_sent:                    { usage: COUNTER                  ,description: \"Total volume in bytes of network traffic sent by pgbouncer\" }\n    - total_xact_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when in a transaction\" }\n    - total_query_time:              { usage: COUNTER ,scale: 1e-6     ,description: \"Total number of seconds spent when executing queries\" }\n    - total_wait_time:               { usage: COUNTER ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds\" }\n    - avg_xact_count:                { usage: GAUGE                    ,description: \"Average transactions per second in last stat period\" }\n    - avg_query_count:               { usage: GAUGE                    ,description: \"Average queries per second in last stat period\" }\n    - avg_recv:                      { usage: GAUGE                    ,description: \"Average received (from clients) bytes per second\" }\n    - avg_sent:                      { usage: GAUGE                    ,description: \"Average sent (to clients) bytes per second\" }\n    - avg_xact_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Average transaction duration, in seconds\" }\n    - avg_query_time:                { usage: GAUGE   ,scale: 1e-6     ,description: \"Average query duration, in seconds\" }\n    - avg_wait_time:                 { usage: GAUGE   ,scale: 1e-6     ,description: \"Time spent by clients waiting for a server, in seconds (average per second).\" }\n\n\n#==============================================================#\n# 0940 pgbouncer_pool\n#==============================================================#\n# http://www.pgbouncer.org/usage.html#show-pools\npgbouncer_pool_124:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.24+)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n    - load_balance_hosts:    { usage: LABEL,                                 description: \"The load_balance_hosts in use\" }\n\npgbouncer_pool_118:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.18-1.23)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11800\n  max_version: 12400\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,                description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                                 description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,         description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,        description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_active_cancel_req:  { usage: GAUGE, rename: active_cancel_clients,  description: \"Client connections that have forwarded query cancellations to the server and are waiting for the server response.\" }\n    - cl_waiting_cancel_req: { usage: GAUGE, rename: cancel_clients,         description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,         description: \"Server connections that are linked to a client\" }\n    - sv_active_cancel:      { usage: GAUGE, rename: active_cancel_servers,  description: \"Server connections that are currently forwarding a cancel request\" }\n    - sv_being_canceled:     { usage: GAUGE, rename: cancel_servers,         description: \"cancel requests have completed that were sent to cancel a query on this server\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,           description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,           description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,         description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,          description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                                 description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                                 description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                                 description: \"Pooling mode in use\" }\n\npgbouncer_pool_116:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.16-1.17)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 11600\n  max_version: 11800\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - cl_cancel_req:         { usage: GAUGE, rename: cancel_clients,   description: \"Client connections that have not forwarded query cancellations to the server yet.\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\npgbouncer_pool_108:\n  name: pgbouncer_pool\n  desc: Pgbouncer pool stats (1.08-1.15)\n  query: SHOW POOLS;\n  ttl: 10\n  min_version: 10800\n  max_version: 11600\n  tags: [ pgbouncer ]\n  metrics:\n    - database:              { usage: LABEL, rename: datname,          description: \"Database name of this pool\" }\n    - user:                  { usage: LABEL,                           description: \"User name of this pool\" }\n    - cl_active:             { usage: GAUGE, rename: active_clients,   description: \"Client connections that are linked to server connection and can process queries\" }\n    - cl_waiting:            { usage: GAUGE, rename: waiting_clients,  description: \"Client connections that have sent queries but have not yet got a server connection\" }\n    - sv_active:             { usage: GAUGE, rename: active_servers,   description: \"Server connections that are linked to a client\" }\n    - sv_idle:               { usage: GAUGE, rename: idle_servers,     description: \"Server connections that are unused and immediately usable for client queries\" }\n    - sv_used:               { usage: GAUGE, rename: used_servers,     description: \"Server connections that have been idle for more than server_check_delay (means have to run check query)\" }\n    - sv_tested:             { usage: GAUGE, rename: tested_servers,   description: \"Server connections that are currently running reset or check query\" }\n    - sv_login:              { usage: GAUGE, rename: login_servers,    description: \"Server connections currently in the process of logging in\" }\n    - maxwait:               { usage: GAUGE,                           description: \"How long the first(oldest) client in the queue has waited, in seconds, key metric\" }\n    - maxwait_us:            { usage: GAUGE,                           description: \"Microsecond part of the maximum waiting time.\" }\n    - pool_mode:             { usage: LABEL,                           description: \"Pooling mode in use\" }\n\n\n#==============================================================#\n# 1000 pg_wait_event\n#==============================================================#\npg_wait_event:\n  name: pg_wait_event\n  desc: PostgreSQL wait event sampling based on pg_wait_sampling extension\n  query: SELECT coalesce(event_type, 'Running') AS etype, coalesce(event, 'Running') AS event, sum(count) AS count FROM pg_wait_sampling_profile GROUP BY 1,2;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster, \"extension:pg_wait_sampling\" ]\n  metrics:\n    - etype: { usage: \"LABEL\"   ,description: \"wait event type\" }\n    - event: { usage: \"LABEL\"   ,description: \"wait event name\" }\n    - count: { usage: \"COUNTER\" ,description: \"Total count of wait events sampled\" }\n\npg_wait_event_1s:\n  name: pg_wait_event_1s\n  desc: PostgreSQL wait event sampling based on pg_wait_sampling extension\n  query: SELECT coalesce(event_type, 'Running') AS etype, coalesce(event, 'Running') AS event, count(*) FROM pg_wait_sampling_history WHERE ts BETWEEN now() - '1s'::INTERVAL AND now() GROUP BY 1,2;\n  ttl: 10\n  min_version: 100000\n  tags: [ cluster, \"extension:pg_wait_sampling\" ]\n  metrics:\n    - etype: { usage: \"LABEL\"   ,description: \"wait event type\" }\n    - event: { usage: \"LABEL\"   ,description: \"wait event name\" }\n    - count: { usage: \"GAUGE\"   ,description: \"Number of wait events in last second\" }\n\n\n#==============================================================#\n# 1800 pg_tsdb_hypertable\n#==============================================================#\n# this collector reqires timescaledb extension to be installed\npg_tsdb_hypertable:\n  name: pg_tsdb_hypertable\n  desc: TimescaleDB hypertable overview\n  query: |-\n    SELECT \n      current_database() AS datname,\n      format('%I.%I', hypertable_schema, hypertable_name) AS relname,\n      num_dimensions AS dimensions, num_chunks AS chunks,\n      compression_enabled::BOOLEAN::int AS compressed,\n      hypertable_size(format('\"%I\".\"%I\"', hypertable_schema, hypertable_name)::RegClass) AS bytes\n    FROM timescaledb_information.hypertables;\n\n  ttl: 60\n  timeout: 2\n  min_version: 100000\n  skip: true\n  tags: [ \"extension:timescaledb\", \"schema:timescaledb_information\" ]\n  metrics:\n    - datname:         { usage: LABEL ,description: \"database name\" }\n    - relname:         { usage: LABEL ,description: \"Hypertable relation name\" }\n    - dimensions:      { usage: GAUGE ,description: \"Number of partitioning dimensions\" }\n    - chunks:          { usage: GAUGE ,description: \"Total chunks of this hypertable\" }\n    - compressed:      { usage: GAUGE ,description: \"1 if compression enabled\" }\n    - bytes:           { usage: GAUGE ,description: \"Total size of hypertable in bytes\" }\n\n\n#==============================================================#\n# 1900 pg_citus_node\n#==============================================================#\n# https://docs.citusdata.com/en/latest/develop/api_metadata.html#worker-node-table\npg_citus_node:\n  name: pg_citus_node\n  desc: Citus worker coordinator node inventory\n  query: |-\n    SELECT\n      CONCAT(nodename, ':', nodeport) AS node,\n      current_database() AS datname,\n      nodeid AS id,\n      groupid AS group,\n      hasmetadata::BOOLEAN::INT AS has_meta,\n      isactive::BOOLEAN::INT AS is_active,\n      metadatasynced::BOOLEAN::INT AS meta_synced,\n      shouldhaveshards::BOOLEAN::INT AS have_shards\n    FROM pg_dist_node;\n  ttl: 60\n  min_version: 100000\n  tags: [ \"extension:citus\" ]\n  metrics:\n    - node:             { usage: LABEL ,description: \"nodename:port of the PostgreSQL instance\" }\n    - datname:          { usage: LABEL ,description: \"database name\" }\n    - id:               { usage: GAUGE ,description: \"auto‑generated node identifier\" }\n    - group:            { usage: GAUGE ,description: \"replication group id (primary + secondaries)\" }\n    - has_meta:         { usage: GAUGE ,description: \"1 = internal use flag set\" }\n    - is_active:        { usage: GAUGE ,description: \"1 = node currently accepts shards\" }\n    - meta_synced:      { usage: GAUGE ,description: \"1 = metadata fully synced to node\" }\n    - have_shards:      { usage: GAUGE ,description: \"1 = rebalancer may place shards here\" }\n\n\n#==============================================================#\n# 2000 heartbeat\n#==============================================================#\n# this is a example of application monitoring and predicate queries\npg_heartbeat:\n  name: pg_heartbeat\n  desc: monitoring heartbeat in monitor.heartbeat table\n  predicate_queries:\n    - name: if heartbeat table exists\n      predicate_query: |\n        SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'monitor' AND table_name = 'heartbeat');\n  query: |-\n    SELECT id AS cluster_name, extract(EPOCH FROM ts) AS ts, lsn, txid FROM monitor.heartbeat;\n\n  ttl: 10\n  min_version: 090100\n  tags: [ \"dbname:postgres\", \"schema:monitor\" ]\n  skip: true\n  metrics:\n    - cluster_name:     { usage: LABEL   ,description: \"cluster_name param of this database cluster\" }\n    - ts:               { usage: GAUGE   ,description: \"unix timestamp of the heartbeat\" }\n    - lsn:              { usage: COUNTER ,description: \"lsn of the heartbeat\" }\n    - txid:             { usage: GAUGE   ,description: \"txid of the heartbeat\" }\n\n\n"
  }
]