about summary refs log tree commit diff
path: root/nixos/modules/services/logging
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-10 13:28:20 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-10 13:28:20 +0200
commit5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010 (patch)
treea6c0f605be6de3f372ae69905b331f9f75452da7 /nixos/modules/services/logging
parent6070bc016bd2fd945b04347e25cfd3738622d2ac (diff)
downloadnixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.gz
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.bz2
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.lz
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.xz
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.zst
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.zip
Move all of NixOS to nixos/ in preparation of the repository merge
Diffstat (limited to 'nixos/modules/services/logging')
-rw-r--r--nixos/modules/services/logging/klogd.nix42
-rw-r--r--nixos/modules/services/logging/logcheck.nix231
-rw-r--r--nixos/modules/services/logging/logrotate.nix38
-rw-r--r--nixos/modules/services/logging/logstash.nix161
-rw-r--r--nixos/modules/services/logging/rsyslogd.nix105
-rw-r--r--nixos/modules/services/logging/syslogd.nix124
6 files changed, 701 insertions, 0 deletions
diff --git a/nixos/modules/services/logging/klogd.nix b/nixos/modules/services/logging/klogd.nix
new file mode 100644
index 000000000000..d7d0bbf89a54
--- /dev/null
+++ b/nixos/modules/services/logging/klogd.nix
@@ -0,0 +1,42 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+{
+  ###### interface
+
+  options = {
+
+    services.klogd.enable = mkOption {
+      type = types.bool;
+      default = versionOlder (getVersion config.boot.kernelPackages.kernel) "3.5";
+      description = ''
+        Whether to enable klogd, the kernel log message processing
+        daemon.  Since systemd handles logging of kernel messages on
+        Linux 3.5 and later, this is only useful if you're running an
+        older kernel.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.klogd.enable {
+
+    jobs.klogd =
+      { description = "Kernel Log Daemon";
+
+        wantedBy = [ "multi-user.target" ];
+
+        path = [ pkgs.sysklogd ];
+
+        exec =
+          "klogd -c 1 -2 -n " +
+          "-k $(dirname $(readlink -f /run/booted-system/kernel))/System.map";
+      };
+
+  };
+
+}
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
new file mode 100644
index 000000000000..23f21b6a754d
--- /dev/null
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -0,0 +1,231 @@
+{config, pkgs, ...}:
+
+with pkgs.lib;
+
+let
+  cfg = config.services.logcheck;
+
+  defaultRules = pkgs.runCommand "logcheck-default-rules" {} ''
+                   cp -prd ${pkgs.logcheck}/etc/logcheck $out
+                   chmod u+w $out
+                   rm $out/logcheck.*
+                 '';
+
+  rulesDir = pkgs.symlinkJoin "logcheck-rules-dir" ([ defaultRules ] ++ cfg.extraRulesDirs);
+
+  configFile = pkgs.writeText "logcheck.conf" cfg.config;
+
+  logFiles = pkgs.writeText "logcheck.logfiles" cfg.files;
+
+  flags = "-r ${rulesDir} -c ${configFile} -L ${logFiles} -${levelFlag} -m ${cfg.mailTo}";
+
+  levelFlag = getAttrFromPath [cfg.level]
+    { "paranoid"    = "p";
+      "server"      = "s";
+      "workstation" = "w";
+    };
+
+  cronJob = ''
+    @reboot   logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags}
+    2 ${cfg.timeOfDay} * * * logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags}
+  '';
+
+  writeIgnoreRule = name: {level, regex, ...}:
+    pkgs.writeTextFile
+      { inherit name;
+        destination = "/ignore.d.${level}/${name}";
+        text = ''
+          ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ${regex}
+        '';
+      };
+
+  writeIgnoreCronRule = name: {level, user, regex, cmdline, ...}:
+    let escapeRegex = escape (stringToCharacters "\\[]{}()^$?*+|.");
+        cmdline_ = builtins.unsafeDiscardStringContext cmdline;
+        re = if regex != "" then regex else if cmdline_ == "" then ".*" else escapeRegex cmdline_;
+    in writeIgnoreRule "cron-${name}" {
+      inherit level;
+      regex = ''
+        (/usr/bin/)?cron\[[0-9]+\]: \(${user}\) CMD \(${re}\)$
+      '';
+    };
+
+  levelOption = mkOption {
+    default = "server";
+    type = types.uniq types.string;
+    description = ''
+      Set the logcheck level. Either "workstation", "server", or "paranoid".
+    '';
+  };
+
+  ignoreOptions = {
+    level = levelOption;
+
+    regex = mkOption {
+      default = "";
+      type = types.uniq types.string;
+      description = ''
+        Regex specifying which log lines to ignore.
+      '';
+    };
+  };
+
+  ignoreCronOptions = {
+    user = mkOption {
+      default = "root";
+      type = types.uniq types.string;
+      description = ''
+        User that runs the cronjob.
+      '';
+    };
+
+    cmdline = mkOption {
+      default = "";
+      type = types.uniq types.string;
+      description = ''
+        Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
+      '';
+    };
+
+    timeArgs = mkOption {
+      default = null;
+      type = types.nullOr (types.uniq types.string);
+      example = "02 06 * * *";
+      description = ''
+        "min hr dom mon dow" crontab time args, to auto-create a cronjob too.
+        Leave at null to not do this and just add a logcheck ignore rule.
+      '';
+    };
+  };
+
+in
+{
+  options = {
+    services.logcheck = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable the logcheck cron job.
+        '';
+      };
+
+      user = mkOption {
+        default = "logcheck";
+        type = types.uniq types.string;
+        description = ''
+          Username for the logcheck user.
+        '';
+      };
+
+      timeOfDay = mkOption {
+        default = "*";
+        example = "6";
+        type = types.uniq types.string;
+        description = ''
+          Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day.
+          Leave default (*) to run every hour. Of course when nothing special was logged,
+          logcheck will be silent.
+        '';
+      };
+
+      mailTo = mkOption {
+        default = "root";
+        example = "you@domain.com";
+        type = types.uniq types.string;
+        description = ''
+          Email address to send reports to.
+        '';
+      };
+
+      level = mkOption {
+        default = "server";
+        type = types.uniq types.string;
+        description = ''
+          Set the logcheck level. Either "workstation", "server", or "paranoid".
+        '';
+      };
+
+      config = mkOption {
+        default = "FQDN=1";
+        type = types.string;
+        description = ''
+          Config options that you would like in logcheck.conf.
+        '';
+      };
+
+      files = mkOption {
+        default = [ "/var/log/messages" ];
+        type = types.listOf types.path;
+        example = [ "/var/log/messages" "/var/log/mail" ];
+        description = ''
+          Which log files to check.
+        '';
+      };
+
+      extraRulesDirs = mkOption {
+        default = [];
+        example = "/etc/logcheck";
+        type = types.listOf types.path;
+        description = ''
+          Directories with extra rules.
+        '';
+      };
+
+      ignore = mkOption {
+        default = {};
+        description = ''
+          This option defines extra ignore rules.
+        '';
+        type = types.loaOf types.optionSet;
+        options = [ ignoreOptions ];
+      };
+
+      ignoreCron = mkOption {
+        default = {};
+        description = ''
+          This option defines extra ignore rules for cronjobs.
+        '';
+        type = types.loaOf types.optionSet;
+        options = [ ignoreOptions ignoreCronOptions ];
+      };
+
+      extraGroups = mkOption {
+        default = [];
+        type = types.listOf types.string;
+        example = [ "postdrop" "mongodb" ];
+        description = ''
+          Extra groups for the logcheck user, for example to be able to use sendmail,
+          or to access certain log files.
+        '';
+      };
+
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.logcheck.extraRulesDirs =
+        mapAttrsToList writeIgnoreRule cfg.ignore
+        ++ mapAttrsToList writeIgnoreCronRule cfg.ignoreCron;
+
+    users.extraUsers = singleton
+      { name = cfg.user;
+        shell = "/bin/sh";
+        description = "Logcheck user account";
+        extraGroups = cfg.extraGroups;
+      };
+
+    system.activationScripts.logcheck = ''
+      mkdir -m 700 -p /var/{lib,lock}/logcheck
+      chown ${cfg.user} /var/{lib,lock}/logcheck
+    '';
+
+    services.cron.systemCronJobs =
+        let withTime = name: {timeArgs, ...}: ! (builtins.isNull timeArgs);
+            mkCron = name: {user, cmdline, timeArgs, ...}: ''
+              ${timeArgs} ${user} ${cmdline}
+            '';
+        in mapAttrsToList mkCron (filterAttrs withTime cfg.ignoreCron)
+           ++ [ cronJob ];
+  };
+}
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
new file mode 100644
index 000000000000..c6c0d2ea2382
--- /dev/null
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -0,0 +1,38 @@
+{config, pkgs, ...}:
+
+with pkgs.lib;
+
+let
+  cfg = config.services.logrotate;
+
+  configFile = pkgs.writeText "logrotate.conf"
+    cfg.config;
+
+  cronJob = ''
+    5 * * * * root ${pkgs.logrotate}/sbin/logrotate ${configFile}
+  '';
+
+in
+{
+  options = {
+    services.logrotate = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Enable the logrotate cron job
+        '';
+      };
+
+      config = mkOption {
+        default = "";
+        description = ''
+          The contents of the logrotate config file
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.cron.systemCronJobs = [ cronJob ];
+  };
+}
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
new file mode 100644
index 000000000000..2f0eea505267
--- /dev/null
+++ b/nixos/modules/services/logging/logstash.nix
@@ -0,0 +1,161 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.logstash;
+
+  listToConfig = list: "[ " + (concatStringsSep ", " (map exprToConfig list)) + " ]";
+
+  hashToConfig = attrs:
+    let
+      attrNameToConfigList = name:
+        [ (exprToConfig name)  (exprToConfig (getAttr name attrs)) ];
+    in
+      "[ " +
+      (concatStringsSep ", " (map attrNameToConfigList (attrNames attrs))) +
+      " ]";
+
+  valueToConfig = nvpair: let name = nvpair.name; value = nvpair.value; in
+    if (isAttrs value) && ((!(value ? __type)) || value.__type == "repeated")
+      then ''
+        ${name} {
+          ${exprToConfig value}
+        }
+      ''
+      else "${name} => ${exprToConfig value}";
+
+  repeatedAttrsToConfig = values:
+      concatStringsSep "\n" (map valueToConfig values);
+
+  attrsToConfig = attrs:
+    let
+      attrToConfig = name: valueToConfig {
+        inherit name;
+        value = (getAttr name attrs);
+      };
+    in
+      concatStringsSep "\n" (map attrToConfig (attrNames attrs));
+
+  exprToConfig = expr:
+    let
+      isCustomType = expr: (isAttrs expr) && (expr ? __type);
+
+      isFloat = expr: (isCustomType expr) && (expr.__type == "float");
+
+      isHash = expr: (isCustomType expr) && (expr.__type == "hash");
+
+      isRepeatedAttrs = expr: (isCustomType expr) && (expr.__type == "repeated");
+    in
+      if builtins.isBool expr then (if expr then "true" else "false") else
+      if builtins.isString expr then ''"${expr}"'' else
+      if builtins.isInt expr then toString expr else
+      if isFloat expr then expr.value else
+      if isList expr then listToConfig expr else
+      if isHash expr then hashToConfig expr.value else
+      if isRepeatedAttrs expr then repeatedAttrsToConfig expr.values
+      else attrsToConfig expr;
+
+  mergeConfigs = configs:
+    let
+      op = attrs: newAttrs:
+        let
+          isRepeated = newAttrs ? __type && newAttrs.__type == "repeated";
+        in {
+            values = attrs.values ++ (if isRepeated then newAttrs.values else
+              map (name: { inherit name; value = getAttr name newAttrs; })
+              (attrNames newAttrs));
+          };
+    in (foldl op { values = []; } configs) // { __type = "repeated"; };
+
+in
+
+{
+  ###### interface
+
+  options = {
+    services.logstash = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Enable logstash.
+        '';
+      };
+
+      inputConfig = mkOption {
+        default = {};
+        description = ''
+          An attribute set (or an expression generated by mkNameValuePairs)
+          representing a logstash configuration's input section.
+          Logstash configs are name-value pairs, where values can be bools,
+          strings, numbers, arrays, hashes, or other name-value pairs,
+          and names are strings that can be repeated. Name-value pairs with no
+          repeats are represented by attr sets. Bools, strings, ints, and
+          arrays are mapped directly. Name-value pairs with repeats can be
+          generated by the config.lib.logstash.mkNameValuePairs function, which
+          takes a list of attrsets and combines them while preserving attribute
+          name duplicates if they occur. Similarly, there are the mkFloat and
+          mkHash functions, which take a string representation of a float and an
+          attrset, respectively.
+        '';
+        merge = mergeConfigs;
+      };
+
+      filterConfig = mkOption {
+        default = {};
+        description = ''
+          An attribute set (or an expression generated by mkNameValuePairs)
+          representing a logstash configuration's filter section.
+          See inputConfig description for details.
+        '';
+        merge = mergeConfigs;
+      };
+
+      outputConfig = mkOption {
+        default = {};
+        description = ''
+          An attribute set (or an expression generated by mkNameValuePairs)
+          representing a logstash configuration's output section.
+          See inputConfig description for details.
+        '';
+        merge = mergeConfigs;
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkMerge [ {
+    lib.logstash = {
+      mkFloat = stringRep: { __type = "float"; value = stringRep; };
+
+      mkHash = attrs: { __type = "hash"; value = attrs; };
+
+      mkNameValuePairs = mergeConfigs;
+    };
+  } ( mkIf cfg.enable {
+    systemd.services.logstash = with pkgs; {
+      description = "Logstash daemon";
+
+      wantedBy = [ "multi-user.target" ];
+
+      path = [ jre ];
+
+      script = "cd /tmp && exec java -jar ${logstash} agent -f ${writeText "logstash.conf" ''
+        input {
+          ${exprToConfig cfg.inputConfig}
+        }
+
+        filter {
+          ${exprToConfig cfg.filterConfig}
+        }
+
+        output {
+          ${exprToConfig cfg.outputConfig}
+        }
+      ''} &> /var/log/logstash.log";
+    };
+  })];
+}
diff --git a/nixos/modules/services/logging/rsyslogd.nix b/nixos/modules/services/logging/rsyslogd.nix
new file mode 100644
index 000000000000..680c7a912c1f
--- /dev/null
+++ b/nixos/modules/services/logging/rsyslogd.nix
@@ -0,0 +1,105 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.rsyslogd;
+
+  syslogConf = pkgs.writeText "syslog.conf" ''
+    $ModLoad imuxsock
+    $SystemLogSocketName /run/systemd/journal/syslog
+    $WorkDirectory /var/spool/rsyslog
+
+    ${cfg.defaultConfig}
+    ${cfg.extraConfig}
+  '';
+
+  defaultConf = ''
+    # "local1" is used for dhcpd messages.
+    local1.*                     -/var/log/dhcpd
+
+    mail.*                       -/var/log/mail
+
+    *.=warning;*.=err            -/var/log/warn
+    *.crit                        /var/log/warn
+
+    *.*;mail.none;local1.none    -/var/log/messages
+  '';
+
+in
+
+{
+  ###### interface
+
+  options = {
+
+    services.rsyslogd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable syslogd.  Note that systemd also logs
+          syslog messages, so you normally don't need to run syslogd.
+        '';
+      };
+
+      defaultConfig = mkOption {
+        type = types.string;
+        default = defaultConf;
+        description = ''
+          The default <filename>syslog.conf</filename> file configures a
+          fairly standard setup of log files, which can be extended by
+          means of <varname>extraConfig</varname>.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.string;
+        default = "";
+        example = "news.* -/var/log/news";
+        description = ''
+          Additional text appended to <filename>syslog.conf</filename>,
+          i.e. the contents of <varname>defaultConfig</varname>.
+        '';
+      };
+
+      extraParams = mkOption {
+        type = types.listOf types.string;
+        default = [ ];
+        example = [ "-m 0" ];
+        description = ''
+          Additional parameters passed to <command>rsyslogd</command>.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.rsyslog ];
+
+    systemd.services.syslog =
+      { description = "Syslog Daemon";
+
+        requires = [ "syslog.socket" ];
+
+        wantedBy = [ "multi-user.target" ];
+
+        serviceConfig =
+          { ExecStart = "${pkgs.rsyslog}/sbin/rsyslogd ${toString cfg.extraParams} -f ${syslogConf} -n";
+            ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/spool/rsyslog";
+            # Prevent syslogd output looping back through journald.
+            StandardOutput = "null";
+          };
+      };
+
+  };
+
+}
diff --git a/nixos/modules/services/logging/syslogd.nix b/nixos/modules/services/logging/syslogd.nix
new file mode 100644
index 000000000000..24cd5c1567e7
--- /dev/null
+++ b/nixos/modules/services/logging/syslogd.nix
@@ -0,0 +1,124 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.syslogd;
+
+  syslogConf = pkgs.writeText "syslog.conf" ''
+    ${if (cfg.tty != "") then "kern.warning;*.err;authpriv.none /dev/${cfg.tty}" else ""}
+    ${cfg.defaultConfig}
+    ${cfg.extraConfig}
+  '';
+
+  defaultConf = ''
+    # Send emergency messages to all users.
+    *.emerg                       *
+
+    # "local1" is used for dhcpd messages.
+    local1.*                     -/var/log/dhcpd
+
+    mail.*                       -/var/log/mail
+
+    *.=warning;*.=err            -/var/log/warn
+    *.crit                        /var/log/warn
+
+    *.*;mail.none;local1.none    -/var/log/messages
+  '';
+
+in
+
+{
+  ###### interface
+
+  options = {
+
+    services.syslogd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable syslogd.  Note that systemd also logs
+          syslog messages, so you normally don't need to run syslogd.
+        '';
+      };
+
+      tty = mkOption {
+        type = types.uniq types.string;
+        default = "tty10";
+        description = ''
+          The tty device on which syslogd will print important log
+          messages. Leave this option blank to disable tty logging.
+        '';
+      };
+
+      defaultConfig = mkOption {
+        type = types.string;
+        default = defaultConf;
+        description = ''
+          The default <filename>syslog.conf</filename> file configures a
+          fairly standard setup of log files, which can be extended by
+          means of <varname>extraConfig</varname>.
+        '';
+      };
+
+      enableNetworkInput = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Accept logging through UDP. Option -r of syslogd(8).
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.string;
+        default = "";
+        example = "news.* -/var/log/news";
+        description = ''
+          Additional text appended to <filename>syslog.conf</filename>,
+          i.e. the contents of <varname>defaultConfig</varname>.
+        '';
+      };
+
+      extraParams = mkOption {
+        type = types.listOf types.string;
+        default = [ ];
+        example = [ "-m 0" ];
+        description = ''
+          Additional parameters passed to <command>syslogd</command>.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.sysklogd ];
+
+    services.syslogd.extraParams = optional cfg.enableNetworkInput "-r";
+
+    # FIXME: restarting syslog seems to break journal logging.
+    systemd.services.syslog =
+      { description = "Syslog Daemon";
+
+        requires = [ "syslog.socket" ];
+
+        wantedBy = [ "multi-user.target" ];
+
+        serviceConfig =
+          { ExecStart = "${pkgs.sysklogd}/sbin/syslogd ${toString cfg.extraParams} -f ${syslogConf} -n";
+            # Prevent syslogd output looping back through journald.
+            StandardOutput = "null";
+          };
+      };
+
+  };
+
+}