]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
logger: allow user to send structured journald messages
authorSami Kerola <kerolasa@iki.fi>
Fri, 21 Feb 2014 19:25:30 +0000 (19:25 +0000)
committerKarel Zak <kzak@redhat.com>
Tue, 4 Mar 2014 12:44:21 +0000 (13:44 +0100)
This feature is hopefully mostly used to give MESSAGE_ID labels for
messages coming from scripts, making search of messages easy.  The
logger(1) manual page update should give enough information how to use
--journald option.

[kzak@redhat.com: - add missing #ifdefs
                  - use xalloc.h]

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Karel Zak <kzak@redhat.com>
bash-completion/logger
configure.ac
misc-utils/Makemodule.am
misc-utils/logger.1
misc-utils/logger.c

index 963abc7040512172b7a877794c1ea49c0d628f02..6b4c7df2c9d3722130ae40aee55be5f2e5d19c41 100644 (file)
@@ -5,7 +5,7 @@ _logger_module()
        cur="${COMP_WORDS[COMP_CWORD]}"
        prev="${COMP_WORDS[COMP_CWORD-1]}"
        case $prev in
-               '-f'|'--file')
+               '-f'|'--file'|'--journald')
                        local IFS=$'\n'
                        compopt -o filenames
                        COMPREPLY=( $(compgen -f -- $cur) )
@@ -37,7 +37,7 @@ _logger_module()
        esac
        case $cur in
                -*)
-                       OPTS="--udp --id --file --help --server --port --priority --stderr --tag --socket --version"
+                       OPTS="--journald --udp --id --file --help --server --port --priority --stderr --tag --socket --version"
                        COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
                        return 0
                        ;;
