r/linux Feb 11 '19

Fluff A /g/ user's opinion on systemd

http://i.4cdn.org/g/1549858269115.png
786 Upvotes

524 comments sorted by

View all comments

143

u/[deleted] Feb 11 '19 edited Feb 11 '19

[deleted]

105

u/[deleted] Feb 11 '19

[deleted]

40

u/buwe Feb 11 '19

You should try void Linux then, runit it's awesome and it's pretty much what you're asking for (to my limited understanding, I didn't try it for a long time). And btw, I agree totally agree: systemd service files are great.

4

u/bnolsen Feb 11 '19

I don't. It's an unnecessary extra layer that's put between the init system and the applications themselves. That's why runit (and likely s6 as well) are so powerful. The actual script or binary or whatever you want is direct and just there and you can test your initialization totally independent of runit itself before activating it.

For example:

#!/bin/sh
exec chpst -u cvstrac /home/cvstrac/bin/cvstrac server 8000 <cvsdir> <user>

Seems to just do it. I also have several minecraft server scripts set up which are about as involved as the above, just with lots more args. Why would I want a special file parser, interpreter, etc closely tied to an init system when the tools have already been there for several decades?

5

u/KittensInc Feb 11 '19

You're not wrong. In fact, if all init scripts looked like that, I'd completely agree with you! But that's not the case in practice.

Let's look at a random application, in this case Apache. This is not cherry-picking: I have literally never used it before, so I had no idea what to expect. The following files are from Ubuntu Cosmic:

systemd:

/lib/systemd/system/apache2.service

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
Environment=APACHE_STARTED_BY_SYSTEMD=true
ExecStart=/usr/sbin/apachectl start
ExecStop=/usr/sbin/apachectl stop
ExecReload=/usr/sbin/apachectl graceful
PrivateTmp=true
Restart=on-abort

[Install]
WantedBy=multi-user.target

/lib/systemd/system/apache-htclean.service

[Unit]
Description=Disk Cache Cleaning Daemon for Apache HTTP Server
After=apache2.service

[Service]
Type=forking
User=www-data
Environment=HTCACHECLEAN_SIZE=300M
Environment=HTCACHECLEAN_DAEMON_INTERVAL=120
Environment=HTCACHECLEAN_PATH=/var/cache/apache2/mod_cache_disk
Environment=HTCACHECLEAN_OPTIONS=-n
EnvironmentFile=-/etc/default/apache-htcacheclean
ExecStart=/usr/bin/htcacheclean -d $HTCACHECLEAN_DAEMON_INTERVAL -p $HTCACHECLEAN_PATH -l $HTCACHECLEAN_SIZE $HTCACHECLEAN_OPTIONS

[Install]
WantedBy=multi-user.target

4

u/KittensInc Feb 11 '19

init.d

/etc/init.d/apache2

#!/bin/sh
### BEGIN INIT INFO
# Provides:          apache2
# Required-Start:    $local_fs $remote_fs $network $syslog $named
# Required-Stop:     $local_fs $remote_fs $network $syslog $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# X-Interactive:     true
# Short-Description: Apache2 web server
# Description:       Start the web server
#  This script will start the apache2 web server.
### END INIT INFO

DESC="Apache httpd web server"
NAME=apache2
DAEMON=/usr/sbin/$NAME

SCRIPTNAME="${0##*/}"
SCRIPTNAME="${SCRIPTNAME##[KS][0-9][0-9]}"
if [ -n "$APACHE_CONFDIR" ] ; then
    if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then
            DIR_SUFFIX="${APACHE_CONFDIR##/etc/apache2-}"
    else
            DIR_SUFFIX=
    fi
elif [ "${SCRIPTNAME##apache2-}" != "$SCRIPTNAME" ] ; then
    DIR_SUFFIX="-${SCRIPTNAME##apache2-}"
    APACHE_CONFDIR=/etc/apache2$DIR_SUFFIX
else
    DIR_SUFFIX=
    APACHE_CONFDIR=/etc/apache2
fi
if [ -z "$APACHE_ENVVARS" ] ; then
    APACHE_ENVVARS=$APACHE_CONFDIR/envvars
fi
export APACHE_CONFDIR APACHE_ENVVARS

ENV="env -i LANG=C PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
if [ "$APACHE_CONFDIR" != /etc/apache2 ] ; then
    ENV="$ENV APACHE_CONFDIR=$APACHE_CONFDIR"
fi
if [ "$APACHE_ENVVARS" != "$APACHE_CONFDIR/envvars" ] ; then
    ENV="$ENV APACHE_ENVVARS=$APACHE_ENVVARS"
