/*
* This file is part of Cockpit.
*
* Copyright (C) 2013 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see .
*/
/* We wrap journal logging, so this is useless */
#define SD_JOURNAL_SUPPRESS_LOCATION 1
#include "config.h"
#include "cockpitlog.h"
#include
#include
#include
#include
#include
static GLogFunc old_handler;
static gboolean have_journal = FALSE;
void
cockpit_null_log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
/* who, me? */
}
void
cockpit_journal_log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
gboolean to_journal = TRUE;
int priority;
const gchar *domains;
/* In case we have generate our own log lines */
const gchar *prefix;
/*
* Note: we should not call GLib fucntions here.
*
* Mapping glib log levels to syslog priorities
* is not at all obvious.
*/
switch (log_level & G_LOG_LEVEL_MASK)
{
/*
* In GLib this is always fatal, caller of this
* function aborts()
*/
case G_LOG_LEVEL_ERROR:
priority = LOG_CRIT;
prefix = "ERROR";
break;
/*
* By convention in GLib applications, critical warnings
* are usually internal programmer error (ie: precondition
* failures). This maps well to LOG_CRIT.
*/
case G_LOG_LEVEL_CRITICAL:
priority = LOG_CRIT;
prefix = "CRITICAL";
break;
/*
* By convention in GLib apps, g_warning() is used for
* non-fatal problems, but ones that should be corrected
* or not be encountered in normal system behavior.
*/
case G_LOG_LEVEL_WARNING:
priority = LOG_ERR;
prefix = "WARNING";
break;
/*
* These are related to bad input, or other hosts behaving
* badly. Map well to syslog warnings.
*/
case G_LOG_LEVEL_MESSAGE:
default:
priority = LOG_WARNING;
prefix = "MESSAGE";
break;
/* Informational messages, startup, shutdown etc. */
case G_LOG_LEVEL_INFO:
priority = LOG_INFO;
prefix = "INFO";
break;
/* Debug messages. */
case G_LOG_LEVEL_DEBUG:
domains = g_getenv ("G_MESSAGES_DEBUG");
if (domains == NULL ||
(strcmp (domains, "all") != 0 && (!log_domain || !strstr (domains, log_domain))))
{
to_journal = FALSE;
}
priority = LOG_INFO;
prefix = "DEBUG";
break;
}
if (to_journal)
{
if (have_journal)
{
sd_journal_send ("MESSAGE=%s", message,
"PRIORITY=%d", (int)priority,
"COCKPIT_DOMAIN=%s", log_domain ? log_domain : "",
NULL);
}
else if (old_handler == NULL)
{
g_printerr ("%s: %s: %s\n",
prefix,
log_domain ? log_domain : "Unknown",
message);
}
}
/* After journal, since this may have side effects */
if (old_handler)
old_handler (log_domain, log_level, message, NULL);
}
void
cockpit_set_journal_logging (const gchar *stderr_domain,
gboolean only)
{
int fd;
/* Don't log to journal while being tested by test-server */
if (g_getenv ("COCKPIT_TEST_SERVER_PORT") != NULL)
only = FALSE;
old_handler = g_log_set_default_handler (cockpit_journal_log_handler, NULL);
/* SELinux won't let us always open the sd_journal_stream_fd
* so just check that the main journal socket exists
*/
have_journal = g_file_test ("/run/systemd/journal/socket", G_FILE_TEST_EXISTS);
if (only)
old_handler = NULL;
if (only && stderr_domain)
{
fd = sd_journal_stream_fd (stderr_domain, LOG_WARNING, 0);
if (fd < 0)
{
if (-fd == ENOENT)
g_debug ("no journal present to stream stderr");
else
g_warning ("couldn't open journal stream for stderr: %s", g_strerror (-fd));
}
else
{
if (dup2 (fd, 2) < 0)
{
g_warning ("couldn't replace journal stream for stderr: %s", g_strerror (errno));
close (fd);
}
}
}
}