summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Eure <ian@retrospec.tv>2026-01-11 08:44:38 -0800
committerIan Eure <ian@retrospec.tv>2026-03-29 08:59:52 -0700
commit0218c4136a63387f122301d9dfb5b71c310d0807 (patch)
treec2fc84c2360928e8da1e4893e8f6116651d5bca5
parentd768c5c27345d335e9d29932d8219ab31a9ae8b4 (diff)
gnu: Add collectd-service-type.
* gnu/services/monitoring.scm: (collectd-plugin-generic, collectd-plugin-generic?, collectd-plugin-generic-load-plugin?, collectd-plugin-generic-name, collectd-plugin-generic-options, collectd-plugin-python, collectd-plugin-python?, collectd-plugin-python-load-plugin?, collectd-plugin-python-type-databases, collectd-plugin-python-type-packages, collectd-plugin-python-module-paths, collectd-plugin-python-log-traces?, collectd-plugin-python-log-interactive?, collectd-plugin-python-import, collectd-plugin-python-module, collectd-plugin?, %collectd-default-type-database, %collectd-pid-file, collectd-configuration, collectd-configuration?, collectd-configuration-collectd, collectd-configuration-base-directory, collectd-configuration-auto-load-plugin?, collectd-configuration-collect-internal-stats?, collectd-configuration-type-databases, collectd-configuration-interval, collectd-configuration-max-read-interval, collectd-configuration-timeout, collectd-configuration-read-threads, collectd-configuration-write-threads, collectd-configuration-write-queue-limit-high, collectd-configuration-write-queue-limit-low, collectd-configuration-host-name, collectd-configuration-fully-qualified-domain-name-lookup?, collectd-configuration-plugins, collectd-service-type): New variable. * doc/guix.texi (Monitoring Services): Document it. Change-Id: I18d581292979e85603e679b9441be3eeb1856949
-rw-r--r--doc/guix.texi294
-rw-r--r--gnu/services/monitoring.scm571
2 files changed, 859 insertions, 6 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 266012a7e82..41ddce9792f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -34106,6 +34106,300 @@ Zabbix server port.
34106 34106
34107@c %end of fragment 34107@c %end of fragment
34108 34108
34109@subsubheading collectd Service
34110@cindex collectd
34111collectd is a daemon which collects, stores, transports, and visualizes
34112system and application performance metrics in a variety of ways.
34113
34114@defvar collectd-service-type
34115This is the service type for the @uref{https://collectd.org/, collectd}
34116service. Its value must be a @code{collectd-configuration} record:
34117
34118@lisp
34119(service collectd-service-type
34120 (collectd-configuration
34121 (plugins
34122 (list
34123 (collectd-plugin-generic
34124 (name "cpu")
34125 (options '((ReportByCpu . #t)
34126 (ReportByState . #t)
34127 (ValuesPercentage . #t))))))))
34128@end lisp
34129
34130The service may be extended to add new plugins:
34131
34132@lisp
34133(simple-service 'collectd-memory
34134 collectd-service-type
34135 (list
34136 (collectd-plugin-generic
34137 (name "memory")
34138 (options '((ValuesAbsolute . #t)
34139 (ValusPercentage . #t))))))
34140@end lisp
34141@end defvar
34142
34143
34144@c %start of fragment
34145
34146@deftp {Data Type} collectd-configuration
34147Available @code{collectd-configuration} fields are:
34148
34149@table @asis
34150@item @code{collectd} (default: @code{collectd}) (type: package)
34151The collectd package to use.
34152
34153@item @code{base-directory} (default: @code{"/var/lib/collectd"}) (type: string)
34154Sets the base directory. This is the directory beneath which all
34155@acronym{RRD,round-robin database} files are created. Possibly more
34156subdirectories are created. This is also the working directory for
34157collectd.
34158
34159@item @code{auto-load-plugins?} (default: @code{#f}) (type: boolean)
34160When set to @code{#f}, plugins must be loaded explicitly, by setting the
34161@code{load-plugin?} field of each plugin configuration to @code{#t}. If
34162a @code{<Plugin ...>} block is encountered and no configuration handling
34163callback for this plugin has been registered, a warning is logged and
34164the block is ignored.
34165
34166When set to @code{#t}, each @code{<Plugin ...>} block acts as if it was
34167immediately preceded by a @code{LoadPlugin} statement. @code{LoadPlugin}
34168statements are still required for plugins that don't provide any
34169configuration, e.g. the @code{Load} plugin.
34170
34171@item @code{collect-internal-stats?} (default: @code{#f}) (type: boolean)
34172When @code{#t}, various statistics about the collectd daemon will be
34173collected, with "collectd" as the plugin name.
34174
34175@item @code{type-databases} (type: list-of-file-likes)
34176One or more files that contain the data-set descriptions. See
34177@code{types.db(5)} for a description of the format of these files.
34178
34179@item @code{interval} (default: @code{60}) (type: maybe-seconds)
34180Configures the interval in which to query the read plugins. Smaller
34181values lead to a higher system load produced by collectd, while higher
34182values lead to more coarse statistics. Warning: You should set this
34183once and then never touch it again. If you do, you will have to delete
34184all your RRD files or know some serious RRDtool magic! (Assuming you're
34185using the RRDtool or RRDCacheD plugin.)
34186
34187@item @code{max-read-interval} (default: @code{86400}) (type: seconds)
34188A read plugin doubles the interval between queries after each failed
34189attempt to get data. This options limits the maximum value of the
34190interval.
34191
34192@item @code{timeout} (type: maybe-integer)
34193Consider a value list "missing" when no update has been read or received
34194for @code{Iterations} iterations. By default, collectd considers a
34195value list missing when no update has been received for twice the update
34196interval. Since this setting uses iterations, the maximum allowed time
34197without update depends on the @code{Interval} information contained in
34198each value list. This is used in the @code{Threshold} configuration to
34199dispatch notifications about missing values, see
34200@code{collectd-threshold(5)} for details.
34201
34202@item @code{read-threads} (default: @code{5}) (type: integer)
34203Number of threads to start for reading plugins. You may want to
34204increase this if you have more than five plugins that take a long time
34205to read. Mostly those are plugins that do network-IO. Setting this to
34206a value higher than the number of registered read callbacks is not
34207recommended.
34208
34209@item @code{write-threads} (default: @code{5}) (type: integer)
34210Number of threads to start for dispatching value lists to write plugins.
34211You may want to increase this if you have more than five plugins that
34212may take relatively long to write to.
34213
34214@item @code{write-queue-limit-high} (type: maybe-integer)
34215Metrics are read by the read threads and then put into a queue to be
34216handled by the write threads. If one of the write plugins is slow (e.g.
34217network timeouts, I/O saturation of the disk) this queue will grow. In
34218order to avoid running into memory issues in such a case, you can limit
34219the size of this queue. If there are @code{write-queue-limit-high}
34220metrics in the queue, any new metrics will be dropped. If the number of
34221metrics currently in the queue is between @code{write-queue-limit-low}
34222and @code{write-queue-limit-high}, the metric is dropped with a
34223probability that is proportional to the number of metrics in the queue
34224(i.e. it increases linearly until it reaches 100%).
34225
34226@item @code{write-queue-limit-low} (type: maybe-integer)
34227If there are less than @code{write-queue-limit-low} metrics in the
34228queue, all new metrics will be enqueued. If
34229@code{write-queue-limit-high} is set to non-zero and
34230@code{write-queue-limit-low} is unset, the latter will default to half
34231of @code{write-queue-limit-high}.
34232
34233@item @code{host-name} (type: maybe-string)
34234Sets the hostname that identifies a host. If you omit this setting, the
34235hostname will be determined using the @code{gethostname(2)} system call.
34236
34237@item @code{fully-qualified-domain-name-lookup?} (default: @code{#t}) (type: boolean)
34238If @code{host-name} is determined automatically, this setting controls
34239whether or not the daemon should try to figure out the
34240@acronym{FQDN,fully qualified domain name}. This is done using a lookup
34241of the name returned by @code{gethostname(2)}.
34242
34243@item @code{plugins} (default: @code{()}) (type: list-of-collectd-plugins)
34244Configurations for collectd plugins.
34245
34246@end table
34247
34248@end deftp
34249
34250
34251@c %end of fragment
34252
34253@c %start of fragment
34254
34255@deftp {Data Type} collectd-plugin-generic
34256
34257The @code{collectd-plugin-generic} record can represent most collectd
34258plugins.
34259
34260This example configuration will enable the CPU usage reporting plugin.
34261See the @code{collectd.conf(5)} man page for a list of plugins and their
34262options.
34263
34264@lisp
34265(collectd-plugin-generic
34266 (name "cpu")
34267 (options '((ReportByCpu . #t)
34268 (ReportByState . #t)
34269 (ValuesPercentage . #t))))
34270@end lisp
34271
34272Available @code{collectd-plugin-generic} fields are:
34273
34274@table @asis
34275@item @code{load-plugin?} (default: @code{#t}) (type: boolean)
34276When @code{#t}, include a @code{LoadPlugin} directive in the
34277configuration. This interacts with @code{auto-load-plugins?} in
34278@code{collectd-configuration}; if @code{auto-load-plugins?} is
34279@code{#f}, all plugins should set this to @code{#t}.
34280
34281@item @code{name} (type: string)
34282The name of the plugin to configure.
34283
34284@item @code{options} (default: @code{()}) (type: plugin-options)
34285Configuration options for the plugin, as an alist. See
34286@code{collect.conf(5)} for the available plugin options.
34287
34288@end table
34289
34290@end deftp
34291
34292
34293@c %end of fragment
34294
34295
34296
34297@c %start of fragment
34298
34299@deftp {Data Type} collectd-plugin-python
34300
34301The @code{collectd-plugin-python} configuration record holds
34302configuration for collectd plugins written in Python. See the
34303@code{collectd-python(5)} man page for more information on Python
34304support in collectd.
34305
34306Guix packages listed in the @code{packages} field will be added to the
34307profile used to run collectd. This example configuration will load a
34308Python plugin named @code{myplugin}, whose code is in the
34309@code{python-myplugin} Guix package.
34310
34311@lisp
34312(collectd-plugin-python
34313 (packages (list python-myplugin))
34314 (module "myplugin")
34315 (module-options '((SomeOption . "hi")
34316 (AnotherOption . 123))))
34317@end lisp
34318
34319The @code{module-paths} field will emit verbatim @code{ModulePath}
34320lines, for plugins not packaged for Guix. This example configuration
34321loads the @code{gpio} plugin from
34322@code{/home/user/projects/collectd-gpio/gpio}.
34323
34324@lisp
34325(collectd-plugin-python
34326 (module-paths
34327 (list
34328 "/home/user/projects/collectd-gpio/gpio"))
34329 (module "gpio")
34330 (module-options '((MonitorGPIOs 1 2 3 4))))
34331@end lisp
34332
34333The two mechanisms may be combined: a Guix-packaged Python library may
34334be used by unpackaged plugin code. This example loads a
34335@code{mongometrics} plugin from
34336@code{/opt/collectd-mongodb/mongometrics}, and also makes the
34337@code{python-pymongo} Python package available for it to use.
34338
34339@lisp
34340(collectd-plugin-python
34341 (packages (list python-pymongo))
34342 (module-paths
34343 (list
34344 "/opt/collectd-mongodb/mongometrics"))
34345 (module "mongometrics")
34346 (module-options '((Host . "localhost"))))
34347@end lisp
34348
34349Available @code{collectd-plugin-python} fields are:
34350
34351@table @asis
34352@item @code{load-plugin?} (default: @code{#t}) (type: boolean)
34353When @code{#t}, include a @code{LoadPlugin} directive in the
34354configuration. This interacts with @code{auto-load-plugins?} in
34355@code{collectd-configuration}; if @code{collectd-configuration}'s
34356@code{auto-load-plugins?} is @code{#f}, all plugins should set this to
34357@code{#t}.
34358
34359@item @code{type-databases} (default: @code{()}) (type: list-of-file-likes)
34360One or more files that contain the data-set descriptions. See
34361@code{types.db(5)} for a description of the format of these files.
34362
34363@item @code{packages} (default: @code{()}) (type: list-of-packages)
34364Packages to make available to the Python plugin. These can be
34365dependencies of the plugin code, or may contain the plugin.
34366
34367@item @code{module-paths} (default: @code{()}) (type: list-of-string)
34368Entries to prepend to @code{sys.path}.
34369
34370@item @code{log-traces?} (default: @code{#f}) (type: boolean)
34371If a Python script throws an exception it will be logged by collectd
34372with the name of the exception and the message. If you set this option
34373to true it will also log the full stacktrace just like the default
34374output of an interactive Python interpreter. This does not apply to the
34375@code{CollectError} exception, which will never log a stacktrace. This
34376should probably be set to false most of the time but is very useful for
34377development and debugging of new modules.
34378
34379@item @code{interactive?} (default: @code{#f}) (type: boolean)
34380This option will cause the module to launch an interactive Python
34381interpreter that reads from and writes to the terminal. Note that
34382collectd will terminate right after starting up if you try to run it as
34383a daemon while this option is enabled so make sure to start collectd
34384with the @code{-f} option. See the @code{collectd-python(5)} man page
34385for more information on this option.
34386
34387@item @code{module} (type: string)
34388The name of the Python module to import into the collectd Python
34389process. The module must be available in @code{packages} or
34390@code{module-paths}, and register a MPD callback.
34391
34392@item @code{module-options} (default: @code{()}) (type: alist)
34393Configuration options for the module.
34394
34395@end table
34396
34397@end deftp
34398
34399
34400@c %end of fragment
34401
34402
34109@node Kerberos Services 34403@node Kerberos Services
34110@subsection Kerberos Services 34404@subsection Kerberos Services
34111@cindex Kerberos 34405@cindex Kerberos
diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm
index 8ba19ddd7ee..66bdc06d04a 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -21,24 +21,39 @@
21;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. 21;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
22 22
23(define-module (gnu services monitoring) 23(define-module (gnu services monitoring)
24 #:use-module (gnu services)
25 #:use-module (gnu services configuration)
26 #:use-module (gnu services shepherd)
27 #:use-module (gnu services web)
28 #:use-module (gnu packages admin) 24 #:use-module (gnu packages admin)
25 #:use-module (gnu packages bash)
29 #:use-module (gnu packages monitoring) 26 #:use-module (gnu packages monitoring)
30 #:use-module (gnu packages networking) 27 #:use-module (gnu packages networking)
28 #:use-module (gnu packages python)
29 #:use-module (gnu services configuration)
30 #:use-module (gnu services shepherd)
31 #:use-module (gnu services web)
32 #:use-module (gnu services)
31 #:use-module (gnu system shadow) 33 #:use-module (gnu system shadow)
32 #:use-module (guix gexp) 34 #:use-module (guix gexp)
35 #:use-module ((guix modules) #:select (source-module-closure))
33 #:use-module (guix packages) 36 #:use-module (guix packages)
37 #:use-module ((guix profiles) #:select (packages->manifest
38 profile
39 profile-search-paths))
34 #:use-module (guix records) 40 #:use-module (guix records)
35 #:use-module (guix utils) 41 #:use-module ((guix search-paths) #:select (search-path-specification-variable))
42 #:use-module ((guix self) #:select (make-config.scm))
36 #:use-module ((guix ui) #:select (display-hint G_)) 43 #:use-module ((guix ui) #:select (display-hint G_))
44 #:use-module (guix utils)
37 #:use-module (ice-9 match) 45 #:use-module (ice-9 match)
38 #:use-module (ice-9 rdelim) 46 #:use-module (ice-9 rdelim)
39 #:use-module (srfi srfi-1) 47 #:use-module (srfi srfi-1)
48 #:use-module ((srfi srfi-2) #:select (and-let*))
40 #:use-module (srfi srfi-26) 49 #:use-module (srfi srfi-26)
41 #:use-module (srfi srfi-35) 50 #:use-module (srfi srfi-35)
51 #:use-module ((srfi srfi-171) #:select (list-transduce
52 rcons
53 tconcatenate
54 tfilter
55 tmap))
56
42 #:export (darkstat-configuration 57 #:export (darkstat-configuration
43 darkstat-service-type 58 darkstat-service-type
44 59
@@ -94,7 +109,49 @@
94 zabbix-agent-service-type 109 zabbix-agent-service-type
95 zabbix-front-end-configuration 110 zabbix-front-end-configuration
96 zabbix-front-end-service-type 111 zabbix-front-end-service-type
97 %zabbix-front-end-configuration-nginx)) 112 %zabbix-front-end-configuration-nginx
113
114 collectd-plugin-generic
115 collectd-plugin-generic?
116 collectd-plugin-generic-load-plugin?
117 collectd-plugin-generic-name
118 collectd-plugin-generic-options
119
120 collectd-plugin-python
121 collectd-plugin-python?
122 collectd-plugin-python-load-plugin?
123 collectd-plugin-python-type-databases
124 collectd-plugin-python-type-packages
125 collectd-plugin-python-module-paths
126 collectd-plugin-python-log-traces?
127 collectd-plugin-python-log-interactive?
128 collectd-plugin-python-import
129 collectd-plugin-python-module
130
131 collectd-plugin?
132
133 %collectd-default-type-database
134 %collectd-pid-file
135
136 collectd-configuration
137 collectd-configuration?
138 collectd-configuration-collectd
139 collectd-configuration-base-directory
140 collectd-configuration-auto-load-plugins?
141 collectd-configuration-collect-internal-stats?
142 collectd-configuration-type-databases
143 collectd-configuration-interval
144 collectd-configuration-max-read-interval
145 collectd-configuration-timeout
146 collectd-configuration-read-threads
147 collectd-configuration-write-threads
148 collectd-configuration-write-queue-limit-high
149 collectd-configuration-write-queue-limit-low
150 collectd-configuration-host-name
151 collectd-configuration-fully-qualified-domain-name-lookup?
152 collectd-configuration-plugins
153
154 collectd-service-type))
98 155
99 156
100;;; 157;;;
@@ -1186,3 +1243,505 @@ with Zabbix server.")))
1186 `((zabbix-front-end-configuration 1243 `((zabbix-front-end-configuration
1187 ,zabbix-front-end-configuration-fields)) 1244 ,zabbix-front-end-configuration-fields))
1188 'zabbix-front-end-configuration)) 1245 'zabbix-front-end-configuration))
1246
1247
1248;;
1249;; collectd
1250;;
1251
1252(define *indent* (make-parameter ""))
1253
1254(defmacro with-indent (. body)
1255 `(parameterize ((*indent* (string-append (*indent*) " ")))
1256 ,@body))
1257
1258(define seconds? integer?)
1259
1260(define-maybe/no-serialization seconds)
1261
1262(define list-of-string? (list-of string?))
1263
1264(define list-of-file-likes? (list-of file-like?))
1265
1266(define (collectd-serialize-list-of-file-likes name value)
1267 #~(string-join
1268 (map
1269 (lambda (v) (format #f "~a~a \"~a\"" #$name #$(*indent*) v))
1270 '#$value)
1271 "\n" 'suffix))
1272
1273(define (collectd-serialize-file-like name value)
1274 (collectd-serialize-list-of-file-likes name (list value)))
1275
1276(define list-of-packages? (list-of package?))
1277
1278(define (collectd-serialize-value value)
1279 (cond
1280 ;; Strings get quoted and escaped.
1281 ((string? value)
1282 (format #f "~s" value))
1283
1284 ;; Keywords become unquoted strings (#:foo -> foo).
1285 ((keyword? value)
1286 (collectd-serialize-value
1287 (keyword->symbol value)))
1288
1289 ;; Booleans become bare words.
1290 ((eq? value #t) "true")
1291 ((eq? value #f) "false")
1292
1293 ;; Alists serialize to lines of KEY VALUE.
1294 ((alist? value)
1295 (apply string-append
1296 (map
1297 (generic-serialize-alist-entry collectd-serialize-field)
1298 value)))
1299
1300 ;; Lists get their elements serialized and joined with a space.
1301 ((list? value) (string-join (map collectd-serialize-value value) " "))
1302
1303 ;; Other types (numbers etc) turn into bare strings.
1304 (else (object->string value))))
1305
1306(define (collectd-serialize-field name value)
1307 (if (and (list? value) (null-list? value))
1308 ""
1309 (format #nil "~a~a ~a~%" (*indent*) name
1310 (collectd-serialize-value value))))
1311
1312(define (remap-names name-map serializer)
1313 "Renaming serializer.
1314
1315Wraps `serializer', renaming fields according to `name-map', an alist of
1316'((field-name . serialized-name))."
1317 (lambda (name value)
1318 (serializer (or (and=> (assoc name name-map) cdr) name) value)))
1319
1320(define (collectd-make-load-plugin?-serializer plugin-name)
1321 (lambda (_ load-plugin?)
1322 (if load-plugin?
1323 (collectd-serialize-field "LoadPlugin" plugin-name)
1324 "")))
1325
1326;; Generic plugin support.
1327
1328(define-configuration/no-serialization collectd-plugin-generic
1329 (load-plugin?
1330 (boolean #t)
1331 "When @code{#t}, include a @code{LoadPlugin} directive in the
1332configuration. This interacts with @code{auto-load-plugins?} in
1333@code{collectd-configuration}; if @code{auto-load-plugins?} is @code{#f}, all
1334plugins should set this to @code{#t}.")
1335
1336 (name
1337 string
1338 "The name of the plugin to configure. See @code{collect.conf(5)} for the
1339list of plugins.")
1340
1341 (options
1342 (alist '())
1343 "Configuration options for the plugin, as an alist. See
1344@code{collect.conf(5)} for the available plugin options."))
1345
1346(define (collectd-serialize-plugin-generic _ value)
1347 (match-record value <collectd-plugin-generic>
1348 (name load-plugin? options)
1349 #~(string-join
1350 `("\n"
1351 ,#$((collectd-make-load-plugin?-serializer name) #nil load-plugin?)
1352 ,(string-append "<Plugin " #$name ">\n")
1353 ,#$(with-indent (collectd-serialize-value options))
1354 "</Plugin>\n")
1355 "")))
1356
1357;; Python plugin support.
1358
1359(define (collectd-serialize-python-module name value)
1360 (apply string-append
1361 `(,(string-append (*indent*) "<Module "
1362 (collectd-serialize-value name)
1363 ">")
1364 "\n"
1365 ,@(with-indent
1366 (map
1367 (lambda (kvs)
1368 (collectd-serialize-field (car kvs) (cdr kvs)))
1369 value))
1370 ,(string-append (*indent*) "</Module>"))))
1371
1372(define collectd-plugin-python-remap
1373 '((module-paths . "ModulePath")
1374 (load-plugin? . "LoadPlugin")
1375 (log-traces? . "LogTraces")
1376 (interactive? . "Interactive")
1377 (type-databases . "TypesDB")
1378 (packages . "ModulePath")
1379 (module . "Import")))
1380
1381(define collectd-serialize-plugin-python-field
1382 (remap-names collectd-plugin-python-remap
1383 collectd-serialize-field))
1384
1385(define-configuration collectd-plugin-python
1386 (load-plugin?
1387 (boolean #t)
1388 "When @code{#t}, include a @code{LoadPlugin} directive in the
1389configuration. This interacts with @code{auto-load-plugins?} in
1390@code{collectd-configuration}; if @code{collectd-configuration}'s
1391@code{auto-load-plugins?} is @code{#f}, all plugins should set this to
1392@code{#t}."
1393 (serializer (collectd-make-load-plugin?-serializer "python")))
1394
1395 (type-databases
1396 (list-of-file-likes '())
1397 "One or more files that contain the data-set descriptions. See
1398@code{types.db(5)} for a description of the format of these files."
1399 (serializer (remap-names collectd-plugin-python-remap
1400 collectd-serialize-list-of-file-likes)))
1401
1402 (packages
1403 (list-of-packages '())
1404 "Packages to make available to the Python plugin. These can be
1405dependencies of the plugin code, or may contain the plugin."
1406 (serializer empty-serializer))
1407
1408 (module-paths
1409 (list-of-string '())
1410 "Entries to prepend to @code{sys.path}."
1411 (serializer collectd-serialize-plugin-python-field))
1412
1413 (log-traces?
1414 (boolean #f)
1415 "If a Python script throws an exception it will be logged by
1416collectd with the name of the exception and the message. If you set
1417this option to true it will also log the full stacktrace just like the
1418default output of an interactive Python interpreter. This does not
1419apply to the @code{CollectError} exception, which will never log a
1420stacktrace. This should probably be set to false most of the time but
1421is very useful for development and debugging of new modules."
1422 (serializer collectd-serialize-plugin-python-field))
1423
1424 (interactive?
1425 (boolean #f)
1426 "This option will cause the module to launch an interactive Python
1427interpreter that reads from and writes to the terminal. Note that collectd
1428will terminate right after starting up if you try to run it as a daemon while
1429this option is enabled so make sure to start collectd with the @code{-f}
1430option. See the @code{collectd-python(5)} man page for more information on
1431this option."
1432 (serializer collectd-serialize-plugin-python-field))
1433
1434 (module
1435 string
1436 "The name of the Python module to import into the collectd Python
1437process. The module must be available in @code{packages} or
1438@code{module-paths}, and register a MPD callback."
1439 (serializer collectd-serialize-plugin-python-field))
1440
1441 (module-options
1442 (alist '())
1443 "Configuration options for the module."
1444 (serializer (lambda (_ value) (collectd-serialize-value value)))))
1445
1446(define (collectd-serialize-plugin-python _ value)
1447 (define (serialize-fields fields)
1448 (list-transduce
1449 (base-transducer value) rcons
1450 (filter-configuration-fields collectd-plugin-python-fields fields)))
1451
1452 (match-record
1453 value <collectd-plugin-python> (module)
1454 #~(string-append
1455 "\n"
1456 #$@(serialize-fields '(load-plugin? type-databases))
1457 "<Plugin python>\n"
1458 #$@(with-indent
1459 (append
1460 (serialize-fields '(log-traces? interactive? module-paths module))
1461 (list (*indent*) "<Module " (collectd-serialize-value module) ">\n")
1462 (with-indent (serialize-fields '(module-options)))
1463 (list (*indent*) "</Module>\n")))
1464 "</Plugin>\n")))
1465
1466(define (collectd-plugin? x)
1467 ;; XXX: Extend this if plugin-specific configuration records are
1468 ;; added.
1469 (or (collectd-plugin-generic? x)
1470 (collectd-plugin-python? x)))
1471
1472(define list-of-collectd-plugins? (list-of collectd-plugin?))
1473
1474(define (collectd-serialize-plugin name value)
1475 ((match value
1476 ;; XXX: Extend this if plugin-specific configuration records are
1477 ;; added.
1478 ;; Note that these *must* return gexps, not strings, otherwise things
1479 ;; like type-databases won't work.
1480 (($ <collectd-plugin-generic>) collectd-serialize-plugin-generic)
1481 (($ <collectd-plugin-python>) collectd-serialize-plugin-python))
1482 name value))
1483
1484(define (collectd-serialize-list-of-plugins name value)
1485 #~(string-append
1486 #$@(map
1487 (lambda (v) (collectd-serialize-plugin name v))
1488 value)))
1489
1490(define collectd-configuration-remap
1491 '((base-directory . "BaseDir")
1492 (auto-load-plugins? . "AutoLoadPlugin")
1493 (collect-internal-stats? . "CollectInternalStats")
1494 (type-databases . "TypesDB")
1495 (interval . "Interval")
1496 (max-read-interval . "MaxReadInterval")
1497 (timeout . "Timeout")
1498 (read-threads . "ReadThreads")
1499 (write-threads . "WriteThreads")
1500 (write-queue-limit-high . "WriteQueueLimitHigh")
1501 (write-queue-limit-low . "WriteQueueLimitLow")
1502 (host-name . "Hostname")
1503 (fully-qualified-domain-name-lookup? . "FQDNLookup")))
1504
1505(define collectd-configuration-serialize-field
1506 (remap-names collectd-configuration-remap
1507 collectd-serialize-field))
1508
1509(define %collectd-default-type-database
1510 (file-append collectd "/share/collectd/types.db"))
1511
1512(define-configuration collectd-configuration
1513 (collectd
1514 (package collectd)
1515 "The collectd package to use."
1516 (serializer empty-serializer))
1517
1518 (base-directory
1519 (string "/var/lib/collectd")
1520 "Sets the base directory. This is the directory beneath which all
1521@acronym{RRD, round-robin database} files are created. Possibly more
1522subdirectories are created. This is also the working directory for
1523collectd."
1524 (serializer collectd-configuration-serialize-field))
1525
1526 (auto-load-plugins?
1527 (boolean #f)
1528 "When set to @code{#f}, plugins must be loaded explicitly, by setting the
1529@code{load-plugin?} field of each plugin configuration to @code{#t}. If a
1530@code{<Plugin ...>} block is encountered and no configuration handling
1531callback for this plugin has been registered, a warning is logged and the
1532block is ignored.
1533
1534When set to @code{#t}, each @code{<Plugin ...>} block acts as if it was
1535immediately preceded by a @code{LoadPlugin} statement. @code{LoadPlugin}
1536statements are still required for plugins that don't provide any
1537configuration, e.g. the @code{Load} plugin."
1538 (serializer collectd-configuration-serialize-field))
1539
1540 (collect-internal-stats?
1541 (boolean #f)
1542 "When @code{#t}, various statistics about the collectd daemon will
1543be collected, with \"collectd\" as the plugin name."
1544 (serializer collectd-configuration-serialize-field))
1545
1546 (type-databases
1547 (list-of-file-likes (list %collectd-default-type-database))
1548 "One or more files that contain the data-set descriptions. See
1549@code{types.db(5)} for a description of the format of these files."
1550 (serializer (remap-names collectd-configuration-remap
1551 collectd-serialize-list-of-file-likes)))
1552
1553 (interval
1554 (seconds 60)
1555 "Configures the interval in which to query the read plugins.
1556Smaller values lead to a higher system load produced by
1557collectd, while higher values lead to more coarse statistics.
1558
1559Warning: You should set this once and then never touch it again. If
1560you do, you will have to delete all your RRD files or know some
1561serious RRDtool magic! (Assuming you're using the RRDtool or
1562RRDCacheD plugin.)"
1563 (serializer collectd-configuration-serialize-field))
1564
1565 (max-read-interval
1566 (seconds 86400)
1567 "A read plugin doubles the interval between queries after each
1568failed attempt to get data.
1569
1570This options limits the maximum value of the interval."
1571 (serializer collectd-configuration-serialize-field))
1572
1573 (timeout
1574 maybe-integer
1575 "Consider a value list \"missing\" when no update has been read or
1576received for @code{Iterations} iterations. By default, collectd considers
1577a value list missing when no update has been received for twice the
1578update interval. Since this setting uses iterations, the maximum
1579allowed time without update depends on the @code{Interval} information
1580contained in each value list. This is used in the @code{Threshold}
1581configuration to dispatch notifications about missing values, see
1582@code{collectd-threshold(5)} for details."
1583 (serializer collectd-configuration-serialize-field))
1584
1585 (read-threads
1586 (integer 5)
1587 "Number of threads to start for reading plugins. You may want to
1588increase this if you have more than five plugins that take a long time
1589to read. Mostly those are plugins that do network-IO. Setting this to
1590a value higher than the number of registered read callbacks is not
1591recommended."
1592 (serializer collectd-configuration-serialize-field))
1593
1594 (write-threads
1595 (integer 5)
1596 "Number of threads to start for dispatching value lists to write
1597plugins. You may want to increase this if you have more than five
1598plugins that may take relatively long to write to."
1599 (serializer collectd-configuration-serialize-field))
1600
1601 (write-queue-limit-high
1602 maybe-integer
1603 "Metrics are read by the read threads and then put into a queue to
1604be handled by the write threads. If one of the write plugins is
1605slow (e.g. network timeouts, I/O saturation of the disk) this queue
1606will grow. In order to avoid running into memory issues in such a
1607case, you can limit the size of this queue.
1608
1609If there are @code{write-queue-limit-high} metrics in the queue, any
1610new metrics will be dropped.
1611
1612If the number of metrics currently in the queue is between
1613@code{write-queue-limit-low} and @code{write-queue-limit-high}, the
1614metric is dropped with a probability that is proportional to the
1615number of metrics in the queue (i.e. it increases linearly until it
1616reaches 100%)."
1617 (serializer collectd-configuration-serialize-field))
1618
1619 (write-queue-limit-low
1620 maybe-integer
1621 "If there are less than @code{write-queue-limit-low} metrics in the
1622queue, all new metrics will be enqueued.
1623
1624If @code{write-queue-limit-high} is set to non-zero and
1625@code{write-queue-limit-low} is unset, the latter will default to half
1626of @code{write-queue-limit-high}."
1627 (serializer collectd-configuration-serialize-field))
1628
1629 (host-name
1630 maybe-string
1631 "Sets the hostname that identifies a host. If you omit this setting,
1632the hostname will be determined using the @code{gethostname(2)} system
1633call."
1634 (serializer collectd-configuration-serialize-field))
1635
1636 (fully-qualified-domain-name-lookup?
1637 (boolean #t)
1638 "If @code{host-name} is determined automatically, this setting
1639controls whether or not the daemon should try to figure out the
1640@acronym{FQDN, fully qualified domain name}. This is done using a
1641lookup of the name returned by @code{gethostname(2)}."
1642 (serializer collectd-configuration-serialize-field))
1643
1644 (plugins
1645 (list-of-collectd-plugins '())
1646 "Configurations for collectd plugins."
1647 (serializer collectd-serialize-list-of-plugins))
1648
1649 (prefix collectd-))
1650
1651(define (collectd-configuration-python config)
1652 "Return the Python package collectd was built with, or #f."
1653 (and=> (assoc-ref (package-native-inputs
1654 (collectd-configuration-collectd config))
1655 "python")
1656 car))
1657
1658(define (collectd-python-packages config)
1659 "Return a list of all packages in Python plugins."
1660 (append-map
1661 (lambda (plugin)
1662 (if (collectd-plugin-python? plugin)
1663 (collectd-plugin-python-packages plugin)
1664 '()))
1665 (collectd-configuration-plugins config)))
1666
1667(define (collectd-profile-packages config)
1668 "Return packages to include in the profile for collectd."
1669 (let ((python (collectd-configuration-python config))
1670 (python-packages (collectd-python-packages config)))
1671 (cons
1672 (collectd-configuration-collectd config)
1673 ;; Only include Python and packages if collectd has support.
1674 (if python
1675 (cons python python-packages)
1676 '()))))
1677
1678(define (make-collectd-profile-wrapper config)
1679 "Return a gexp representing a wrapper for collectd, which runs it in a profile."
1680 (let* ((collectd (collectd-configuration-collectd config))
1681 (packages (collectd-profile-packages config))
1682 (collectd-profile (profile
1683 (content
1684 (packages->manifest packages)))))
1685 (computed-file
1686 "collectd-profile-wrapper"
1687 (with-imported-modules '((guix build utils))
1688 #~(begin
1689 (use-modules (guix build utils))
1690 (call-with-output-file #$output
1691 (lambda (output)
1692 (format output
1693 (string-append
1694 "#! ~a~%~%"
1695 ". ~a~%"
1696 "exec -a \"${0##*/}\" ~a \"$@\"~%")
1697 #$(file-append bash "/bin/bash")
1698 #$(file-append collectd-profile "/etc/profile")
1699 #$(file-append collectd "/sbin/collectd"))))
1700 (chmod #$output #o755))))))
1701
1702(define %collectd-pid-file "/var/run/collectd.pid")
1703
1704(define (make-collectd-shepherd-service config)
1705 (let ((config-file
1706 (mixed-text-file
1707 "collectd.conf"
1708 (serialize-configuration config collectd-configuration-fields))))
1709 (match-record config <collectd-configuration> (collectd)
1710 (shepherd-service
1711 (provision '(collectd))
1712 (documentation "Run collectd.")
1713 (requirement '(user-processes networking))
1714 (start
1715 #~(make-forkexec-constructor
1716 (list #$(make-collectd-profile-wrapper config)
1717 "-C" #$config-file
1718 "-B" ; Don't create base dir.
1719 "-P" #$%collectd-pid-file)
1720 #:pid-file #$%collectd-pid-file))
1721 (stop #~(make-kill-destructor))))))
1722
1723(define (collectd-activation config)
1724 (match-record config <collectd-configuration> (base-directory)
1725 (with-imported-modules
1726 (source-module-closure '((guix build utils)))
1727 #~(begin
1728 (use-modules (guix build utils))
1729 (mkdir-p #$base-directory)))))
1730
1731(define collectd-service-type
1732 (service-type
1733 (name 'collectd)
1734 (description "Run collectd")
1735 (extensions
1736 (list
1737 (service-extension shepherd-root-service-type
1738 (compose list make-collectd-shepherd-service))
1739 (service-extension activation-service-type
1740 collectd-activation)))
1741 (compose concatenate)
1742 (extend
1743 (lambda (config plugins)
1744 (collectd-configuration
1745 (inherit config)
1746 (plugins (append (collectd-configuration-plugins config) plugins)))))
1747 (default-value (collectd-configuration))))