summaryrefslogtreecommitdiff
path: root/gnu/services
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/services')
-rw-r--r--gnu/services/monitoring.scm571
1 files changed, 565 insertions, 6 deletions
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))))