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}