Add a default logging parameter to daemon command invocations to make diagnosing problems easier, add a troubleshooting section to the README.md that explains how to investigate logs

This commit is contained in:
Sander van der Burg 2020-08-19 20:34:23 +02:00 committed by Sander van der Burg
parent dad1f2f7ca
commit 5bf40eb7d5
11 changed files with 94 additions and 12 deletions

View File

@ -75,7 +75,13 @@ $ nix-env -f default.nix -iA sysvinit
```
To work with a different process manager, you should replace `sysvinit` with
any of the supported process managers listed above.
any of the supported process managers listed in the previous section. For
example, to use utilities to generate and deploy `systemd` configurations, you
should run:
```bash
$ nix-env -f default.nix -iA systemd
```
Usage
=====
@ -653,6 +659,50 @@ This repository contains three example systems, that can be found in the
files so that these system services can be deployed as Disnix containers --
services in which other services can be hosted.
Troubleshooting
===============
This section contains a number of known problems and their resolutions.
Inspecting log files
--------------------
When a service does not work as expected, then it is typically desired to check
the logs of the corresponding service. Although many process management concepts
are standardized by this framework, logging is not standardized at all.
This section contains some pointers for some of the process management solution
targets that are currently implemented.
### systemd and docker
Some process/service managers have their own logging facility. For example,
`systemd` provides `journalctl`, and `docker` provides `docker logs`. They
automatically capture the output (the `stdout` and `stderr`) of foreground
processes.
### sysvinit, bsdrc, disnix
For process management solutions that rely on processes that deamonize on their
own (`sysvinit`, `bsdrc` and `disnix`), you need to consult the logs that are
managed by the services themselves (a daemon typically detaches itself from the
`stdout` and `stderr`. As a result, a process manager cannot do it).
Services that only provide foreground processes are automatically daemonized
with the `daemon` command by these three backends. By default, the `daemon`
command will capture their outputs in log files with a `nixproc-` prefix in
the log directory. On a production system, such a log file could be:
`/var/log/nixproc-myservice.log`.
### supervisord
`supervisord` will (if no settings have been configured) store log files
(capturing the `stdout` and `stderr` of each process) in the temp directory
(typically `/tmp` or the value of the `TMPDIR` environment variable).
### cygrunsrv
By default, the `stderr` of `cygrunsrv` managed services are captured in the log
folder. An example could be: `/var/log/myservice.log`.
License
=======
The contents of this package is available under the same license as Nixpkgs --

View File

@ -10,7 +10,7 @@
let
createManagedProcess = import ../../nixproc/create-managed-process/agnostic/create-managed-process-universal.nix {
inherit pkgs runtimeDir stateDir tmpDir forceDisableUserChange processManager;
inherit pkgs runtimeDir stateDir logDir tmpDir forceDisableUserChange processManager;
};
in
{

View File

@ -32,7 +32,7 @@ rec {
};
};
postgresql = rec {
/*postgresql = rec {
port = 6432;
pkg = constructors.postgresql {
@ -69,5 +69,5 @@ rec {
docker = {
pkg = constructors.docker;
};
};*/
}

View File

@ -10,7 +10,7 @@
let
createManagedProcess = import ../../nixproc/create-managed-process/agnostic/create-managed-process-universal.nix {
inherit pkgs runtimeDir stateDir tmpDir forceDisableUserChange processManager;
inherit pkgs runtimeDir stateDir logDir tmpDir forceDisableUserChange processManager;
};
webappExpr = if webappMode == "foreground" then ./webapp-fg.nix

View File

@ -9,7 +9,7 @@
let
createSystemVInitScript = import ../../nixproc/create-managed-process/sysvinit/create-sysvinit-script.nix {
inherit (pkgs) stdenv writeTextFile daemon;
inherit runtimeDir tmpDir forceDisableUserChange;
inherit runtimeDir logDir tmpDir forceDisableUserChange;
createCredentials = import ../../nixproc/create-credentials {
inherit (pkgs) stdenv;

View File

@ -4,6 +4,7 @@
, pkgs ? import <nixpkgs> { inherit system; }
, stateDir ? "/var"
, runtimeDir ? "${stateDir}/run"
, logDir ? "${stateDir}/log"
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
, forceDisableUserChange ? false
}:
@ -12,7 +13,7 @@ let
createManagedProcessFromConfig = configFile:
let
createManagedProcess = import ./create-managed-process-universal.nix {
inherit pkgs stateDir runtimeDir tmpDir forceDisableUserChange processManager;
inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager;
};
properties = builtins.fromJSON (builtins.readFile configFile);

View File

@ -1,4 +1,4 @@
{pkgs, runtimeDir, tmpDir, stateDir, forceDisableUserChange ? false, processManager ? null}:
{pkgs, runtimeDir, logDir, tmpDir, stateDir, forceDisableUserChange ? false, processManager ? null}:
let
basePackages = [
@ -14,7 +14,7 @@ let
createSystemVInitScript = import ../sysvinit/create-sysvinit-script.nix {
inherit (pkgs) stdenv writeTextFile daemon;
inherit createCredentials runtimeDir tmpDir forceDisableUserChange;
inherit createCredentials runtimeDir logDir tmpDir forceDisableUserChange;
initFunctions = import ../sysvinit/init-functions.nix {
inherit (pkgs) stdenv fetchurl;
@ -90,7 +90,7 @@ let
generateProcessScript = import ../agnostic/generate-process-script.nix {
inherit (pkgs) stdenv writeTextFile daemon;
inherit createProcessScript runtimeDir tmpDir forceDisableUserChange basePackages;
inherit createProcessScript runtimeDir logDir tmpDir forceDisableUserChange basePackages;
};
createDockerContainer = import ../docker/create-docker-container.nix {

View File

@ -1,5 +1,5 @@
{ createProcessScript, writeTextFile, stdenv, daemon, basePackages
, runtimeDir, tmpDir, forceDisableUserChange
, runtimeDir, logDir, tmpDir, forceDisableUserChange
}:
let
@ -62,6 +62,10 @@ let
args = foregroundProcessArgs;
pidFile = _pidFile;
user = _user;
outputLogFile = util.autoGenerateDaemonLogFilePath {
inherit name instanceName logDir;
enableDaemonOutputLogging = true;
};
inherit pidFilesDir;
}
else throw "I don't know how to start this process!";

View File

@ -12,6 +12,8 @@
, defaultStopSignal ? "TERM"
# Default run time directory where PID files are stored
, runtimeDir ? "/var/run"
# Directory in which log files are stored
, logDir ? "/var/log"
# Directory in which temp files are stored
, tmpDir ? "/tmp"
# Specifies whether user changing functionality should be disabled or not
@ -31,6 +33,8 @@ name
, commandArgs ? []
# Specifies whether the command daemonizes or not. If the command is not a daemon, it gets daemonized by the generator
, commandIsDaemon ? true
# Whether to disable logging the daemon process' output
, enableDaemonOutputLogging ? true
# Specifies the signal that needs to be sent to reload a process
, reloadSignal ? "HUP"
# Specifies the signal that needs to be sent to stop a process
@ -92,9 +96,14 @@ let
inherit user forceDisableUserChange;
};
outputLogFile = util.autoGenerateDaemonLogFilePath {
inherit name instanceName logDir enableDaemonOutputLogging;
};
_command = if commandIsDaemon then command else "daemon";
_commandArgs = if commandIsDaemon then commandArgs else
stdenv.lib.optionals (pidFile != null) [ "-p" pidFile ]
++ stdenv.lib.optionals (outputLogFile != null) [ "-o" outputLogFile ]
++ [ command ]
++ commandArgs;

View File

@ -20,6 +20,8 @@
, statusCommand ? "statusproc"
# Default run time directory where PID files are stored
, runtimeDir ? "/var/run"
# Directory in which log files are stored
, logDir ? "/var/log"
# Directory in which temp files are stored
, tmpDir ? "/tmp"
# Specifies the implementation of the restart activity that is used for all sysvinit scripts. Typically, there is little reason to change it.
@ -63,6 +65,8 @@ name
, process ? null
# Specifies that the process is a daemon. If a process is not a daemon, then the generator will automatically daemonize it.
, processIsDaemon ? true
# Whether to disable logging the daemon process' output
, enableDaemonOutputLogging ? true
# Command-line arguments passed to the process.
, args ? []
# Path to a PID file that the system should use to manage the process. If null, it will use a default path.
@ -137,6 +141,9 @@ let
daemon = startProcessAsDaemon;
user = _user;
pidFile = _pidFile;
outputLogFile = util.autoGenerateDaemonLogFilePath {
inherit name instanceName logDir enableDaemonOutputLogging;
};
inherit process args pidFilesDir;
};
in

View File

@ -60,12 +60,23 @@ rec {
else "${pidFilesDir}/${instanceName}.pid"
else pidFile;
/*
* Auto-generates the path to the log file that captures the
* output of a process invoked with the daemon command
*/
autoGenerateDaemonLogFilePath = {name, instanceName, logDir, enableDaemonOutputLogging ? true}:
if enableDaemonOutputLogging then
if instanceName == null then "${logDir}/nixproc-${name}.log"
else "${logDir}/nixproc-${instanceName}.log"
else null;
/*
* Creates a shell command invocation that deamonizes a foreground process by
* using libslack's daemon command.
*/
daemonizeForegroundProcess = {daemon, process, args, pidFile ? null, pidFilesDir, user ? null}:
daemonizeForegroundProcess = {daemon, process, args, pidFile ? null, pidFilesDir, user ? null, outputLogFile ? null}:
"${daemon} --unsafe --inherit"
+ (if outputLogFile == null then "" else " --output ${outputLogFile}")
+ (if pidFile == null then " --pidfiles ${pidFilesDir} --name $(basename ${process})" else " --pidfile ${pidFile}")
+ lib.optionalString (user != null) " --user ${user}"
+ " -- ${process} ${lib.escapeShellArgs args}";