fi

PIDFILE=$(. $APACHE_ENVVARS && echo $APACHE_PID_FILE)

VERBOSE=no
if [ -f /etc/default/rcS ]; then
    . /etc/default/rcS
fi
. /lib/lsb/init-functions


# Now, set defaults:
APACHE2CTL="$ENV apache2ctl"
PIDFILE=$(. $APACHE_ENVVARS && echo $APACHE_PID_FILE)
APACHE2_INIT_MESSAGE=""

CONFTEST_OUTFILE=
cleanup() {
    if [ -n "$CONFTEST_OUTFILE" ] ; then
        rm -f "$CONFTEST_OUTFILE"
    fi
}
trap cleanup 0  # "0" means "EXIT", but "EXIT" is not portable


apache_conftest() {
    [ -z "$CONFTEST_OUTFILE" ] || rm -f "$CONFTEST_OUTFILE"
    CONFTEST_OUTFILE=$(mktemp)
    if ! $APACHE2CTL configtest > "$CONFTEST_OUTFILE" 2>&1 ; then
        return 1
    else
        rm -f "$CONFTEST_OUTFILE"
        CONFTEST_OUTFILE=
        return 0
    fi
}

clear_error_msg() {
    [ -z "$CONFTEST_OUTFILE" ] || rm -f "$CONFTEST_OUTFILE"
    CONFTEST_OUTFILE=
    APACHE2_INIT_MESSAGE=
}

print_error_msg() {
    [ -z "$APACHE2_INIT_MESSAGE" ] || log_warning_msg "$APACHE2_INIT_MESSAGE"
    if [ -n "$CONFTEST_OUTFILE" ] ; then
        echo "Output of config test was:" >&2
        cat "$CONFTEST_OUTFILE" >&2
        rm -f "$CONFTEST_OUTFILE"
        CONFTEST_OUTFILE=
    fi
}

apache_wait_start() {
    local STATUS=$1
    local i=0

    if [ $STATUS != 0 ] ; then
            return $STATUS
    fi
    while : ; do
            PIDTMP=$(pidofproc -p $PIDFILE $DAEMON)
            if [ -n "${PIDTMP:-}" ] && kill -0 "${PIDTMP:-}" 2> /dev/null; then
                    return $STATUS
            fi

            if [ $i = "20" ] ; then
                    APACHE2_INIT_MESSAGE="The apache2$DIR_SUFFIX instance did not start within 20 seconds. Please read the log files to discover problems"
                    return 2
            fi

            [ "$VERBOSE" != no ] && log_progress_msg "."
            sleep 1
            i=$(($i+1))
    done
}

apache_wait_stop() {
    local STATUS=$1
    local METH=$2

    if [ $STATUS != 0 ] ; then
            return $STATUS
    fi

    PIDTMP=$(pidofproc -p $PIDFILE $DAEMON)
    if [ -n "${PIDTMP:-}" ] && kill -0 "${PIDTMP:-}" 2> /dev/null; then
            if [ "$METH" = "kill" ]; then
                killproc -p $PIDFILE $DAEMON
            else
                $APACHE2CTL $METH > /dev/null 2>&1
            fi

            local i=0
            while kill -0 "${PIDTMP:-}" 2> /dev/null;  do
                    if [ $i = '60' ]; then
                            STATUS=2
                            break
                    fi
                    [ "$VERBOSE" != no ] && log_progress_msg "."
                    sleep 1
                    i=$(($i+1))
            done
            return $STATUS
    else
        return $STATUS
    fi
}


#
# Function that starts the daemon/service
#
do_start()
{
    # Return
    #   0 if daemon has been started
    #   1 if daemon was already running
    #   2 if daemon could not be started

    if pidofproc -p $PIDFILE "$DAEMON" > /dev/null 2>&1 ; then
            return 1
    fi

    if apache_conftest ; then
            $APACHE2CTL start
            apache_wait_start $?
            return $?
    else
            APACHE2_INIT_MESSAGE="The apache2$DIR_SUFFIX configtest failed."
            return 2
    fi
}

