mirror of
https://codeberg.org/guix/guix.git
synced 2026-01-25 03:55:08 -06:00
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
This commit is contained in:
parent
cd86148bf3
commit
d1fd80b2ac
2 changed files with 889 additions and 6 deletions
294
doc/guix.texi
294
doc/guix.texi
|
|
@ -33630,6 +33630,300 @@ Zabbix server port.
|
|||
|
||||
@c %end of fragment
|
||||
|
||||
@subsubheading collectd Service
|
||||
@cindex collectd
|
||||
collectd is a daemon collecting system and application performance
|
||||
metrics periodically and provides mechanisms to store and transport the
|
||||
values in a variety of ways.
|
||||
|
||||
@defvar collectd-service-type
|
||||
This is the service type for the @uref{https://collectd.org/, collectd}
|
||||
service. Its value must be a @code{collectd-configuration} record:
|
||||
|
||||
@lisp
|
||||
(service collectd-service-type
|
||||
(collectd-configuration
|
||||
(plugins
|
||||
(list
|
||||
(collectd-plugin-generic
|
||||
(name "cpu")
|
||||
(options '((ReportByCpu . #t)
|
||||
(ReportByState . #t)
|
||||
(ValuesPercentage . #t))))))))
|
||||
@end lisp
|
||||
|
||||
The service may be extended to add new plugins:
|
||||
|
||||
@lisp
|
||||
(simple-service 'collectd-memory
|
||||
collectd-service-type
|
||||
(list
|
||||
(collectd-plugin-generic
|
||||
(name "memory")
|
||||
(options '((ValuesAbsolute . #t)
|
||||
(ValusPercentage . #t))))))
|
||||
@end lisp
|
||||
@end defvar
|
||||
|
||||
|
||||
@c %start of fragment
|
||||
|
||||
@deftp {Data Type} collectd-configuration
|
||||
Available @code{collectd-configuration} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{collectd} (default: @code{collectd}) (type: package)
|
||||
The collectd package to use.
|
||||
|
||||
@item @code{base-directory} (default: @code{"/var/lib/collectd"}) (type: string)
|
||||
Sets the base directory. This is the directory beneath which all
|
||||
@acronym{RRD,round-robin database} files are created. Possibly more
|
||||
subdirectories are created. This is also the working directory for
|
||||
collectd.
|
||||
|
||||
@item @code{auto-load-plugin?} (default: @code{#f}) (type: boolean)
|
||||
When set to @code{#f}, each plugin needs to be loaded explicitly, using
|
||||
@code{collectd-load-plugin}. If a @code{<Plugin ...>} block is
|
||||
encountered and no configuration handling callback for this plugin has
|
||||
been registered, a warning is logged and the block is ignored. When set
|
||||
to true, explicit @code{LoadPlugin} statements are not required. Each
|
||||
@code{<Plugin ...>} block acts as if it was immediately preceded by a
|
||||
LoadPlugin statement. LoadPlugin statements are still required for
|
||||
plugins that don't provide any configuration, e.g. the @code{Load}
|
||||
plugin.
|
||||
|
||||
@item @code{collect-internal-stats?} (default: @code{#f}) (type: boolean)
|
||||
When @code{#t}, various statistics about the collectd daemon will be
|
||||
collected, with "collectd" as the plugin name.
|
||||
|
||||
@item @code{type-databases} (type: list-of-file-likes)
|
||||
One or more files that contain the data-set descriptions. See
|
||||
@code{types.db(5)} for a description of the format of these files.
|
||||
|
||||
@item @code{interval} (default: @code{60}) (type: maybe-seconds)
|
||||
Configures the interval in which to query the read plugins. Smaller
|
||||
values lead to a higher system load produced by collectd, while higher
|
||||
values lead to more coarse statistics. Warning: You should set this
|
||||
once and then never touch it again. If you do, you will have to delete
|
||||
all your RRD files or know some serious RRDtool magic! (Assuming you're
|
||||
using the RRDtool or RRDCacheD plugin.)
|
||||
|
||||
@item @code{max-read-interval} (default: @code{86400}) (type: seconds)
|
||||
A read plugin doubles the interval between queries after each failed
|
||||
attempt to get data. This options limits the maximum value of the
|
||||
interval.
|
||||
|
||||
@item @code{timeout} (type: maybe-integer)
|
||||
Consider a value list "missing" when no update has been read or received
|
||||
for @code{Iterations} iterations. By default, collectd considers a
|
||||
value list missing when no update has been received for twice the update
|
||||
interval. Since this setting uses iterations, the maximum allowed time
|
||||
without update depends on the @code{Interval} information contained in
|
||||
each value list. This is used in the @code{Threshold} configuration to
|
||||
dispatch notifications about missing values, see
|
||||
@code{collectd-threshold(5)} for details.
|
||||
|
||||
@item @code{read-threads} (default: @code{5}) (type: integer)
|
||||
Number of threads to start for reading plugins. You may want to
|
||||
increase this if you have more than five plugins that take a long time
|
||||
to read. Mostly those are plugins that do network-IO. Setting this to
|
||||
a value higher than the number of registered read callbacks is not
|
||||
recommended.
|
||||
|
||||
@item @code{write-threads} (default: @code{5}) (type: integer)
|
||||
Number of threads to start for dispatching value lists to write plugins.
|
||||
You may want to increase this if you have more than five plugins that
|
||||
may take relatively long to write to.
|
||||
|
||||
@item @code{write-queue-limit-high} (type: maybe-integer)
|
||||
Metrics are read by the read threads and then put into a queue to be
|
||||
handled by the write threads. If one of the write plugins is slow (e.g.
|
||||
network timeouts, I/O saturation of the disk) this queue will grow. In
|
||||
order to avoid running into memory issues in such a case, you can limit
|
||||
the size of this queue. If there are @code{write-queue-limit-high}
|
||||
metrics in the queue, any new metrics will be dropped. If the number of
|
||||
metrics currently in the queue is between @code{write-queue-limit-low}
|
||||
and @code{write-queue-limit-high}, the metric is dropped with a
|
||||
probability that is proportional to the number of metrics in the queue
|
||||
(i.e. it increases linearly until it reaches 100%).
|
||||
|
||||
@item @code{write-queue-limit-low} (type: maybe-integer)
|
||||
If there are less than @code{write-queue-limit-low} metrics in the
|
||||
queue, all new metrics will be enqueued. If
|
||||
@code{write-queue-limit-high} is set to non-zero and
|
||||
@code{write-queue-limit-low} is unset, the latter will default to half
|
||||
of @code{write-queue-limit-high}.
|
||||
|
||||
@item @code{host-name} (type: maybe-string)
|
||||
Sets the hostname that identifies a host. If you omit this setting, the
|
||||
hostname will be determined using the @code{gethostname(2)} system call.
|
||||
|
||||
@item @code{fully-qualified-domain-name-lookup?} (default: @code{#t}) (type: boolean)
|
||||
If @code{host-name} is determined automatically, this setting controls
|
||||
whether or not the daemon should try to figure out the
|
||||
@acronym{FQDN,fully qualified domain name}. This is done using a lookup
|
||||
of the name returned by @code{gethostname(2)}.
|
||||
|
||||
@item @code{plugins} (default: @code{()}) (type: list-of-collectd-plugins)
|
||||
Plugins to load, and their configurations.
|
||||
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
@c %end of fragment
|
||||
|
||||
@c %start of fragment
|
||||
|
||||
@deftp {Data Type} collectd-plugin-generic
|
||||
|
||||
The @code{collectd-plugin-generic} record can represent most collectd
|
||||
plugins.
|
||||
|
||||
As an example, this configuration will enable the CPU usage reporting
|
||||
plugin. See the @code{collectd.conf(5)} man page for a list of plugins
|
||||
and their options.
|
||||
|
||||
@lisp
|
||||
(collectd-plugin-generic
|
||||
(name "cpu")
|
||||
(options '((ReportByCpu . #t)
|
||||
(ReportByState . #t)
|
||||
(ValuesPercentage . #t))))
|
||||
@end lisp
|
||||
|
||||
Available @code{collectd-plugin-generic} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{load-plugin?} (default: @code{#t}) (type: boolean)
|
||||
When @code{#t}, include a @code{LoadPlugin} directive in the
|
||||
configuration. This interacts with @code{auto-load-plugin?} in
|
||||
@code{collectd-configuration}; if @code{collectd-configuration}'s
|
||||
@code{auto-load-plugin?} is @code{#f}, all plugins should set this to
|
||||
@code{#t}.
|
||||
|
||||
@item @code{name} (type: string)
|
||||
The name of the plugin.
|
||||
|
||||
@item @code{options} (default: @code{()}) (type: plugin-options)
|
||||
Options for the plugin.
|
||||
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
@c %end of fragment
|
||||
|
||||
@c %start of fragment
|
||||
|
||||
@deftp {Data Type} collectd-plugin-python
|
||||
|
||||
Users may extend collectd by writing plugins in Python, which run in a
|
||||
Python interpreter embedded into collectd. The
|
||||
@code{collectd-plugin-python} configuration record configures these
|
||||
plugins. See the @code{collectd-python(5)} man page for more
|
||||
information on Python support in collectd.
|
||||
|
||||
Guix-packaged plugins and dependencies listed in the @code{packages}
|
||||
field will be available in the Python plugin environment.
|
||||
|
||||
@lisp
|
||||
(collectd-plugin-python
|
||||
(packages (list python-myplugin))
|
||||
(module "myplugin")
|
||||
(module-options '((SomeOption . "hi")
|
||||
(AnotherOption . 123))))
|
||||
@end lisp
|
||||
|
||||
This configuration will emit a @code{ModulePath} line in the collectd
|
||||
configuration pointing at a profile containing Python, @code{python-myplugin},
|
||||
and any of its propagated inputs.
|
||||
|
||||
For plugin code not packaged for Guix, the @code{module-paths} field
|
||||
will emit verbatim @code{ModulePath} lines.
|
||||
|
||||
@lisp
|
||||
(collectd-plugin-python
|
||||
(module-paths
|
||||
(list
|
||||
"/home/users/projects/collectd-gpio/gpio"))
|
||||
(module "gpio")
|
||||
(module-options '((MonitorGPIOs 1 2 3 4))))
|
||||
@end lisp
|
||||
|
||||
The two mechanisms may be combined: a Guix-packaged Python library may
|
||||
be used by unpackaged plugin code.
|
||||
|
||||
@lisp
|
||||
(collectd-plugin-python
|
||||
(packages (list python-pymongo))
|
||||
(module-paths
|
||||
(list
|
||||
"/opt/collectd-mongodb/mongometrics"))
|
||||
(module "mongometrics")
|
||||
(module-options '((Host . "localhost"))))
|
||||
@end lisp
|
||||
|
||||
|
||||
Available @code{collectd-plugin-python} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{load-plugin?} (default: @code{#t}) (type: boolean)
|
||||
When @code{#t}, include a @code{LoadPlugin} directive in the
|
||||
configuration. This interacts with @code{auto-load-plugin?} in
|
||||
@code{collectd-configuration}; if @code{collectd-configuration}'s
|
||||
@code{auto-load-plugin?} is @code{#f}, all plugins should set this to
|
||||
@code{#t}.
|
||||
|
||||
@item @code{type-databases} (default: @code{()}) (type: list-of-file-likes)
|
||||
One or more files that contain the data-set descriptions. See
|
||||
@code{types.db(5)} for a description of the format of these files.
|
||||
|
||||
@item @code{packages} (default: @code{()}) (type: list-of-packages)
|
||||
Packages to make available to the Python plugin. These can be
|
||||
dependencies of the plugin code, or may contain the plugin. The
|
||||
plugin's @code{ModulePath} will point to a profile containing these
|
||||
packages.
|
||||
|
||||
@item @code{module-paths} (default: @code{()}) (type: list-of-string)
|
||||
Prepends entries to @code{sys.path}. You won’t be able to import any
|
||||
scripts you wrote unless they are located in one of the directories in
|
||||
this list. Please note that it only has effect on plugins loaded after
|
||||
this option.
|
||||
|
||||
@item @code{log-traces?} (default: @code{#f}) (type: boolean)
|
||||
If a Python script throws an exception it will be logged by collectd
|
||||
with the name of the exception and the message. If you set this option
|
||||
to true it will also log the full stacktrace just like the default
|
||||
output of an interactive Python interpreter. This does not apply to the
|
||||
@code{CollectError} exception, which will never log a stacktrace. This
|
||||
should probably be set to false most of the time but is very useful for
|
||||
development and debugging of new modules.
|
||||
|
||||
@item @code{interactive?} (default: @code{#f}) (type: boolean)
|
||||
This option will cause the module to launch an interactive Python
|
||||
interpreter that reads from and writes to the terminal. Note that
|
||||
collectd will terminate right after starting up if you try to run it as
|
||||
a daemon while this option is enabled so make sure to start collectd
|
||||
with the @code{-f} option. See the collectd-python(5) man page for more
|
||||
information on this option.
|
||||
|
||||
@item @code{module} (type: string)
|
||||
The name of the Python module to import into the collectd Python
|
||||
process. The module must be available in @code{packages} or
|
||||
@code{module-paths}, and register a MPD callback.
|
||||
|
||||
@item @code{module-options} (default: @code{()}) (type: alist)
|
||||
Options for the module.
|
||||
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
@c %end of fragment
|
||||
@node Kerberos Services
|
||||
@subsection Kerberos Services
|
||||
@cindex Kerberos
|
||||
|
|
|
|||
|
|
@ -21,24 +21,38 @@
|
|||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu services monitoring)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu services web)
|
||||
#:use-module (gnu packages admin)
|
||||
#:use-module (gnu packages monitoring)
|
||||
#:use-module (gnu packages networking)
|
||||
#:use-module (gnu packages python)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu services web)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu system shadow)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module ((guix modules) #:select (source-module-closure))
|
||||
#:use-module (guix packages)
|
||||
#:use-module ((guix profiles) #:select (packages->manifest
|
||||
profile
|
||||
profile-search-paths))
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix utils)
|
||||
#:use-module ((guix search-paths) #:select (search-path-specification-variable))
|
||||
#:use-module ((guix self) #:select (make-config.scm))
|
||||
#:use-module ((guix ui) #:select (display-hint G_))
|
||||
#:use-module (guix utils)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 rdelim)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module ((srfi srfi-2) #:select (and-let*))
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (srfi srfi-35)
|
||||
#:use-module ((srfi srfi-171) #:select (list-transduce
|
||||
rcons
|
||||
tconcatenate
|
||||
tfilter
|
||||
tmap))
|
||||
|
||||
#:export (darkstat-configuration
|
||||
darkstat-service-type
|
||||
|
||||
|
|
@ -94,7 +108,49 @@
|
|||
zabbix-agent-service-type
|
||||
zabbix-front-end-configuration
|
||||
zabbix-front-end-service-type
|
||||
%zabbix-front-end-configuration-nginx))
|
||||
%zabbix-front-end-configuration-nginx
|
||||
|
||||
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))
|
||||
|
||||
|
||||
;;;
|
||||
|
|
@ -1194,3 +1250,536 @@ with Zabbix server.")))
|
|||
`((zabbix-front-end-configuration
|
||||
,zabbix-front-end-configuration-fields))
|
||||
'zabbix-front-end-configuration))
|
||||
|
||||
|
||||
;;
|
||||
;; collectd
|
||||
;;
|
||||
|
||||
(define *indent* (make-parameter ""))
|
||||
|
||||
(defmacro with-indent (. body)
|
||||
`(parameterize ((*indent* (string-append (*indent*) " ")))
|
||||
,@body))
|
||||
|
||||
(define seconds? integer?)
|
||||
|
||||
(define-maybe/no-serialization seconds)
|
||||
|
||||
(define list-of-string? (list-of string?))
|
||||
|
||||
(define list-of-file-likes? (list-of file-like?))
|
||||
|
||||
(define (collectd-serialize-list-of-file-likes name value)
|
||||
#~(string-join
|
||||
(map
|
||||
(lambda (v) (format #f "~a~a \"~a\"" #$name #$(*indent*) v))
|
||||
'#$value)
|
||||
"\n" 'suffix))
|
||||
|
||||
(define (collectd-serialize-file-like name value)
|
||||
(collectd-serialize-list-of-file-likes name (list value)))
|
||||
|
||||
(define list-of-packages? (list-of package?))
|
||||
|
||||
(define (collectd-serialize-value value)
|
||||
(cond
|
||||
;; Strings get quoted and escaped.
|
||||
((string? value)
|
||||
(format #f "~s" value))
|
||||
|
||||
;; Keywords become unquoted strings (#:foo -> foo).
|
||||
((keyword? value)
|
||||
(collectd-serialize-value
|
||||
(keyword->symbol value)))
|
||||
|
||||
;; Booleans become bare words.
|
||||
((eq? value #t) "true")
|
||||
((eq? value #f) "false")
|
||||
|
||||
;; Alists serialize to lines of KEY VALUE.
|
||||
((alist? value)
|
||||
(apply string-append
|
||||
(map
|
||||
(generic-serialize-alist-entry collectd-serialize-field)
|
||||
value)))
|
||||
|
||||
;; Lists get their elements serialized and joined with a space.
|
||||
((list? value) (string-join (map collectd-serialize-value value) " "))
|
||||
|
||||
;; Other types (numbers etc) turn into bare strings.
|
||||
(else (object->string value))))
|
||||
|
||||
(define (collectd-serialize-field name value)
|
||||
(if (and (list? value) (null-list? value))
|
||||
""
|
||||
(format #nil "~a~a ~a~%" (*indent*) name
|
||||
(collectd-serialize-value value))))
|
||||
|
||||
(define (remap-names name-map serializer)
|
||||
"Renaming serializer.
|
||||
|
||||
Wraps `serializer', renaming fields according to `name-map', an alist of
|
||||
'((field-name . serialized-name))."
|
||||
(lambda (name value)
|
||||
(serializer (or (and=> (assoc name name-map) cdr) name) value)))
|
||||
|
||||
(define plugin-options? alist?)
|
||||
|
||||
(define (collectd-make-load-plugin?-serializer plugin-name)
|
||||
(lambda (_ load-plugin?)
|
||||
(if load-plugin?
|
||||
(collectd-serialize-field "LoadPlugin" plugin-name)
|
||||
"")))
|
||||
|
||||
;; Generic plugin support.
|
||||
|
||||
(define-configuration/no-serialization collectd-plugin-generic
|
||||
(load-plugin?
|
||||
(boolean #t)
|
||||
"When @code{#t}, include a @code{LoadPlugin} directive in the
|
||||
configuration. This interacts with @code{auto-load-plugin?} in
|
||||
@code{collectd-configuration}; if @code{collectd-configuration}'s
|
||||
@code{auto-load-plugin?} is @code{#f}, all plugins should set this to
|
||||
@code{#t}.")
|
||||
|
||||
(name
|
||||
string
|
||||
"The name of the plugin.")
|
||||
|
||||
(options
|
||||
(plugin-options '())
|
||||
"Options for the plugin."))
|
||||
|
||||
(define (collectd-serialize-plugin-generic _ value)
|
||||
(match-record value <collectd-plugin-generic>
|
||||
(name load-plugin? options)
|
||||
#~(string-join
|
||||
`("\n"
|
||||
,#$((collectd-make-load-plugin?-serializer name) #nil load-plugin?)
|
||||
,(string-append "<Plugin " #$name ">\n")
|
||||
,#$(with-indent (collectd-serialize-value options))
|
||||
"</Plugin>\n")
|
||||
"")))
|
||||
|
||||
;; Python plugin support.
|
||||
|
||||
(define (collectd-serialize-python-module name value)
|
||||
(apply string-append
|
||||
`(,(string-append (*indent*) "<Module "
|
||||
(collectd-serialize-value name)
|
||||
">")
|
||||
"\n"
|
||||
,@(with-indent
|
||||
(map
|
||||
(lambda (kvs)
|
||||
(collectd-serialize-field (car kvs) (cdr kvs)))
|
||||
value))
|
||||
,(string-append (*indent*) "</Module>"))))
|
||||
|
||||
(define collectd-plugin-python-remap
|
||||
'((module-paths . "ModulePath")
|
||||
(load-plugin? . "LoadPlugin")
|
||||
(log-traces? . "LogTraces")
|
||||
(interactive? . "Interactive")
|
||||
(type-databases . "TypesDB")
|
||||
(packages . "ModulePath")
|
||||
(module . "Import")))
|
||||
|
||||
(define collectd-serialize-plugin-python-field
|
||||
(remap-names collectd-plugin-python-remap
|
||||
collectd-serialize-field))
|
||||
|
||||
(define (collectd-plugin-python-serialize-packages name value)
|
||||
(define not-config?
|
||||
;; Select (guix …) and (gnu …) modules, except (guix config).
|
||||
(match-lambda
|
||||
(('guix 'config) #f)
|
||||
(('guix _ ...) #t)
|
||||
(('gnu _ ...) #t)
|
||||
(_ #f)))
|
||||
|
||||
;; Note that for this to work, `collectd-preprocess-config' must have
|
||||
;; propagated a Python package into the packages field being serialized.
|
||||
(define python-profile
|
||||
(profile
|
||||
(content
|
||||
(packages->manifest value))))
|
||||
|
||||
(with-imported-modules `(((guix config) => ,(make-config.scm))
|
||||
,@(source-module-closure
|
||||
'((guix profiles)
|
||||
(guix build utils))
|
||||
#:select? not-config?))
|
||||
#~(eval
|
||||
'(begin
|
||||
(use-modules (guix build utils)
|
||||
((guix profiles) #:select (profile-search-paths))
|
||||
((guix search-paths)
|
||||
#:select (search-path-specification-variable))
|
||||
(srfi srfi-1))
|
||||
(let ((guix-pythonpath
|
||||
(and=>
|
||||
(find
|
||||
(lambda (psp)
|
||||
(string=? "GUIX_PYTHONPATH"
|
||||
(search-path-specification-variable (car psp))))
|
||||
(profile-search-paths #$python-profile))
|
||||
cdr)))
|
||||
(unless guix-pythonpath
|
||||
(error "Profile contained no $GUIX_PYTHONPATH!"))
|
||||
(format #f "~a~a ~s~%"
|
||||
#$(*indent*)
|
||||
#$name
|
||||
guix-pythonpath)))
|
||||
(current-module))))
|
||||
|
||||
(define-configuration collectd-plugin-python
|
||||
(load-plugin?
|
||||
(boolean #t)
|
||||
"When @code{#t}, include a @code{LoadPlugin} directive in the
|
||||
configuration. This interacts with @code{auto-load-plugin?} in
|
||||
@code{collectd-configuration}; if @code{collectd-configuration}'s
|
||||
@code{auto-load-plugin?} is @code{#f}, all plugins should set this to
|
||||
@code{#t}."
|
||||
(serializer (collectd-make-load-plugin?-serializer "python")))
|
||||
|
||||
(type-databases
|
||||
(list-of-file-likes '())
|
||||
"One or more files that contain the data-set descriptions. See
|
||||
@code{types.db(5)} for a description of the format of these files."
|
||||
(serializer (remap-names collectd-plugin-python-remap
|
||||
collectd-serialize-list-of-file-likes)))
|
||||
|
||||
(packages
|
||||
(list-of-packages '())
|
||||
"Packages to make available to the Python plugin. These can be
|
||||
dependencies of the plugin code, or may contain the plugin. The plugin's
|
||||
@code{ModulePath} will point to a profile containing these packages."
|
||||
(serializer (remap-names collectd-plugin-python-remap
|
||||
collectd-plugin-python-serialize-packages)))
|
||||
|
||||
(module-paths
|
||||
(list-of-string '())
|
||||
"Prepends entries to @code{sys.path}. You won’t be able to import
|
||||
any scripts you wrote unless they are located in one of the
|
||||
directories in this list. Please note that it only has effect on
|
||||
plugins loaded after this option."
|
||||
(serializer collectd-serialize-plugin-python-field))
|
||||
|
||||
(log-traces?
|
||||
(boolean #f)
|
||||
"If a Python script throws an exception it will be logged by
|
||||
collectd with the name of the exception and the message. If you set
|
||||
this option to true it will also log the full stacktrace just like the
|
||||
default output of an interactive Python interpreter. This does not
|
||||
apply to the @code{CollectError} exception, which will never log a
|
||||
stacktrace. This should probably be set to false most of the time but
|
||||
is very useful for development and debugging of new modules."
|
||||
(serializer collectd-serialize-plugin-python-field))
|
||||
|
||||
(interactive?
|
||||
(boolean #f)
|
||||
"This option will cause the module to launch an interactive Python
|
||||
interpreter that reads from and writes to the terminal. Note that
|
||||
collectd will terminate right after starting up if you try to run it
|
||||
as a daemon while this option is enabled so make sure to start
|
||||
collectd with the @code{-f} option. See the collectd-python(5) man
|
||||
page for more information on this option."
|
||||
(serializer collectd-serialize-plugin-python-field))
|
||||
|
||||
(module
|
||||
string
|
||||
"The name of the Python module to import into the collectd Python
|
||||
process. The module must be available in @code{packages} or
|
||||
@code{module-paths}, and register a MPD callback."
|
||||
(serializer collectd-serialize-plugin-python-field))
|
||||
|
||||
(module-options
|
||||
(alist '())
|
||||
"Options for the module."
|
||||
(serializer (lambda (_ value) (collectd-serialize-value value)))))
|
||||
|
||||
(define (collectd-serialize-plugin-python _ value)
|
||||
(define (serialize-fields fields)
|
||||
(list-transduce
|
||||
(base-transducer value) rcons
|
||||
(filter-configuration-fields collectd-plugin-python-fields fields)))
|
||||
|
||||
(match-record
|
||||
value <collectd-plugin-python> (module)
|
||||
#~(string-append
|
||||
"\n"
|
||||
#$@(serialize-fields '(load-plugin? type-databases))
|
||||
"<Plugin python>\n"
|
||||
#$@(with-indent
|
||||
(append
|
||||
(serialize-fields '(log-traces? interactive? module-paths packages module))
|
||||
(list (*indent*) "<Module " (collectd-serialize-value module) ">\n")
|
||||
(with-indent (serialize-fields '(module-options)))
|
||||
(list (*indent*) "</Module>\n")))
|
||||
"</Plugin>\n")))
|
||||
|
||||
(define (collectd-plugin? x)
|
||||
;; XXX: Extend this if plugin-specific configuration records are
|
||||
;; added.
|
||||
(or (collectd-plugin-generic? x)
|
||||
(collectd-plugin-python? x)))
|
||||
|
||||
(define list-of-collectd-plugins? (list-of collectd-plugin?))
|
||||
|
||||
(define (collectd-serialize-plugin name value)
|
||||
((match value
|
||||
;; XXX: Extend this if plugin-specific configuration records are
|
||||
;; added.
|
||||
;; Note that these *must* return gexps, not strings, otherwise things
|
||||
;; like type-databases won't work.
|
||||
(($ <collectd-plugin-generic>) collectd-serialize-plugin-generic)
|
||||
(($ <collectd-plugin-python>) collectd-serialize-plugin-python))
|
||||
name value))
|
||||
|
||||
(define (collectd-serialize-list-of-plugins name value)
|
||||
#~(string-append
|
||||
#$@(map
|
||||
(lambda (v) (collectd-serialize-plugin name v))
|
||||
value)))
|
||||
|
||||
(define collectd-configuration-remap
|
||||
'((base-directory . "BaseDir")
|
||||
(auto-load-plugin? . "AutoLoadPlugin")
|
||||
(collect-internal-stats? . "CollectInternalStats")
|
||||
(type-databases . "TypesDB")
|
||||
(interval . "Interval")
|
||||
(max-read-interval . "MaxReadInterval")
|
||||
(timeout . "Timeout")
|
||||
(read-threads . "ReadThreads")
|
||||
(write-threads . "WriteThreads")
|
||||
(write-queue-limit-high . "WriteQueueLimitHigh")
|
||||
(write-queue-limit-low . "WriteQueueLimitLow")
|
||||
(host-name . "Hostname")
|
||||
(fully-qualified-domain-name-lookup? . "FQDNLookup")))
|
||||
|
||||
(define collectd-configuration-serialize-field
|
||||
(remap-names collectd-configuration-remap
|
||||
collectd-serialize-field))
|
||||
|
||||
(define %collectd-default-type-database
|
||||
(file-append collectd "/share/collectd/types.db"))
|
||||
|
||||
(define-configuration collectd-configuration
|
||||
(collectd
|
||||
(package collectd)
|
||||
"The collectd package to use."
|
||||
(serializer empty-serializer))
|
||||
|
||||
(base-directory
|
||||
(string "/var/lib/collectd")
|
||||
"Sets the base directory. This is the directory beneath which all
|
||||
@acronym{RRD, round-robin database} files are created. Possibly more
|
||||
subdirectories are created. This is also the working directory for
|
||||
collectd."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(auto-load-plugin?
|
||||
(boolean #f)
|
||||
"When set to @code{#f}, each plugin needs to be loaded explicitly,
|
||||
using @code{collectd-load-plugin}. If a @code{<Plugin ...>} block is
|
||||
encountered and no configuration handling callback for this plugin has
|
||||
been registered, a warning is logged and the block is ignored.
|
||||
|
||||
When set to true, explicit @code{LoadPlugin} statements are not
|
||||
required. Each @code{<Plugin ...>} block acts as if it was
|
||||
immediately preceded by a LoadPlugin statement. LoadPlugin statements
|
||||
are still required for plugins that don't provide any configuration,
|
||||
e.g. the @code{Load} plugin."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(collect-internal-stats?
|
||||
(boolean #f)
|
||||
"When @code{#t}, various statistics about the collectd daemon will
|
||||
be collected, with \"collectd\" as the plugin name."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(type-databases
|
||||
(list-of-file-likes (list %collectd-default-type-database))
|
||||
"One or more files that contain the data-set descriptions. See
|
||||
@code{types.db(5)} for a description of the format of these files."
|
||||
(serializer (remap-names collectd-configuration-remap
|
||||
collectd-serialize-list-of-file-likes)))
|
||||
|
||||
(interval
|
||||
(maybe-seconds 60)
|
||||
"Configures the interval in which to query the read plugins.
|
||||
Smaller values lead to a higher system load produced by
|
||||
collectd, while higher values lead to more coarse statistics.
|
||||
|
||||
Warning: You should set this once and then never touch it again. If
|
||||
you do, you will have to delete all your RRD files or know some
|
||||
serious RRDtool magic! (Assuming you're using the RRDtool or
|
||||
RRDCacheD plugin.)"
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(max-read-interval
|
||||
(seconds 86400)
|
||||
"A read plugin doubles the interval between queries after each
|
||||
failed attempt to get data.
|
||||
|
||||
This options limits the maximum value of the interval."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(timeout
|
||||
maybe-integer
|
||||
"Consider a value list \"missing\" when no update has been read or
|
||||
received for @code{Iterations} iterations. By default, collectd considers
|
||||
a value list missing when no update has been received for twice the
|
||||
update interval. Since this setting uses iterations, the maximum
|
||||
allowed time without update depends on the @code{Interval} information
|
||||
contained in each value list. This is used in the @code{Threshold}
|
||||
configuration to dispatch notifications about missing values, see
|
||||
@code{collectd-threshold(5)} for details."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(read-threads
|
||||
(integer 5)
|
||||
"Number of threads to start for reading plugins. You may want to
|
||||
increase this if you have more than five plugins that take a long time
|
||||
to read. Mostly those are plugins that do network-IO. Setting this to
|
||||
a value higher than the number of registered read callbacks is not
|
||||
recommended."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(write-threads
|
||||
(integer 5)
|
||||
"Number of threads to start for dispatching value lists to write
|
||||
plugins. You may want to increase this if you have more than five
|
||||
plugins that may take relatively long to write to."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(write-queue-limit-high
|
||||
maybe-integer
|
||||
"Metrics are read by the read threads and then put into a queue to
|
||||
be handled by the write threads. If one of the write plugins is
|
||||
slow (e.g. network timeouts, I/O saturation of the disk) this queue
|
||||
will grow. In order to avoid running into memory issues in such a
|
||||
case, you can limit the size of this queue.
|
||||
|
||||
If there are @code{write-queue-limit-high} metrics in the queue, any
|
||||
new metrics will be dropped.
|
||||
|
||||
If the number of metrics currently in the queue is between
|
||||
@code{write-queue-limit-low} and @code{write-queue-limit-high}, the
|
||||
metric is dropped with a probability that is proportional to the
|
||||
number of metrics in the queue (i.e. it increases linearly until it
|
||||
reaches 100%)."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(write-queue-limit-low
|
||||
maybe-integer
|
||||
"If there are less than @code{write-queue-limit-low} metrics in the
|
||||
queue, all new metrics will be enqueued.
|
||||
|
||||
If @code{write-queue-limit-high} is set to non-zero and
|
||||
@code{write-queue-limit-low} is unset, the latter will default to half
|
||||
of @code{write-queue-limit-high}."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(host-name
|
||||
maybe-string
|
||||
"Sets the hostname that identifies a host. If you omit this setting,
|
||||
the hostname will be determined using the @code{gethostname(2)} system
|
||||
call."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(fully-qualified-domain-name-lookup?
|
||||
(boolean #t)
|
||||
"If @code{host-name} is determined automatically, this setting
|
||||
controls whether or not the daemon should try to figure out the
|
||||
@acronym{FQDN, fully qualified domain name}. This is done using a
|
||||
lookup of the name returned by @code{gethostname(2)}."
|
||||
(serializer collectd-configuration-serialize-field))
|
||||
|
||||
(plugins
|
||||
(list-of-collectd-plugins '())
|
||||
"Plugins to load, and their configurations."
|
||||
(serializer collectd-serialize-list-of-plugins))
|
||||
|
||||
(prefix collectd-))
|
||||
|
||||
(define (collectd-propagate-python config python)
|
||||
"Rewrite config, adding python to Python plugins' packages."
|
||||
(collectd-configuration
|
||||
(inherit config)
|
||||
(plugins
|
||||
(map
|
||||
(lambda (plugin)
|
||||
(if (collectd-plugin-python? plugin)
|
||||
(collectd-plugin-python
|
||||
(inherit plugin)
|
||||
(packages
|
||||
;; Add the Python package collectd was built with to the
|
||||
;; plugin's package list. This allows profiles built from its
|
||||
;; packages field to compute GUIX_PYTHONPATH.
|
||||
(cons python (collectd-plugin-python-packages plugin))))
|
||||
plugin))
|
||||
(collectd-configuration-plugins config)))))
|
||||
|
||||
(define (collectd-configuration-python config)
|
||||
"Return the Python package collectd was built with, or #f."
|
||||
(and=> (assoc-ref (package-native-inputs
|
||||
(collectd-configuration-collectd config))
|
||||
"python")
|
||||
car))
|
||||
|
||||
(define (collectd-preprocess-config config)
|
||||
"Determine Python package from collectd and propagate it to Python plugins."
|
||||
(or (and=> (collectd-configuration-python config)
|
||||
(cut collectd-propagate-python config <>))
|
||||
config))
|
||||
|
||||
(define %collectd-pid-file "/var/run/collectd.pid")
|
||||
|
||||
(define (make-collectd-shepherd-service config)
|
||||
(let ((config-file
|
||||
(mixed-text-file
|
||||
"collectd.conf"
|
||||
(serialize-configuration (collectd-preprocess-config config)
|
||||
collectd-configuration-fields))))
|
||||
(match-record config <collectd-configuration> (collectd)
|
||||
(shepherd-service
|
||||
(provision '(collectd))
|
||||
(documentation "Run collectd.")
|
||||
(requirement '(user-processes networking))
|
||||
(start
|
||||
#~(make-forkexec-constructor
|
||||
(list #$(file-append collectd "/sbin/collectd")
|
||||
"-C" #$config-file
|
||||
"-B" ; Don't create base dir.
|
||||
"-P" #$%collectd-pid-file)
|
||||
#:pid-file #$%collectd-pid-file))
|
||||
(stop #~(make-kill-destructor))))))
|
||||
|
||||
(define (collectd-activation config)
|
||||
(match-record config <collectd-configuration> (base-directory)
|
||||
(with-imported-modules
|
||||
(source-module-closure '((guix build utils)))
|
||||
#~(begin
|
||||
(use-modules (guix build utils))
|
||||
(mkdir-p #$base-directory)))))
|
||||
|
||||
(define collectd-service-type
|
||||
(service-type
|
||||
(name 'collectd)
|
||||
(description "Run collectd")
|
||||
(extensions
|
||||
(list
|
||||
(service-extension shepherd-root-service-type
|
||||
(compose list make-collectd-shepherd-service))
|
||||
(service-extension activation-service-type
|
||||
collectd-activation)))
|
||||
(compose concatenate)
|
||||
(extend
|
||||
(lambda (config plugins)
|
||||
(collectd-configuration
|
||||
(inherit config)
|
||||
(plugins (append (collectd-configuration-plugins config) plugins)))))
|
||||
(default-value (collectd-configuration))))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue