1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.logstash;
9 ops = lib.optionalString;
10 verbosityFlag = "--log.level " + cfg.logLevel;
11
12 logstashConf = pkgs.writeText "logstash.conf" ''
13 input {
14 ${cfg.inputConfig}
15 }
16
17 filter {
18 ${cfg.filterConfig}
19 }
20
21 output {
22 ${cfg.outputConfig}
23 }
24 '';
25
26 logstashSettingsYml = pkgs.writeText "logstash.yml" cfg.extraSettings;
27
28 logstashJvmOptionsFile = pkgs.writeText "jvm.options" cfg.extraJvmOptions;
29
30 logstashSettingsDir =
31 pkgs.runCommand "logstash-settings"
32 {
33 inherit logstashJvmOptionsFile;
34 inherit logstashSettingsYml;
35 preferLocalBuild = true;
36 }
37 ''
38 mkdir -p $out
39 ln -s $logstashSettingsYml $out/logstash.yml
40 ln -s $logstashJvmOptionsFile $out/jvm.options
41 '';
42in
43
44{
45 imports = [
46 (lib.mkRenamedOptionModule
47 [ "services" "logstash" "address" ]
48 [ "services" "logstash" "listenAddress" ]
49 )
50 (lib.mkRemovedOptionModule [
51 "services"
52 "logstash"
53 "enableWeb"
54 ] "The web interface was removed from logstash")
55 ];
56
57 ###### interface
58
59 options = {
60
61 services.logstash = {
62
63 enable = lib.mkOption {
64 type = lib.types.bool;
65 default = false;
66 description = "Enable logstash.";
67 };
68
69 package = lib.mkPackageOption pkgs "logstash" { };
70
71 plugins = lib.mkOption {
72 type = lib.types.listOf lib.types.path;
73 default = [ ];
74 example = lib.literalExpression "[ pkgs.logstash-contrib ]";
75 description = "The paths to find other logstash plugins in.";
76 };
77
78 dataDir = lib.mkOption {
79 type = lib.types.str;
80 default = "/var/lib/logstash";
81 description = ''
82 A path to directory writable by logstash that it uses to store data.
83 Plugins will also have access to this path.
84 '';
85 };
86
87 logLevel = lib.mkOption {
88 type = lib.types.enum [
89 "debug"
90 "info"
91 "warn"
92 "error"
93 "fatal"
94 ];
95 default = "warn";
96 description = "Logging verbosity level.";
97 };
98
99 filterWorkers = lib.mkOption {
100 type = lib.types.int;
101 default = 1;
102 description = "The quantity of filter workers to run.";
103 };
104
105 listenAddress = lib.mkOption {
106 type = lib.types.str;
107 default = "127.0.0.1";
108 description = "Address on which to start webserver.";
109 };
110
111 port = lib.mkOption {
112 type = lib.types.str;
113 default = "9292";
114 description = "Port on which to start webserver.";
115 };
116
117 inputConfig = lib.mkOption {
118 type = lib.types.lines;
119 default = "generator { }";
120 description = "Logstash input configuration.";
121 example = lib.literalExpression ''
122 '''
123 # Read from journal
124 pipe {
125 command => "''${config.systemd.package}/bin/journalctl -f -o json"
126 type => "syslog" codec => json {}
127 }
128 '''
129 '';
130 };
131
132 filterConfig = lib.mkOption {
133 type = lib.types.lines;
134 default = "";
135 description = "logstash filter configuration.";
136 example = ''
137 if [type] == "syslog" {
138 # Keep only relevant systemd fields
139 # https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
140 prune {
141 whitelist_names => [
142 "type", "@timestamp", "@version",
143 "MESSAGE", "PRIORITY", "SYSLOG_FACILITY"
144 ]
145 }
146 }
147 '';
148 };
149
150 outputConfig = lib.mkOption {
151 type = lib.types.lines;
152 default = "stdout { codec => rubydebug }";
153 description = "Logstash output configuration.";
154 example = ''
155 redis { host => ["localhost"] data_type => "list" key => "logstash" codec => json }
156 elasticsearch { }
157 '';
158 };
159
160 extraSettings = lib.mkOption {
161 type = lib.types.lines;
162 default = "";
163 description = "Extra Logstash settings in YAML format.";
164 example = ''
165 pipeline:
166 batch:
167 size: 125
168 delay: 5
169 '';
170 };
171
172 extraJvmOptions = lib.mkOption {
173 type = lib.types.lines;
174 default = "";
175 description = "Extra JVM options, one per line (jvm.options format).";
176 example = ''
177 -Xms2g
178 -Xmx2g
179 '';
180 };
181
182 };
183 };
184
185 ###### implementation
186
187 config = lib.mkIf cfg.enable {
188 systemd.services.logstash = {
189 description = "Logstash Daemon";
190 wantedBy = [ "multi-user.target" ];
191 path = [ pkgs.bash ];
192 serviceConfig = {
193 ExecStartPre = ''${pkgs.coreutils}/bin/mkdir -p "${cfg.dataDir}" ; ${pkgs.coreutils}/bin/chmod 700 "${cfg.dataDir}"'';
194 ExecStart = lib.concatStringsSep " " (
195 lib.filter (s: lib.stringLength s != 0) [
196 "${cfg.package}/bin/logstash"
197 "-w ${toString cfg.filterWorkers}"
198 (lib.concatMapStringsSep " " (x: "--path.plugins ${x}") cfg.plugins)
199 "${verbosityFlag}"
200 "-f ${logstashConf}"
201 "--path.settings ${logstashSettingsDir}"
202 "--path.data ${cfg.dataDir}"
203 ]
204 );
205 };
206 };
207 };
208}