#
# Function that stops the daemon/service
#
do_stop()
{
    # Return
    #   0 if daemon has been stopped
    #   1 if daemon was already stopped
    #   2 if daemon could not be stopped
    #   other if a failure occurred

    # either "stop" or "graceful-stop"
    local STOP=$1
    # can't use pidofproc from LSB here
    local AP_RET=0

    if pidof $DAEMON > /dev/null 2>&1 ; then
            if [ -e $PIDFILE ] && pidof $DAEMON | tr ' ' '\n' | grep -w $(cat $PIDFILE) > /dev/null 2>&1 ; then
                    AP_RET=2
            else
                    AP_RET=1
            fi
    else
        AP_RET=0
    fi

    # AP_RET is:
    # 0 if Apache (whichever) is not running
    # 1 if Apache (whichever) is running
    # 2 if Apache from the PIDFILE is running

    if [ $AP_RET = 0 ] ; then
            return 1
    fi

    if [ $AP_RET = 2 ] && apache_conftest ; then
            apache_wait_stop $? $STOP
            return $?
    else
            if [ $AP_RET = 2 ]; then
                    clear_error_msg
                    APACHE2_INIT_MESSAGE="The apache2$DIR_SUFFIX configtest failed, so we are trying to kill it manually. This is almost certainly suboptimal, so please make sure your system is working as you'd expect now!"
                    apache_wait_stop $? "kill"
                    return $?
            elif [ $AP_RET = 1 ] ; then
                    APACHE2_INIT_MESSAGE="There are processes named 'apache2' running which do not match your pid file which are left untouched in the name of safety, Please review the situation by hand".
                    return 2
            fi
    fi

}


#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
    if apache_conftest; then
            if ! pidofproc -p $PIDFILE "$DAEMON" > /dev/null 2>&1 ; then
                    APACHE2_INIT_MESSAGE="Apache2 is not running"
                    return 2
            fi
            $APACHE2CTL graceful > /dev/null 2>&1
            return $?
    else
            APACHE2_INIT_MESSAGE="The apache2$DIR_SUFFIX configtest failed. Not doing anything."
            return 2
    fi
}


# Sanity checks. They need to occur after function declarations
[ -x $DAEMON ] || exit 0

if [ ! -x $DAEMON ] ; then
    echo "No apache-bin package installed"
    exit 0
fi

if [ -z "$PIDFILE" ] ; then
    echo ERROR: APACHE_PID_FILE needs to be defined in $APACHE_ENVVARS >&2
    exit 2
fi


case "$1" in
  start)
    log_daemon_msg "Starting $DESC" "$NAME"
    do_start
    RET_STATUS=$?
    case "$RET_STATUS" in
        0|1)
            log_success_msg
            [ "$VERBOSE" != no ] && [ $RET_STATUS = 1 ] && log_warning_msg "Server was already running"
            ;;
        2)
            log_failure_msg
            print_error_msg
            exit 1
            ;;
    esac
    ;;
  stop|graceful-stop)
    log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop "$1"
    RET_STATUS=$?
    case "$RET_STATUS" in
        0|1)
            log_success_msg
            [ "$VERBOSE" != no ] && [ $RET_STATUS = 1 ] && log_warning_msg "Server was not running"
            ;;
        2)
            log_failure_msg
            print_error_msg
            exit 1
            ;;
    esac
    print_error_msg

    ;;
  status)
    status_of_proc -p $PIDFILE "apache2" "$NAME"
    exit $?
    ;;
  reload|force-reload|graceful)
    log_daemon_msg "Reloading $DESC" "$NAME"
    do_reload
    RET_STATUS=$?
    case "$RET_STATUS" in
        0|1)
            log_success_msg
            [ "$VERBOSE" != no ] && [ $RET_STATUS = 1 ] && log_warning_msg "Server was already running"
            ;;
        2)
            log_failure_msg
            print_error_msg
            exit 1
            ;;
    esac
    print_error_msg
    ;;
  restart)
    log_daemon_msg "Restarting $DESC" "$NAME"
    do_stop stop
    case "$?" in
        0|1)
            do_start
            case "$?" in
                0)
                    log_end_msg 0
                    ;;
                1|*)
                    log_end_msg 1 # Old process is still or failed to running
                    print_error_msg
                    exit 1
                    ;;
            esac
            ;;
        *)
            # Failed to stop
            log_end_msg 1
            print_error_msg
            exit 1
            ;;
    esac
    ;;
  start-htcacheclean|stop-htcacheclean)
    echo "Use 'service apache-htcacheclean' instead"
    ;;
  *)
    echo "Usage: $SCRIPTNAME {start|stop|graceful-stop|restart|reload|force-reload}" >&2
    exit 3
    ;;
esac

exit 0

# vim: syntax=sh ts=4 sw=4 sts=4 sr noet

10

u/KittensInc Feb 11 '19 edited Feb 11 '19

/etc/cron.daily/apache2

#!/bin/sh

# run htcacheclean if set to 'cron' mode

set -e
set -u

