diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index c45f3268b975..bbbd9362d0b1 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -591,6 +591,7 @@
./services/monitoring/loki.nix
./services/monitoring/longview.nix
./services/monitoring/mackerel-agent.nix
+ ./services/monitoring/metricbeat.nix
./services/monitoring/monit.nix
./services/monitoring/munin.nix
./services/monitoring/nagios.nix
diff --git a/nixos/modules/services/monitoring/metricbeat.nix b/nixos/modules/services/monitoring/metricbeat.nix
new file mode 100644
index 000000000000..b285559eaa9b
--- /dev/null
+++ b/nixos/modules/services/monitoring/metricbeat.nix
@@ -0,0 +1,152 @@
+{ config, lib, pkgs, ... }:
+
+let
+ inherit (lib)
+ attrValues
+ literalExample
+ mkEnableOption
+ mkIf
+ mkOption
+ types
+ ;
+ cfg = config.services.metricbeat;
+
+ settingsFormat = pkgs.formats.yaml {};
+
+in
+{
+ options = {
+
+ services.metricbeat = {
+
+ enable = mkEnableOption "metricbeat";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.metricbeat;
+ defaultText = literalExample "pkgs.metricbeat";
+ example = literalExample "pkgs.metricbeat7";
+ description = ''
+ The metricbeat package to use
+ '';
+ };
+
+ modules = mkOption {
+ description = ''
+ Metricbeat modules are responsible for reading metrics from the various sources.
+
+ This is like services.metricbeat.settings.metricbeat.modules,
+ but structured as an attribute set. This has the benefit that multiple
+ NixOS modules can contribute settings to a single metricbeat module.
+
+ A module can be specified multiple times by choosing a different <name>
+ for each, but setting to the same value.
+
+ See .
+ '';
+ default = {};
+ type = types.attrsOf (types.submodule ({ name, ... }: {
+ freeformType = settingsFormat.type;
+ options = {
+ module = mkOption {
+ type = types.str;
+ default = name;
+ defaultText = literalExample '''';
+ description = ''
+ The name of the module.
+
+ Look for the value after module: on the individual
+ module pages linked from .
+ '';
+ };
+ };
+ }));
+ example = {
+ system = {
+ metricsets = ["cpu" "load" "memory" "network" "process" "process_summary" "uptime" "socket_summary"];
+ enabled = true;
+ period = "10s";
+ processes = [".*"];
+ cpu.metrics = ["percentages" "normalized_percentages"];
+ core.metrics = ["percentages"];
+ };
+ };
+ };
+
+ settings = mkOption {
+ type = types.submodule {
+ freeformType = settingsFormat.type;
+ options = {
+
+ name = mkOption {
+ type = types.str;
+ default = "";
+ description = ''
+ Name of the beat. Defaults to the hostname.
+ See .
+ '';
+ };
+
+ tags = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ Tags to place on the shipped metrics.
+ See .
+ '';
+ };
+
+ metricbeat.modules = mkOption {
+ type = types.listOf settingsFormat.type;
+ default = [];
+ internal = true;
+ description = ''
+ The metric collecting modules. Use instead.
+
+ See .
+ '';
+ };
+ };
+ };
+ default = {};
+ description = ''
+ Configuration for metricbeat. See for supported values.
+ '';
+ };
+
+ };
+ };
+
+ config = mkIf cfg.enable {
+
+ assertions = [
+ {
+ # empty modules would cause a failure at runtime
+ assertion = cfg.settings.metricbeat.modules != [];
+ message = "services.metricbeat: You must configure one or more modules.";
+ }
+ ];
+
+ services.metricbeat.settings.metricbeat.modules = attrValues cfg.modules;
+
+ systemd.services.metricbeat = {
+ description = "metricbeat metrics shipper";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ ExecStart = ''
+ ${cfg.package}/bin/metricbeat \
+ -c ${settingsFormat.generate "metricbeat.yml" cfg.settings} \
+ --path.data $STATE_DIRECTORY \
+ --path.logs $LOGS_DIRECTORY \
+ ;
+ '';
+ Restart = "always";
+ DynamicUser = true;
+ ProtectSystem = "strict";
+ ProtectHome = "tmpfs";
+ StateDirectory = "metricbeat";
+ LogsDirectory = "metricbeat";
+ };
+ };
+ };
+}
diff --git a/nixos/tests/elk.nix b/nixos/tests/elk.nix
index fee350de65b5..db51aede0de9 100644
--- a/nixos/tests/elk.nix
+++ b/nixos/tests/elk.nix
@@ -56,6 +56,24 @@ let
'');
};
+ metricbeat = {
+ enable = true;
+ package = elk.metricbeat;
+ modules.system = {
+ metricsets = ["cpu" "load" "memory" "network" "process" "process_summary" "uptime" "socket_summary"];
+ enabled = true;
+ period = "5s";
+ processes = [".*"];
+ cpu.metrics = ["percentages" "normalized_percentages"];
+ core.metrics = ["percentages"];
+ };
+ settings = {
+ output.elasticsearch = {
+ hosts = ["127.0.0.1:9200"];
+ };
+ };
+ };
+
logstash = {
enable = true;
package = elk.logstash;
@@ -135,6 +153,16 @@ let
)
+ def has_metricbeat():
+ dictionary = {"query": {"match": {"event.dataset": {"query": "system.cpu"}}}}
+ return (
+ "curl --silent --show-error '${esUrl}/_search' "
+ + "-H 'Content-Type: application/json' "
+ + "-d '{}' ".format(json.dumps(dictionary))
+ + "| jq '.hits.total > 0'"
+ )
+
+
start_all()
one.wait_for_unit("elasticsearch.service")
@@ -161,6 +189,12 @@ let
"curl --silent --show-error 'http://localhost:5601/api/status' | jq .status.overall.state | grep green"
)
+ with subtest("Metricbeat is running"):
+ one.wait_for_unit("metricbeat.service")
+
+ with subtest("Metricbeat metrics arrive in elasticsearch"):
+ one.wait_until_succeeds(has_metricbeat() + " | tee /dev/console | grep 'true'")
+
with subtest("Logstash messages arive in elasticsearch"):
one.wait_until_succeeds(total_hits("flowers") + " | grep -v 0")
one.wait_until_succeeds(total_hits("dragons") + " | grep 0")
@@ -190,12 +224,14 @@ in pkgs.lib.mapAttrs mkElkTest {
logstash = pkgs.logstash6;
kibana = pkgs.kibana6;
journalbeat = pkgs.journalbeat6;
+ metricbeat = pkgs.metricbeat6;
}
else {
elasticsearch = pkgs.elasticsearch6-oss;
logstash = pkgs.logstash6-oss;
kibana = pkgs.kibana6-oss;
journalbeat = pkgs.journalbeat6;
+ metricbeat = pkgs.metricbeat6;
};
ELK-7 =
if enableUnfree
@@ -204,11 +240,13 @@ in pkgs.lib.mapAttrs mkElkTest {
logstash = pkgs.logstash7;
kibana = pkgs.kibana7;
journalbeat = pkgs.journalbeat7;
+ metricbeat = pkgs.metricbeat7;
}
else {
elasticsearch = pkgs.elasticsearch7-oss;
logstash = pkgs.logstash7-oss;
kibana = pkgs.kibana7-oss;
journalbeat = pkgs.journalbeat7;
+ metricbeat = pkgs.metricbeat7;
};
}
diff --git a/pkgs/misc/logging/beats/6.x.nix b/pkgs/misc/logging/beats/6.x.nix
index ce80b174d327..81b8ba0ab5bf 100644
--- a/pkgs/misc/logging/beats/6.x.nix
+++ b/pkgs/misc/logging/beats/6.x.nix
@@ -1,4 +1,4 @@
-{ lib, fetchFromGitHub, elk6Version, buildGoPackage, libpcap, systemd }:
+{ lib, fetchFromGitHub, elk6Version, buildGoPackage, libpcap, nixosTests, systemd }:
let beat = package : extraArgs : buildGoPackage (rec {
name = "${package}-${version}";
@@ -22,10 +22,17 @@ let beat = package : extraArgs : buildGoPackage (rec {
platforms = platforms.linux;
};
} // extraArgs);
-in {
+in rec {
filebeat6 = beat "filebeat" {meta.description = "Lightweight shipper for logfiles";};
heartbeat6 = beat "heartbeat" {meta.description = "Lightweight shipper for uptime monitoring";};
- metricbeat6 = beat "metricbeat" {meta.description = "Lightweight shipper for metrics";};
+ metricbeat6 = beat "metricbeat" {
+ meta.description = "Lightweight shipper for metrics";
+ passthru.tests =
+ assert metricbeat6.drvPath == nixosTests.elk.ELK-6.elkPackages.metricbeat.drvPath;
+ {
+ elk = nixosTests.elk.ELK-6;
+ };
+ };
packetbeat6 = beat "packetbeat" {
buildInputs = [ libpcap ];
meta.broken = true;
diff --git a/pkgs/misc/logging/beats/7.x.nix b/pkgs/misc/logging/beats/7.x.nix
index 43ea85508c69..77e14e96c54e 100644
--- a/pkgs/misc/logging/beats/7.x.nix
+++ b/pkgs/misc/logging/beats/7.x.nix
@@ -1,4 +1,4 @@
-{ lib, fetchFromGitHub, elk7Version, buildGoPackage, libpcap, systemd }:
+{ lib, fetchFromGitHub, elk7Version, buildGoPackage, libpcap, nixosTests, systemd }:
let beat = package : extraArgs : buildGoPackage (rec {
name = "${package}-${version}";
@@ -22,10 +22,17 @@ let beat = package : extraArgs : buildGoPackage (rec {
platforms = platforms.linux;
};
} // extraArgs);
-in {
+in rec {
filebeat7 = beat "filebeat" {meta.description = "Lightweight shipper for logfiles";};
heartbeat7 = beat "heartbeat" {meta.description = "Lightweight shipper for uptime monitoring";};
- metricbeat7 = beat "metricbeat" {meta.description = "Lightweight shipper for metrics";};
+ metricbeat7 = beat "metricbeat" {
+ meta.description = "Lightweight shipper for metrics";
+ passthru.tests =
+ assert metricbeat7.drvPath == nixosTests.elk.ELK-7.elkPackages.metricbeat.drvPath;
+ {
+ elk = nixosTests.elk.ELK-7;
+ };
+ };
packetbeat7 = beat "packetbeat" {
buildInputs = [ libpcap ];
meta.description = "Network packet analyzer that ships data to Elasticsearch";