1{ config, lib, pkgs, options }: 2 3with lib; 4 5let 6 cfg = config.services.prometheus.exporters.pgbouncer; 7in 8{ 9 port = 9127; 10 extraOpts = { 11 12 telemetryPath = mkOption { 13 type = types.str; 14 default = "/metrics"; 15 description = lib.mdDoc '' 16 Path under which to expose metrics. 17 ''; 18 }; 19 20 connectionString = mkOption { 21 type = types.str; 22 default = ""; 23 example = "postgres://admin:@localhost:6432/pgbouncer?sslmode=require"; 24 description = lib.mdDoc '' 25 Connection string for accessing pgBouncer. 26 27 NOTE: You MUST keep pgbouncer as database name (special internal db)!!! 28 29 NOTE: Admin user (with password or passwordless) MUST exist 30 in the services.pgbouncer.authFile if authType other than any is used. 31 32 WARNING: this secret is stored in the world-readable Nix store! 33 Use {option}`connectionStringFile` instead. 34 ''; 35 }; 36 37 connectionStringFile = mkOption { 38 type = types.nullOr types.path; 39 default = null; 40 example = "/run/keys/pgBouncer-connection-string"; 41 description = lib.mdDoc '' 42 File that contains pgBouncer connection string in format: 43 postgres://admin:@localhost:6432/pgbouncer?sslmode=require 44 45 NOTE: You MUST keep pgbouncer as database name (special internal db)!!! 46 47 NOTE: Admin user (with password or passwordless) MUST exist 48 in the services.pgbouncer.authFile if authType other than any is used. 49 50 {option}`connectionStringFile` takes precedence over {option}`connectionString` 51 ''; 52 }; 53 54 pidFile = mkOption { 55 type = types.nullOr types.str; 56 default = null; 57 description = lib.mdDoc '' 58 Path to PgBouncer pid file. 59 60 If provided, the standard process metrics get exported for the PgBouncer 61 process, prefixed with 'pgbouncer_process_...'. The pgbouncer_process exporter 62 needs to have read access to files owned by the PgBouncer process. Depends on 63 the availability of /proc. 64 65 https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics. 66 67 ''; 68 }; 69 70 webSystemdSocket = mkOption { 71 type = types.bool; 72 default = false; 73 description = lib.mdDoc '' 74 Use systemd socket activation listeners instead of port listeners (Linux only). 75 ''; 76 }; 77 78 logLevel = mkOption { 79 type = types.enum ["debug" "info" "warn" "error" ]; 80 default = "info"; 81 description = lib.mdDoc '' 82 Only log messages with the given severity or above. 83 ''; 84 }; 85 86 logFormat = mkOption { 87 type = types.enum ["logfmt" "json"]; 88 default = "logfmt"; 89 description = lib.mdDoc '' 90 Output format of log messages. One of: [logfmt, json] 91 ''; 92 }; 93 94 webConfigFile = mkOption { 95 type = types.nullOr types.path; 96 default = null; 97 description = lib.mdDoc '' 98 Path to configuration file that can enable TLS or authentication. 99 ''; 100 }; 101 102 extraFlags = mkOption { 103 type = types.listOf types.str; 104 default = [ ]; 105 description = lib.mdDoc '' 106 Extra commandline options when launching Prometheus. 107 ''; 108 }; 109 110 }; 111 112 serviceOpts = { 113 after = [ "pgbouncer.service" ]; 114 serviceConfig = let 115 startScript = pkgs.writeShellScriptBin "pgbouncer-start" "${concatStringsSep " " ([ 116 "${pkgs.prometheus-pgbouncer-exporter}/bin/pgbouncer_exporter" 117 "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" 118 "--pgBouncer.connectionString ${if cfg.connectionStringFile != null then 119 "$(head -n1 ${cfg.connectionStringFile})" else "${escapeShellArg cfg.connectionString}"}" 120 ] 121 ++ optionals (cfg.telemetryPath != null) [ 122 "--web.telemetry-path ${escapeShellArg cfg.telemetryPath}" 123 ] 124 ++ optionals (cfg.pidFile != null) [ 125 "--pgBouncer.pid-file= ${escapeShellArg cfg.pidFile}" 126 ] 127 ++ optionals (cfg.logLevel != null) [ 128 "--log.level ${escapeShellArg cfg.logLevel}" 129 ] 130 ++ optionals (cfg.logFormat != null) [ 131 "--log.format ${escapeShellArg cfg.logFormat}" 132 ] 133 ++ optionals (cfg.webSystemdSocket != false) [ 134 "--web.systemd-socket ${escapeShellArg cfg.webSystemdSocket}" 135 ] 136 ++ optionals (cfg.webConfigFile != null) [ 137 "--web.config.file ${escapeShellArg cfg.webConfigFile}" 138 ] 139 ++ cfg.extraFlags)}"; 140 in 141 { 142 ExecStart = "${startScript}/bin/pgbouncer-start"; 143 }; 144 }; 145}