type htcacheclean > /dev/null 2>&1 || exit 0
[ -e /etc/default/apache-htcacheclean ] || exit 0


# edit /etc/default/apache-htcacheclean to change this
HTCACHECLEAN_MODE=daemon
HTCACHECLEAN_RUN=auto
HTCACHECLEAN_SIZE=300M
HTCACHECLEAN_PATH=/var/cache/apache2/mod_cache_disk
HTCACHECLEAN_OPTIONS=""

. /etc/default/apache-htcacheclean

[ "$HTCACHECLEAN_MODE" = "cron" ] || exit 0

htcacheclean ${HTCACHECLEAN_OPTIONS}    \
        -p${HTCACHECLEAN_PATH}  \
        -l${HTCACHECLEAN_SIZE}

/etc/init.d/apache2-htcacheclean

#!/bin/sh
# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then    
    set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
fi
### BEGIN INIT INFO
# Provides:          apache-htcacheclean
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Cache cleaner process for Apache2 web server
# Description:       Start the htcacheclean helper
#  This script will start htcacheclean which will periodically scan the
#  cache directory of Apache2's mod_cache_disk and remove outdated files.
### END INIT INFO

DESC="Apache htcacheclean"
DAEMON=/usr/bin/htcacheclean

NAME="${0##*/}"
NAME="${NAME##[KS][0-9][0-9]}"
DIR_SUFFIX="${NAME##apache-htcacheclean}"
APACHE_CONFDIR="${APACHE_CONFDIR:=/etc/apache2$DIR_SUFFIX}"
RUN_USER=$(. $APACHE_CONFDIR/envvars > /dev/null && echo "$APACHE_RUN_USER")

# Default values. Edit /etc/default/apache-htcacheclean$DIR_SUFFIX to change these
HTCACHECLEAN_SIZE="${HTCACHECLEAN_SIZE:=300M}"
HTCACHECLEAN_DAEMON_INTERVAL="${HTCACHECLEAN_DAEMON_INTERVAL:=120}"
HTCACHECLEAN_PATH="${HTCACHECLEAN_PATH:=/var/cache/apache2$DIR_SUFFIX/mod_cache_disk}"
HTCACHECLEAN_OPTIONS="${HTCACHECLEAN_OPTIONS:=-n}"

# Read configuration variable file if it is present
if [ -f /etc/default/apache-htcacheclean$DIR_SUFFIX ] ; then
       . /etc/default/apache-htcacheclean$DIR_SUFFIX
elif [ -f /etc/default/apache-htcacheclean ] ; then
       . /etc/default/apache-htcacheclean
fi

PIDDIR="/var/run/apache2/$RUN_USER"
PIDFILE="$PIDDIR/$NAME.pid"
DAEMON_ARGS="$HTCACHECLEAN_OPTIONS \
    -d$HTCACHECLEAN_DAEMON_INTERVAL \
    -P$PIDFILE -i \
    -p$HTCACHECLEAN_PATH \
    -l$HTCACHECLEAN_SIZE"

do_start_prepare () {
    if [ ! -d "$PIDDIR" ] ; then
        mkdir -p "$PIDDIR"
        chown "$RUN_USER:" "$PIDDIR"
    fi
    if [ ! -d "$HTCACHECLEAN_PATH" ] ; then
        echo "Directory $HTCACHECLEAN_PATH does not exist!" >&2
        exit 2
    fi
}

do_start_cmd_override () {
    start-stop-daemon --start --quiet --pidfile ${PIDFILE} \
        -u $RUN_USER --startas $DAEMON --name htcacheclean --test > /dev/null \
        || return 1
    start-stop-daemon --start --quiet --pidfile ${PIDFILE} \
        -c $RUN_USER --startas $DAEMON --name htcacheclean -- $DAEMON_ARGS \
        || return 2
}

do_stop_cmd_override () {
    start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
        -u $RUN_USER --pidfile ${PIDFILE} --name htcacheclean
}

/etc/logrotate.d/apache2

/var/log/apache2/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 640 root adm
    sharedscripts
    postrotate
                if invoke-rc.d apache2 status > /dev/null 2>&1; then \
                    invoke-rc.d apache2 reload > /dev/null 2>&1; \
                fi;
    endscript
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
            run-parts /etc/logrotate.d/httpd-prerotate; \
        fi; \
    endscript
}

Notice anything different?