index e742801d23c4e45c9aa4cad94c42ff7e274bf552..2e47bacab2d5c189509cffa14a79649b64622155 100644 (file)
@@ -716,6 +716,7 @@ AS_IF([test "x$enable_most_builds" = xyes], [
   enable_newgrp=yes
   enable_reset=yes
   enable_socket_activation=yes
+  enable_journald=yes
   enable_tunelp=yes
   enable_vipw=yes
   enable_write=yes
@@ -1414,6 +1415,21 @@ AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [
 ])
 
 
+AC_ARG_ENABLE([journald],
+  AS_HELP_STRING([--enable-journald], [add journald support to logger]),
+  [], [enable_journald=no]
+)
+have_journald=no
+AS_IF([test "x$enable_journald" = xyes], [
+  PKG_CHECK_MODULES([SYSTEMD_JOURNAL], [libsystemd-journal], [], [
+    AC_MSG_ERROR([cannot find libsystemd-journal support])
+  ])
+  have_journald=yes
+  AC_DEFINE([HAVE_JOURNALD], [1], [Define if journald is available])
+])
+AM_CONDITIONAL([HAVE_JOURNALD], [test "x$have_journald" = xyes])
+
+
 AC_ARG_WITH([smack],
   AS_HELP_STRING([--with-smack], [build with SMACK support]),
   [], [with_smack=no]
index d30229d5f14cbc988e82a158be09f924e4bab87d..05407de9b3211456ddec4d204ad9460a4eae484d 100644 (file)
@@ -20,6 +20,10 @@ endif
 usrbin_exec_PROGRAMS += logger
 dist_man_MANS += misc-utils/logger.1
 logger_SOURCES = misc-utils/logger.c lib/strutils.c
+if HAVE_JOURNALD
+logger_LDADD = $(SYSTEMD_JOURNAL_LIBS)
+logger_CFLAGS = $(SYSTEMD_JOURNAL_CFLAGS)
+endif
 
 usrbin_exec_PROGRAMS += look
 dist_man_MANS += misc-utils/look.1
index c7c3de0f588ca76f0d8b18c4b24ee70686d1bd39..08cf907a6ffc1970fa2dbd8f4c803c069d5cb373 100644 (file)
@@ -122,6 +122,31 @@ Write to the specified
 .I socket
 instead of to the builtin syslog routines.
 .TP
+\fB\-\-journald\fR [\fIfile\fR]
+Write systemd journal entry.  The entry is read from
+.I stdin
+or input
+.IR file .
+Each new line must begin with a field that is accepted by journald, see
+.IR systemd.journal-fields (7)
+for details.  Use of MESSAGE_ID field is generally good idea, as they
+make finding entries easy.
+.IP
+.nf
+$ printf "%s\\n%s\\n%s\\n" MESSAGE_ID=86184c3b1aa444f58ebe7b30fec1438b DOGS=bark "CARAVAN=goes on" | logger --journald
+$ logger --journald=entry.txt
+.fi
+.IP
+Notice that
+.B \-\-journald
+will ignore values of other options, such as priority.  If priority is
+needed it must be within input, and use PRIORITY field.  The simple
+execution of
+.B journalctl
+will display MESSAGE field.  Use
+.B journalctl --output json-pretty
+to see rest of the fields.
+.TP
 \fB\-V\fR, \fB\-\-version\fR
 Display version information and exit.
 .TP
@@ -169,7 +194,9 @@ logger \-p local0.notice \-t HOSTIDM \-f /dev/idmc
 logger \-n loghost.example.com System rebooted
 .SH SEE ALSO
 .BR syslog (3),
-.BR syslogd (8)
+.BR syslogd (8),
+.BR journalctl (1),
+.BR systemd.journal-fields (7)
 .SH STANDARDS
 The
 .B logger
index 07176470e5451cbf23b6ee3cd33eff15a27587af..c07bfac8992f59d009acdcbee5714395c7bd46ae 100644 (file)
 #include "closestream.h"
 #include "nls.h"
 #include "strutils.h"
+#include "xalloc.h"
 
 #define        SYSLOG_NAMES
 #include <syslog.h>
 
+#ifdef HAVE_JOURNALD
+# include <systemd/sd-journal.h>
+#endif
+
 enum {
        TYPE_UDP = (1 << 1),
        TYPE_TCP = (1 << 2),
@@ -65,7 +70,8 @@ enum {
 };
 
 enum {
-       OPT_PRIO_PREFIX = CHAR_MAX + 1
+       OPT_PRIO_PREFIX = CHAR_MAX + 1,
+       OPT_JOURNALD
 };
 
 
@@ -204,6 +210,40 @@ static int inet_socket(const char *servername, const char *port,
        return fd;
 }
 
+#ifdef HAVE_JOURNALD
+static int journald_entry(FILE *fp)
+{
+       struct iovec *iovec;
+       char *buf = NULL;
+       ssize_t sz;
+       int n, lines, vectors = 8, ret;
+       size_t dummy = 0;
+
+       iovec = xmalloc(vectors * sizeof(struct iovec));
+       for (lines = 0; /* nothing */ ; lines++) {
+               buf = NULL;
+               sz = getline(&buf, &dummy, fp);
+               if (sz == -1)
+                       break;
+               if (0 < sz && buf[sz - 1] == '\n') {
+                       sz--;
+                       buf[sz] = '\0';
+               }
+               if (lines == vectors) {
+                       vectors *= 2;
+                       iovec = xrealloc(iovec, vectors * sizeof(struct iovec));
+               }
+               iovec[lines].iov_base = buf;
+               iovec[lines].iov_len = sz;
+       }
+       ret = sd_journal_sendv(iovec, lines);
+       for (n = 0; n < lines; n++)
+               free(iovec[n].iov_base);
+       free(iovec);
+       return ret;
+}
+#endif
+
 static void mysyslog(int fd, int logflags, int pri, char *tag, char *msg)
 {
        char buf[1000], pid[30], *cp, *tp;
@@ -249,6 +289,9 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
        fputs(_(" -s, --stderr          output message to standard error as well\n"), out);
        fputs(_(" -t, --tag <tag>       mark every line with this tag\n"), out);
        fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out);
+#ifdef HAVE_JOURNALD
+       fputs(_("     --journald[=<file>]  write journald entry\n"), out);
+#endif
 
        fputs(USAGE_SEPARATOR, out);
        fputs(USAGE_HELP, out);
@@ -272,7 +315,9 @@ int main(int argc, char **argv)
        char *server = NULL;
        char *port = NULL;
        int LogSock = -1, socket_type = ALL_TYPES;
-
+#ifdef HAVE_JOURNALD
+       FILE *jfd = NULL;
+#endif
        static const struct option longopts[] = {
                { "id",         no_argument,        0, 'i' },
                { "stderr",     no_argument,        0, 's' },
@@ -287,6 +332,9 @@ int main(int argc, char **argv)
                { "version",    no_argument,        0, 'V' },
                { "help",       no_argument,        0, 'h' },
                { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX },
+#ifdef HAVE_JOURNALD
+               { "journald",   optional_argument,  0, OPT_JOURNALD },
+#endif
                { NULL,         0, 0, 0 }
        };
 
@@ -342,6 +390,17 @@ int main(int argc, char **argv)
                case OPT_PRIO_PREFIX:
                        prio_prefix = 1;
                        break;
+#ifdef HAVE_JOURNALD
+               case OPT_JOURNALD:
+                       if (optarg) {
+                               jfd = fopen(optarg, "r");
+                               if (!jfd)
+                                       err(EXIT_FAILURE, _("cannot open %s"),
+                                           optarg);
+                       } else
+                               jfd = stdin;
+                       break;
+#endif
                case '?':
                default:
                        usage(stderr);
@@ -351,6 +410,14 @@ int main(int argc, char **argv)
        argv += optind;
 
        /* setup for logging */
+#ifdef HAVE_JOURNALD
+       if (jfd) {
+               int ret = journald_entry(jfd);
+               if (stdin != jfd)
+                       fclose(jfd);
+               return ret ? EXIT_FAILURE : EXIT_SUCCESS;
+       }
+#endif
        if (server)
                LogSock = inet_socket(server, port, socket_type);
        else if (usock)