Nix Observability Daemon
observability nix
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 148 lines 5.1 kB view raw
1{ 2 description = "A simple self-contained daemon to gather nix statistics"; 3 4 inputs = { 5 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 rust-overlay.url = "github:oxalica/rust-overlay"; 7 rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; 8 }; 9 10 outputs = { 11 self, 12 nixpkgs, 13 rust-overlay, 14 }: let 15 systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"]; 16 forAllSystems = f: 17 nixpkgs.lib.genAttrs systems (system: 18 f (import nixpkgs { 19 inherit system; 20 overlays = [(import rust-overlay)]; 21 })); 22 in { 23 packages = forAllSystems (pkgs: { 24 default = pkgs.rustPlatform.buildRustPackage { 25 pname = "nod"; 26 version = "0.1.0"; 27 src = ./.; 28 cargoLock.lockFile = ./Cargo.lock; 29 30 nativeBuildInputs = [pkgs.pkg-config]; 31 buildInputs = 32 [pkgs.sqlite] 33 ++ ( 34 if pkgs.stdenv.isDarwin 35 then [pkgs.iconv] 36 else [] 37 ); 38 }; 39 }); 40 devShells = forAllSystems (pkgs: { 41 default = pkgs.mkShell { 42 buildInputs = 43 [ 44 pkgs.rust-bin.stable.latest.default 45 pkgs.pkg-config 46 pkgs.sqlite 47 ] 48 ++ ( 49 if pkgs.stdenv.isDarwin 50 then [pkgs.iconv] 51 else [] 52 ); 53 }; 54 }); 55 56 nixosModules.default = { 57 config, 58 lib, 59 pkgs, 60 ... 61 }: let 62 cfg = config.services.nod; 63 in { 64 options.services.nod = { 65 enable = lib.mkEnableOption "Nix Observability Daemon"; 66 package = lib.mkOption { 67 type = lib.types.package; 68 default = self.packages.${pkgs.system}.default; 69 description = "The nod package to use."; 70 }; 71 user = lib.mkOption { 72 type = lib.types.str; 73 default = "nod"; 74 description = "User to run the nod daemon as."; 75 }; 76 group = lib.mkOption { 77 type = lib.types.str; 78 default = "nod"; 79 description = '' 80 Group for the nod daemon. Other services that need read access to the database (e.g. a monitoring agent) should be added to this group. 81 ''; 82 }; 83 84 socketPath = lib.mkOption { 85 type = lib.types.path; 86 default = "/run/nod/nod.sock"; 87 description = "Path to the Unix socket. Propagated to all sessions via /etc/environment so nod always finds the daemon without --socket."; 88 }; 89 databasePath = lib.mkOption { 90 type = lib.types.path; 91 default = "/var/lib/nod/nod.db"; 92 description = "Path to the SQLite database."; 93 }; 94 retainDays = lib.mkOption { 95 type = lib.types.nullOr lib.types.ints.positive; 96 default = null; 97 description = "Override the retention period in days. When null the daemon default of 180 days is used."; 98 }; 99 }; 100 101 config = lib.mkIf cfg.enable { 102 users.users.${cfg.user} = { 103 isSystemUser = true; 104 group = cfg.group; 105 description = "Nix Observability Daemon"; 106 }; 107 users.groups.${cfg.group} = {}; 108 109 # Forward Nix's internal JSON activity log to the daemon socket. 110 # The nix-daemon runs as root so the socket directory must be world-searchable 111 # and the socket itself must be group-writable (handled by RuntimeDirectoryMode 112 # and UMask below). Users that only need to query nod require no group membership. 113 nix.settings.json-log-path = cfg.socketPath; 114 115 # Expose the socket path to every session (login, SSH, scripts) via /etc/environment 116 # so that `nod` always resolves the socket without needing --socket or NOD_SOCKET set 117 # manually. sessionVariables only reaches interactive login shells and would cause 118 # "cannot connect to socket" errors in non-login SSH sessions and cron jobs. 119 environment.variables.NOD_SOCKET = cfg.socketPath; 120 environment.variables.NOD_DB = cfg.databasePath; 121 122 # Make `nod` available to all users without manual systemPackages entries. 123 environment.systemPackages = [ cfg.package ]; 124 125 systemd.services.nod = { 126 description = "Nix Observability Daemon"; 127 wantedBy = ["multi-user.target"]; 128 after = ["local-fs.target"]; 129 130 serviceConfig = { 131 User = cfg.user; 132 Group = cfg.group; 133 ExecStart = "${cfg.package}/bin/nod daemon --db ${cfg.databasePath} --socket ${cfg.socketPath}" 134 + lib.optionalString (cfg.retainDays != null) " --retain-days ${toString cfg.retainDays}"; 135 Restart = "always"; 136 StateDirectory = "nod"; 137 StateDirectoryMode = "0750"; 138 # /run/nod must be world-searchable so nix (running as any user) can reach the socket. 139 RuntimeDirectory = "nod"; 140 RuntimeDirectoryMode = "0755"; 141 # SQLite WAL mode requires write access to the -shm file even for read-only connections. 142 UMask = "0117"; 143 }; 144 }; 145 }; 146 }; 147 }; 148}