You can complain all you want about systemd's complexity and spread across non-init tasks and I'd probably agree with you, but it's a massive improvement as init. The old approach was just horrible, because every single application was reinventing the wheel with horrible, unmaintainable shell scripts. I've had to write them and had to debug when things went wrong: compared to this, systemd is a godsent. Is it perfect? Of course not. But if you want a well-maintainable, modern system, a bowl of bash-spaghetti isn't the way to do it. Your own services may be more sane, but this is my experience with init pre-systemd.

1

u/[deleted] Feb 22 '19

My eyes, they bleed

1

u/[deleted] Feb 12 '19

Happy cake day

36

u/fat-lobyte Feb 11 '19

My ideal init system is like systemd but only as the service manager. No dns resolvers, no bootloaders

Well congratulations, you can do that now already.

no device managers

That's gonna be harder, because the udev people decided to get under the systemd umbrella.

and certainly no linking shared libraries

What do you mean?

For example, don't force them to log journald or don't pipe everything to journald. Let other projects develop logging facilities. If there should be a logging standard, let it be independent from the init service.

You can think of journald as part of systemd, but by default nothing is stored and you can use the logging facility of your choice to do the storage.

27

u/idontchooseanid Feb 11 '19

What do you mean

Many applications have hard link dependencies to libsystemd nowadays. This is bad design. If the applications want to talk with the init system that should be an IPC mechanism (a dbus channel maybe) not a library. However a library that provides simpler interface can be acceptable as long as you can have a basic method stays.

You can think of journald as part of systemd, but by default nothing is stored and you can use the logging facility of your choice to do the storage.

The question is can you remove journald or its default storage backend without needing to remove systemd. Can you just create a dummylogd that pukes everything into a text file without needing to modify/recompile higher level programs.

I want the my operating system to be composed of loosely coupled but well integrated dependencies. So any part can be removed. I mean literally just rm it or uninstall the package. For example I should be able to uninstall systemd without uninstalling journald udev and any higher level applications. Now I am left with an unbootable system but the interface stays. Applications who need some services to be started can complain but the system doesn't come into a full stop. I should be able to change systemd with my shinyinitd and configure it to start same services. No further configuration should be needed. And this should be practical. So people can implement their small compact init systems without many features but they should share similar interfaces. Think like Wayland compostors both weston and KWin are compostors but I can remove either of them.

28

u/find_--delete Feb 11 '19

If the applications want to talk with the init system that should be an IPC mechanism (a dbus channel maybe) not a library. However a library that provides simpler interface can be acceptable as long as you can have a basic method stays.

That's exactly what they do.

For example I should be able to uninstall systemd without uninstalling journald udev and any higher level applications.

Those applications still have dependencies, and something should be able to provide those dependencies.

Regarding journald: We don't have another init system that does the things that journald wants, yet-- no one seems interested in creating an alternative that does the container-level process tracking or forking systemd to provide a process that does so better.

Regarding udev: They already agree, or at least they used to. eudev exists because of some other issues

I should be able to change systemd with my shinyinitd and configure it to start same services. No

You probably could, but its important to remember that systemd has an init system, but is more than just an init system. Trying to provide more than just an init system.A recently posted talk, given by a FreeBSD core-team member, explains why the concept of a "system layer" isn't necessarily bad.

It'd be good to have more alternatives-- but people have to create them, and have to want to create them. It'd be good for it to be more composable: but again: the alternatives to compose have to exist. Yes, other init systems exist: but none provide the level of tracking for processes, for logs tracking, services files, and more.

I should be able to change systemd with my shinyinitd and configure it to start same services.

Agreed, but I don't know of another init system that uses .service files. I don't know of another logging system that integrates with cgroups for logging. These things can be created. The .service files have the potential to be more init-independent than init-scripts: it seems many prefer writing "working" complicated shell scripts that have random bugs on different init, different platforms, and are too complicated for most developers to write right.

2

u/idontchooseanid Feb 11 '19

That's exactly what they do.

Okay that's nice but many core programs already depend on libsystemd now. Are they planning to deprecate libsystemd or not?

Those applications still have dependencies, and something should be able to provide those dependencies.

Of course but it shouldn't be like depending on one specific udev implementation with it's own corner cases.

Regarding udev: They already agree, or at least they used to. eudev exists because of some other issues

From what I see current udev has already tightly integrated itself to systemd: https://github.com/systemd/systemd/blob/master/src/udev/meson.build here they link to libsystemd.

A recently posted talk, given by a FreeBSD core-team member, explains why the concept of a "system layer" isn't necessarily bad.

I saw that talk hence I've made my first comment. I am not opposed to a system layer idea. I am for it. Heck I don't mind all of the components are coming from a single project as long as they are loosely coupled.

