mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-04 18:26:19 +01:00
Drop libsystemd dependency
Talk to the journal ourselves using sendmsg() instead of linking against libsystemd for sd_journal_sendv(). At the same time, we can also avoid excessive copying. The motivation for dropping the dependency is that we can then use structured logging e.g. in a flatpak sandbox where libsystemd may not be present in the runtime. The code here is inspired by similar code in libvirt.
This commit is contained in:
parent
ca775518d8
commit
6a07885a98
15
configure.ac
15
configure.ac
@ -1730,21 +1730,6 @@ if test x$have_libelf = xyes; then
|
|||||||
AC_DEFINE(HAVE_LIBELF, 1, [Define if libelf is available])
|
AC_DEFINE(HAVE_LIBELF, 1, [Define if libelf is available])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl *************************
|
|
||||||
dnl *** check for systemd ***
|
|
||||||
dnl *************************
|
|
||||||
AC_ARG_ENABLE([libsystemd],
|
|
||||||
[AS_HELP_STRING([--disable-libsystemd],
|
|
||||||
[build without libsystemd support])])
|
|
||||||
AS_IF([test "$enable_libsystemd" != "no"],[
|
|
||||||
PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd],
|
|
||||||
[have_libsystemd=yes], [have_libsystemd=no])
|
|
||||||
])
|
|
||||||
|
|
||||||
AS_IF([test "$have_libsystemd" = "yes"],[
|
|
||||||
AC_DEFINE([HAVE_LIBSYSTEMD],[1],[Define if libsystemd is available])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl ****************************************
|
dnl ****************************************
|
||||||
dnl *** platform dependent source checks ***
|
dnl *** platform dependent source checks ***
|
||||||
dnl ****************************************
|
dnl ****************************************
|
||||||
|
189
glib/gmessages.c
189
glib/gmessages.c
@ -104,6 +104,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include "glib-init.h"
|
#include "glib-init.h"
|
||||||
#include "galloca.h"
|
#include "galloca.h"
|
||||||
@ -130,12 +132,6 @@
|
|||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBSYSTEMD
|
|
||||||
#define SD_JOURNAL_SUPPRESS_LOCATION 1
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <systemd/sd-journal.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:messages
|
* SECTION:messages
|
||||||
@ -1475,7 +1471,7 @@ g_log_structured (const gchar *log_domain,
|
|||||||
|
|
||||||
fields[1].key = "PRIORITY";
|
fields[1].key = "PRIORITY";
|
||||||
fields[1].value = log_level_to_priority (log_level);
|
fields[1].value = log_level_to_priority (log_level);
|
||||||
fields[1].length = 1;
|
fields[1].length = -1;
|
||||||
|
|
||||||
if (log_domain)
|
if (log_domain)
|
||||||
{
|
{
|
||||||
@ -1623,6 +1619,21 @@ g_log_writer_supports_color (gint output_fd)
|
|||||||
return isatty (output_fd);
|
return isatty (output_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int journal_fd = -1;
|
||||||
|
|
||||||
|
static void
|
||||||
|
open_journal (void)
|
||||||
|
{
|
||||||
|
if ((journal_fd = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fcntl (journal_fd, F_SETFD, FD_CLOEXEC) < 0)
|
||||||
|
{
|
||||||
|
close (journal_fd);
|
||||||
|
journal_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_log_writer_is_journald:
|
* g_log_writer_is_journald:
|
||||||
* @output_fd: output file descriptor to check
|
* @output_fd: output file descriptor to check
|
||||||
@ -1637,7 +1648,6 @@ g_log_writer_supports_color (gint output_fd)
|
|||||||
gboolean
|
gboolean
|
||||||
g_log_writer_is_journald (gint output_fd)
|
g_log_writer_is_journald (gint output_fd)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LIBSYSTEMD
|
|
||||||
/* FIXME: Use the new journal API for detecting whether we’re writing to the
|
/* FIXME: Use the new journal API for detecting whether we’re writing to the
|
||||||
* journal. See: https://github.com/systemd/systemd/issues/2473
|
* journal. See: https://github.com/systemd/systemd/issues/2473
|
||||||
*/
|
*/
|
||||||
@ -1654,13 +1664,14 @@ g_log_writer_is_journald (gint output_fd)
|
|||||||
if (err == 0 && addr.ss_family == AF_UNIX)
|
if (err == 0 && addr.ss_family == AF_UNIX)
|
||||||
fd_is_journal = g_str_has_prefix (((struct sockaddr_un *)&addr)->sun_path,
|
fd_is_journal = g_str_has_prefix (((struct sockaddr_un *)&addr)->sun_path,
|
||||||
"/run/systemd/journal/");
|
"/run/systemd/journal/");
|
||||||
|
|
||||||
|
if (fd_is_journal)
|
||||||
|
open_journal ();
|
||||||
|
|
||||||
g_once_init_leave (&initialized, TRUE);
|
g_once_init_leave (&initialized, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd_is_journal;
|
return fd_is_journal;
|
||||||
#else /* if !HAVE_LIBSYSTEMD */
|
|
||||||
return FALSE;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void escape_string (GString *string);
|
static void escape_string (GString *string);
|
||||||
@ -1771,6 +1782,78 @@ g_log_writer_format_fields (GLogLevelFlags log_level,
|
|||||||
return g_string_free (gstring, FALSE);
|
return g_string_free (gstring, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
journal_sendv (struct iovec *iov,
|
||||||
|
gsize iovlen)
|
||||||
|
{
|
||||||
|
int buf_fd = -1;
|
||||||
|
struct msghdr mh;
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
union {
|
||||||
|
struct cmsghdr cmsghdr;
|
||||||
|
guint8 buf[CMSG_SPACE(sizeof(int))];
|
||||||
|
} control;
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
|
char path[] = "/dev/shm/journal.XXXXXX";
|
||||||
|
|
||||||
|
if (journal_fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset (&sa, 0, sizeof (sa));
|
||||||
|
sa.sun_family = AF_UNIX;
|
||||||
|
if (g_strlcpy (sa.sun_path, "/run/systemd/journal/socket", sizeof (sa.sun_path)) >= sizeof (sa.sun_path))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset (&mh, 0, sizeof (mh));
|
||||||
|
mh.msg_name = &sa;
|
||||||
|
mh.msg_namelen = offsetof (struct sockaddr_un, sun_path) + strlen (sa.sun_path);
|
||||||
|
mh.msg_iov = iov;
|
||||||
|
mh.msg_iovlen = iovlen;
|
||||||
|
|
||||||
|
if (sendmsg (journal_fd, &mh, MSG_NOSIGNAL) >= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (errno != EMSGSIZE && errno != ENOBUFS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Message was too large, so dump to temporary file
|
||||||
|
* and pass an FD to the journal
|
||||||
|
*/
|
||||||
|
if ((buf_fd = mkostemp (path, O_CLOEXEC|O_RDWR)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (unlink (path) < 0)
|
||||||
|
{
|
||||||
|
close (buf_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writev (buf_fd, iov, iovlen) < 0)
|
||||||
|
{
|
||||||
|
close (buf_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mh.msg_iov = NULL;
|
||||||
|
mh.msg_iovlen = 0;
|
||||||
|
|
||||||
|
memset (&control, 0, sizeof (control));
|
||||||
|
mh.msg_control = &control;
|
||||||
|
mh.msg_controllen = sizeof (control);
|
||||||
|
|
||||||
|
cmsg = CMSG_FIRSTHDR (&mh);
|
||||||
|
cmsg->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
|
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
|
||||||
|
memcpy (CMSG_DATA (cmsg), &buf_fd, sizeof (int));
|
||||||
|
|
||||||
|
mh.msg_controllen = cmsg->cmsg_len;
|
||||||
|
|
||||||
|
(void) sendmsg (journal_fd, &mh, MSG_NOSIGNAL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_log_writer_journald:
|
* g_log_writer_journald:
|
||||||
* @log_level: log level, either from #GLogLevelFlags, or a user-defined
|
* @log_level: log level, either from #GLogLevelFlags, or a user-defined
|
||||||
@ -1799,9 +1882,11 @@ g_log_writer_journald (GLogLevelFlags log_level,
|
|||||||
gsize n_fields,
|
gsize n_fields,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LIBSYSTEMD
|
const char equals = '=';
|
||||||
gsize i;
|
const char newline = '\n';
|
||||||
struct iovec *pairs;
|
gsize i, k;
|
||||||
|
struct iovec *iov, *v;
|
||||||
|
char *buf;
|
||||||
gint retval;
|
gint retval;
|
||||||
|
|
||||||
g_return_val_if_fail (fields != NULL, G_LOG_WRITER_UNHANDLED);
|
g_return_val_if_fail (fields != NULL, G_LOG_WRITER_UNHANDLED);
|
||||||
@ -1814,38 +1899,66 @@ g_log_writer_journald (GLogLevelFlags log_level,
|
|||||||
* locale’s character set.
|
* locale’s character set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pairs = g_alloca (sizeof (struct iovec) * n_fields);
|
iov = g_alloca (sizeof (struct iovec) * 5 * n_fields);
|
||||||
|
buf = g_alloca (32 * n_fields);
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
v = iov;
|
||||||
for (i = 0; i < n_fields; i++)
|
for (i = 0; i < n_fields; i++)
|
||||||
{
|
{
|
||||||
guint8 *buf = NULL;
|
gsize length;
|
||||||
gsize key_length;
|
gboolean binary;
|
||||||
gsize value_length;
|
|
||||||
|
|
||||||
/* Build the iovec for this field. */
|
if (fields[i].length < 0)
|
||||||
key_length = strlen (fields[i].key);
|
{
|
||||||
value_length =
|
length = strlen (fields[i].value);
|
||||||
(fields[i].length < 0) ? strlen (fields[i].value) : fields[i].length;
|
binary = strchr (fields[i].value, '\n') != NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = fields[i].length;
|
||||||
|
binary = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
buf = g_malloc (key_length + 1 + value_length + 1);
|
if (binary)
|
||||||
pairs[i].iov_base = buf;
|
{
|
||||||
pairs[i].iov_len = key_length + 1 + value_length;
|
guint64 nstr;
|
||||||
|
|
||||||
strncpy ((char *) buf, fields[i].key, key_length);
|
v[0].iov_base = (gpointer)fields[i].key;
|
||||||
buf[key_length] = '=';
|
v[0].iov_len = strlen (fields[i].key);
|
||||||
memcpy ((char *) buf + key_length + 1, fields[i].value, value_length);
|
|
||||||
buf[key_length + 1 + value_length] = '\0';
|
v[1].iov_base = (gpointer)&newline;
|
||||||
|
v[1].iov_len = 1;
|
||||||
|
|
||||||
|
nstr = htole64 (length);
|
||||||
|
memcpy (&buf[k], &nstr, sizeof (nstr));
|
||||||
|
|
||||||
|
v[2].iov_base = &buf[k];
|
||||||
|
v[2].iov_len = sizeof (nstr);
|
||||||
|
v += 3;
|
||||||
|
k += sizeof (nstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v[0].iov_base = (gpointer)fields[i].key;
|
||||||
|
v[0].iov_len = strlen (fields[i].key);
|
||||||
|
|
||||||
|
v[1].iov_base = (gpointer)=
|
||||||
|
v[1].iov_len = 1;
|
||||||
|
v += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
v[0].iov_base = (gpointer)fields[i].value;
|
||||||
|
v[0].iov_len = length;
|
||||||
|
|
||||||
|
v[1].iov_base = (gpointer)&newline;
|
||||||
|
v[1].iov_len = 1;
|
||||||
|
v += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = sd_journal_sendv (pairs, n_fields);
|
retval = journal_sendv (iov, v - iov);
|
||||||
|
|
||||||
for (i = 0; i < n_fields; i++)
|
return retval == 0 ? G_LOG_WRITER_HANDLED : G_LOG_WRITER_UNHANDLED;
|
||||||
g_free (pairs[i].iov_base);
|
|
||||||
|
|
||||||
return (retval == 0) ? G_LOG_WRITER_HANDLED : G_LOG_WRITER_UNHANDLED;
|
|
||||||
#else /* if !HAVE_LIBSYSTEMD */
|
|
||||||
return G_LOG_WRITER_UNHANDLED;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2414,7 +2527,7 @@ g_log_default_handler (const gchar *log_domain,
|
|||||||
|
|
||||||
fields[2].key = "PRIORITY";
|
fields[2].key = "PRIORITY";
|
||||||
fields[2].value = log_level_to_priority (log_level);
|
fields[2].value = log_level_to_priority (log_level);
|
||||||
fields[2].length = 1;
|
fields[2].length = -1;
|
||||||
n_fields++;
|
n_fields++;
|
||||||
|
|
||||||
if (log_domain)
|
if (log_domain)
|
||||||
|
Loading…
Reference in New Issue
Block a user