at master 4.0 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 inherit (lib) 10 escapeShellArgs 11 mkEnableOption 12 mkIf 13 mkOption 14 types 15 ; 16 17 cfg = config.services.loki; 18 19 prettyJSON = 20 conf: 21 pkgs.runCommand "loki-config.json" { } '' 22 echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq 'del(._module)' > $out 23 ''; 24 25in 26{ 27 options.services.loki = { 28 enable = mkEnableOption "Grafana Loki"; 29 30 user = mkOption { 31 type = types.str; 32 default = "loki"; 33 description = '' 34 User under which the Loki service runs. 35 ''; 36 }; 37 38 package = lib.mkPackageOption pkgs "grafana-loki" { }; 39 40 group = mkOption { 41 type = types.str; 42 default = "loki"; 43 description = '' 44 Group under which the Loki service runs. 45 ''; 46 }; 47 48 dataDir = mkOption { 49 type = types.path; 50 default = "/var/lib/loki"; 51 description = '' 52 Specify the data directory for Loki. 53 ''; 54 }; 55 56 configuration = mkOption { 57 type = (pkgs.formats.json { }).type; 58 default = { }; 59 description = '' 60 Specify the configuration for Loki in Nix. 61 62 See [documentation of Grafana Loki](https://grafana.com/docs/loki/latest/configure/) for all available options. 63 64 Cannot be specified together with {option}`services.loki.configFile`. 65 ''; 66 }; 67 68 configFile = mkOption { 69 type = types.nullOr types.path; 70 default = null; 71 description = '' 72 Specify a configuration file that Loki should use. 73 74 Cannot be specified together with {option}`services.loki.configuration`. 75 ''; 76 }; 77 78 extraFlags = mkOption { 79 type = types.listOf types.str; 80 default = [ ]; 81 example = [ "--server.http-listen-port=3101" ]; 82 description = '' 83 Specify a list of additional command line flags, 84 which get escaped and are then passed to Loki. 85 ''; 86 }; 87 }; 88 89 config = mkIf cfg.enable { 90 assertions = [ 91 { 92 assertion = ( 93 (cfg.configuration == { } -> cfg.configFile != null) 94 && (cfg.configFile != null -> cfg.configuration == { }) 95 ); 96 message = '' 97 Please specify either 98 'services.loki.configuration' or 99 'services.loki.configFile'. 100 ''; 101 } 102 ]; 103 104 environment.systemPackages = [ cfg.package ]; # logcli 105 106 users.groups.${cfg.group} = { }; 107 users.users.${cfg.user} = { 108 description = "Loki Service User"; 109 group = cfg.group; 110 home = cfg.dataDir; 111 createHome = true; 112 isSystemUser = true; 113 }; 114 115 systemd.services.loki = { 116 description = "Loki Service Daemon"; 117 wants = [ "network-online.target" ]; 118 after = [ "network-online.target" ]; 119 wantedBy = [ "multi-user.target" ]; 120 121 serviceConfig = 122 let 123 conf = 124 if cfg.configFile == null then 125 # Config validation may fail when using extraFlags = [ "-config.expand-env=true" ]. 126 # To work around this, we simply skip it when extraFlags is not empty. 127 if cfg.extraFlags == [ ] then 128 validateConfig (prettyJSON cfg.configuration) 129 else 130 prettyJSON cfg.configuration 131 else 132 cfg.configFile; 133 validateConfig = 134 file: 135 pkgs.runCommand "validate-loki-conf" 136 { 137 nativeBuildInputs = [ cfg.package ]; 138 } 139 '' 140 loki -verify-config -config.file "${file}" 141 ln -s "${file}" "$out" 142 ''; 143 in 144 { 145 ExecStart = "${cfg.package}/bin/loki --config.file=${conf} ${escapeShellArgs cfg.extraFlags}"; 146 User = cfg.user; 147 Restart = "always"; 148 PrivateTmp = true; 149 ProtectHome = true; 150 ProtectSystem = "full"; 151 DevicePolicy = "closed"; 152 NoNewPrivileges = true; 153 WorkingDirectory = cfg.dataDir; 154 }; 155 }; 156 }; 157}