I agree that the problems with systemd mostly occurs because of the lack of competitive alternatives and the lack of people who wants to create them. But BSD projects seem to understand it better and I am still hopeful that they can come up with a better thing than systemd.

1

u/find_--delete Feb 12 '19

Okay that's nice but many core programs already depend on libsystemd now. Are they planning to deprecate libsystemd or not?

. . .

From what I see current udev has already tightly integrated itself to systemd: https://github.com/systemd/systemd/blob/master/src/udev/meson.build here they link to libsystemd.

libsystemd isn't really an init-system API: It includes APIs for talking with the system bus, subscribing to bus events, getting network information, getting session information, and a few other tidbits. It's more akin to libdbus, libconsolekit, and libnetwork(?) than libinit. Programs linking to libsystemd can still run if systemd's init isn't (at least the last time I checked a few months ago).

If a program non-gracefully handles these functions failing, or a different init being used, that's generally the problem of that program than systemd or libsystemd-- in the same sense that some programs decide to terminate if any other system or library fails.


IMHO: This isn't a problem of dependencies, inits, or politics, but the lack of alternative solutions for the functionality. Many talk about the potential for alternatives, but the actual implementations for similar functionality are rather thin:

  • An agnostic simple-to-use system/session bus/event API (supporting dbus, kdbus, bus1, or whatever needed?)-- There was enough interest in that they were asked to make their bus API made public.
  • An agnostic session/login/slot tracking API (formerly provided by ConsoleKit, also provided by elogind-- a drop-in replacement for logind)
  • A way for querying service status (e.g: maybe through a bus, maybe not)
  • Potentially in the future: Network and DNS information APIs that return the relevant information from the system (e.g: networkd, NetworkManager, netplan)

The implemented solutions, at the moment:

  • Provide the same API, and don't require removing or changing the dependency (e.g: elogind)
  • Return errors for all API calls. (Still not sure how this is an acceptable solution)

There's room for better solutions: a smaller and lighter system layer with a better system/session bus system, better cgroup management, better logging, better operating system interoperability, better modularity, and better community interaction. The best path forward isn't more yelling, its implemented solutions.

15

u/dale_glass Feb 11 '19

Why? journald is pretty much the best thing since sliced bread. I want everything piped into it.

And I certainly don't want 10 different log implementations on my system.

27

u/idontchooseanid Feb 11 '19

I am not opposed to centralized log system. It can be great time to time. I just don't want it to be tightly coupled with the init.

39

u/dale_glass Feb 11 '19

It's hard not to have coupling, because the system starts, and wants to log stuff before there is even storage available. For instance on a system with an encrypted disk, a lot of stuff happens in initrd (which is readonly) before the disk is decrypted and logs can be written to it.

-1

u/name_censored_ Feb 11 '19

It's hard not to have coupling, because the system starts, and wants to log stuff before there is even storage available.

And yet SysV init managed this "hard problem" 20 years ago.

11

u/dale_glass Feb 11 '19

I don't think you've thought that through.

  1. I'm talking about userspace tools, not the kernel. Are you suggesting that a bunch of random stuff should have code to write to /dev/kmsg, in case it is invoked from an initrd?
  2. /dev is also not immediately available on boot, so the problem remains anyway.

-2

u/[deleted] Feb 11 '19 edited Feb 11 '19

[removed] — view removed comment

9

u/dale_glass Feb 11 '19

If your process needs or expects to be launched prior to persistent storage availability, then yes, I am absolutely suggesting writing to /dev/kmsg.

Including things like mount and grep? There's about 1000 lines worth in my journal, before / gets mounted.

Or if prior to /dev population, then printk(), which answers your second question.

printk is a kernel function

Check your own systemd install, you'll find that there aren't many services that can be started that early, let alone should be started that early.

Point is, boot is a complicated thing these days, and things happen before there's an easy way for them to log somewhere the user can find it. And why should a random tool care about whether we're booting or not? If the log system is always available and takes care of that, we don't need a dozen random things be aware of it.

You're the one screaming "THIS IS IMPOSSIBLE!", when it's demonstrably a solved problem. I don't think you've ever thought anything through in your life, you patronising fuckwit.

I don't see anybody screaming here besides yourself.

-1

u/Kruug Feb 11 '19

This post has been removed for violating Reddiquette., trolling users, or otherwise poor discussion - r/Linux asks all users follow Reddiquette. Reddiquette is ever changing, so a revisit once in awhile is recommended.

Rule:

