1{ config, lib, pkgs, ... }:
2
3let
4 inherit (lib) escapeShellArgs mkEnableOption mkIf mkOption types;
5
6 cfg = config.services.loki;
7
8 prettyJSON = conf:
9 pkgs.runCommand "loki-config.json" { } ''
10 echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq 'del(._module)' > $out
11 '';
12
13in {
14 options.services.loki = {
15 enable = mkEnableOption (lib.mdDoc "loki");
16
17 user = mkOption {
18 type = types.str;
19 default = "loki";
20 description = lib.mdDoc ''
21 User under which the Loki service runs.
22 '';
23 };
24
25 package = lib.mkPackageOptionMD pkgs "grafana-loki" { };
26
27 group = mkOption {
28 type = types.str;
29 default = "loki";
30 description = lib.mdDoc ''
31 Group under which the Loki service runs.
32 '';
33 };
34
35 dataDir = mkOption {
36 type = types.path;
37 default = "/var/lib/loki";
38 description = lib.mdDoc ''
39 Specify the directory for Loki.
40 '';
41 };
42
43 configuration = mkOption {
44 type = (pkgs.formats.json {}).type;
45 default = {};
46 description = lib.mdDoc ''
47 Specify the configuration for Loki in Nix.
48 '';
49 };
50
51 configFile = mkOption {
52 type = types.nullOr types.path;
53 default = null;
54 description = lib.mdDoc ''
55 Specify a configuration file that Loki should use.
56 '';
57 };
58
59 extraFlags = mkOption {
60 type = types.listOf types.str;
61 default = [];
62 example = [ "--server.http-listen-port=3101" ];
63 description = lib.mdDoc ''
64 Specify a list of additional command line flags,
65 which get escaped and are then passed to Loki.
66 '';
67 };
68 };
69
70 config = mkIf cfg.enable {
71 assertions = [{
72 assertion = (
73 (cfg.configuration == {} -> cfg.configFile != null) &&
74 (cfg.configFile != null -> cfg.configuration == {})
75 );
76 message = ''
77 Please specify either
78 'services.loki.configuration' or
79 'services.loki.configFile'.
80 '';
81 }];
82
83 environment.systemPackages = [ cfg.package ]; # logcli
84
85 users.groups.${cfg.group} = { };
86 users.users.${cfg.user} = {
87 description = "Loki Service User";
88 group = cfg.group;
89 home = cfg.dataDir;
90 createHome = true;
91 isSystemUser = true;
92 };
93
94 systemd.services.loki = {
95 description = "Loki Service Daemon";
96 wantedBy = [ "multi-user.target" ];
97
98 serviceConfig = let
99 conf = if cfg.configFile == null
100 then prettyJSON cfg.configuration
101 else cfg.configFile;
102 in
103 {
104 ExecStart = "${cfg.package}/bin/loki --config.file=${conf} ${escapeShellArgs cfg.extraFlags}";
105 User = cfg.user;
106 Restart = "always";
107 PrivateTmp = true;
108 ProtectHome = true;
109 ProtectSystem = "full";
110 DevicePolicy = "closed";
111 NoNewPrivileges = true;
112 WorkingDirectory = cfg.dataDir;
113 };
114 };
115 };
116}