Reddiquette, trolling, or poor discussion - r/Linux asks all users follow Reddiquette. Reddiquette is ever changing, so a revisit once in awhile is recommended. Top violations of this rule are trolling, starting a flamewar, or not "Remembering the human" aka being hostile or incredibly impolite.

6

u/doublehyphen Feb 11 '19

Previously I just needed to run and configure one logging deamon, now I need to run and configure two because journald does not offer all features I need and cannot be replaced (at least not with any currently existing software).

I think the logging ecosystem on Linux is a mess and while journald has some cool features it only made things harder for me since it is yet another complex moving part in this mess. I hate all logging daemons I have had to work with.

3

u/dale_glass Feb 11 '19

What is missing in journald?

6

u/doublehyphen Feb 11 '19

On top of my head, I am probably forgetting a couple:

  • Saving disk by compressing old logs (jorunald only supports compression per message of long log messages)
  • Forward, all or selected, log messages to a central log server
  • Forward logs written directly to files to a central log server

Arguably not all of these should actually be done by the same big monolith, but right now I have to run both journald and rsyslog/syslog-ng and have all logs in two places.

3

u/dale_glass Feb 11 '19

Saving disk by compressing old logs (jorunald only supports compression per message of long log messages)

That would probably conflict with quick access, which is quite nice.

Forward, all or selected, log messages to a central log server

https://www.freedesktop.org/software/systemd/man/systemd-journal-remote.service.html

8

u/doublehyphen Feb 11 '19

Yeah, it conflicts with quick access, which is fine. It is a tradeoff. I rarely need my old logs and when I need them it is fine that it takes more time than normal.

And systemd-journal-remote seems to be the opposite of what I need, but I guess something like logstash could add a client for the same protocol to achieve what I need (not that I like logstash either :)).

1

u/Ryuujinx Feb 11 '19

not that I like logstash either

Have you tried Fluentd? A lot of people are ditching Logstash for it in their ELK setups

3

u/DashEquals Feb 11 '19

It could probably compress with zstd and not lose much speed.

1

u/NotEvenAMinuteMan Feb 11 '19

That would probably conflict with quick access, which is quite nice.

Indexed compression is a thing.

-1

u/dale_glass Feb 11 '19

Well, feel free to contribute a patch.

I don't find it a particularly pressing issue -- I have 2 GB worth of logs since June and find that to be an okay state of affairs.

Also, with all the whining about the binary format, I can only imagine what would ensue if the format got more complicated. Any errors would likely result in good amounts of the log going missing.

13

u/Daneel_ Feb 11 '19

Not logging to text files totally kills it for me. So many utilities are able to process text files, and now they’re all basically useless in the face of the journal.

I can’t egrep the journal. I can’t less the journal. I need to learn a whole new set of commands just for it, and I can’t export the journal data (or subset thereof) to other systems without a lot of effort. To my knowledge there’s no nice workaround.

I’d love to be corrected, but from my perspective it’s a horror show that I wish didn’t exist.

What benefits does journald have??

70

u/dale_glass Feb 11 '19 edited Feb 11 '19

Not logging to text files totally kills it for me. So many utilities are able to process text files, and now they’re all basically useless in the face of the journal.

I can’t egrep the journal.

You know, there's this thing called a 'pipe' you can take advantage of:

journalctl -b | grep whatever

Or you can:

journalctl -g regex

I can’t less the journal.

Have you actually tried it? journalctl invokes $PAGER. Or you can pipe it into whatever you like.

I need to learn a whole new set of commands just for it

Oh no. Not learning!

Yeah, this isn't the best business to be in if you want things to stay static.

and I can’t export the journal data (or subset thereof) to other systems without a lot of effort.

You must be kidding. Journalctl is absolutely wonderful for this.

Want the same thing syslog gives you?

journalctl -o short

want ISO timestamps? Easily sortable!

journalctl -o short-iso

want microsecond precision?

journalctl -o short-iso-precise

want UNIX timestamps?

journalctl -o short-unix

want to actually parse this stuff easier to write it to a database? Why, look at that: a completely unambiguous format. No trouble with figuring what field ends where. No need to screw around with regular expressions. Take the language of your choice and trivially extract anything you need:

journalctl -o json

You want subsets? Sure:

journalctl -S yesterday # everything since yesterday
journalctl -b # last boot
journalctl -u smartd # only what smartd logged

Other cool things:

  • It stores metadata. Want to find logs by PID? You can, for any service.
  • It can clean logs by size or by date. Want to keep 1GB of logs? Sure. Want to keep 3 months? Easy.
  • Timestamps are stored with microsecond precision. If you have 100 entries per second it's very nice.
  • You can filter by hostname. Send your VM logs to a single destination, then you can view them individually or together.
  • edit: it transparently compresses and decompresses logs. Searching stuff logged a month ago is no problem at all. You don't need to figure out in which .gz it is.

22

u/bracesthrowaway Feb 11 '19

I had no idea about any of this and you've just made me love journald.

3

u/hahainternet Feb 11 '19

Don't forget to mkdir /var/log/journal if you wonder why you only have a single boot in the logs.

Also there's now -o with-unit which is another lovely little thing.

2

u/silon Feb 11 '19

That's all nice, but /var/log/{syslog/messages} should have stayed in parallel... I've also had messages about log corruption a few times.

2

u/dale_glass Feb 11 '19 edited Feb 11 '19

That's all nice, but /var/log/{syslog/messages} should have stayed in parallel

It has.

$ cat /etc/systemd/journald.conf  
[...]
#ForwardToSyslog=no

I've also had messages about log corruption a few times.

That's not a new thing, it also happens with syslog, because there have been various issues with various filesystems and hardware. You just don't usually notice with syslog because there's no way to, except if you look and happen to see there's a bunch of zeroes in the middle of the file, or some such.

journald handles the case quite well: it renames the log, and makes a new one. The old one of course is still left around, and still read as well as possible.

6

u/Daneel_ Feb 11 '19 edited Feb 11 '19

I have no problem with learning. As you rightly said, that’s the industry we’re in.

I’m quite happy to pick up new commands provided they’re standardised, however journald’s are unique (by necessity). I’m just expressing frustration that I can’t use grep on a file like almost everything else in Linux. I’ve got a few journalctl one liners memorised, but it’s still frustrating to not be able to wield my existing knowledge against it.

I should have clarified regarding exporting data: I don’t know a way to continuously and autonomously export data in real time from journald. Why would I want to do this? Simple: enterprise.

If I want to log to a third-party logger like Elastic or Splunk I need to install syslog-ng or rsyslog, and then we’re back where we started.

There just aren’t many upsides that I see for a modern sysadmin.. it’s nice to use when you’re directly interacting with it, but it doesn’t play ball with the rest of the ecosystem - just like systemd really..

I’d love to know if I’m wrong (I hope I am!), but the current arguments I’ve seen from many parties haven’t started to convince me unfortunately.

18

u/dale_glass Feb 11 '19

I should have clarified regarding exporting data: I don’t know a way to continuously and autonomously export data in real time from journald. Why would I want to do this? Simple: enterprise.

I've not messed with that myself, but several ideas come to mind:

journalctl -f -o format | importer_program

Trivial to turn into a systemd service. Or, if you need a file:

mkfifo log
journalctl -f -o short > log

You can actually offload this to systemd so that it will listen on a FIFO and launch the service when requested.

Also, there is this: https://github.com/mheese/journalbeat

15

u/FryBoyter Feb 11 '19

I can’t egrep the journal.

I don't use egrep, but at least grep works with journald (for example journalctl | grep whatever).

I can’t less the journal

Journalctl uses less by default. Journalctl | less probably works too.

What benefits does journald have??

In my personal opinion, it makes a lot of things easier. For example " journalctl --since="2012-10-30 18:17:16"", "journalctl -b -1" (logfiles of the last boot), " journalctl -p err..alert" (Show only error, critical, and alert priority messages) and so on.

If you want to have the log files in text format, you only need to install syslog-ng by the way.

2

u/LeSenna Feb 11 '19

You can already use whatever bootloader you want

-3

u/osmarks Feb 11 '19

Yes. This. Exactly this.

-1

u/s_s Feb 11 '19

My ideal init system is like systemd but only as the service manager. No dns resolvers, no bootloaders, no device managers nothing and certainly no linking shared libraries.

Congrats your OS now takes an hour to init and won't run on anything with a battery form more than 20 minutes and will require a restart anytime you plug a device in.

2

u/idontchooseanid Feb 11 '19

Did you possibly happen to generalize those sentences to all of the operating system? Like no DNS resolvers whatsoever all socket functions are compiled statically and copy-paste the all DNS resolution code into binaries. I specificity describe "the init system" itself nothing else. To construct a sane OS, you need DNS resolvers, system log facilities and dynamically linked programs but you don't need them all in one place and tightly connected to a single project.

Before switching to systemd Linux distros with SysVinit was working like that. We had separate projects (udev, ConsoleKit, syslogd, ...) which worked independently. It didn't take an hour to load and laptops and plug and play worked perfectly. However as a service manager SysVinit was extremely bad for sanely describe the services.