Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/include/crm/common/logging.h b/include/crm/common/logging.h
index 3efcc4f4d8..40b813fe64 100644
--- a/include/crm/common/logging.h
+++ b/include/crm/common/logging.h
@@ -1,180 +1,161 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This software 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CRM_LOGGING__H
# define CRM_LOGGING__H
# include <qb/qblog.h>
# ifndef LOG_TRACE
# define LOG_TRACE LOG_DEBUG+1
# endif
# define LOG_DEBUG_2 LOG_TRACE
# define LOG_DEBUG_3 LOG_TRACE
# define LOG_DEBUG_4 LOG_TRACE
# define LOG_DEBUG_5 LOG_TRACE
# define LOG_DEBUG_6 LOG_TRACE
extern unsigned int crm_log_level;
extern gboolean crm_config_error;
extern gboolean crm_config_warning;
void crm_enable_blackbox(int nsig);
void crm_enable_blackbox_tracing(int nsig);
-void crm_write_blackbox(int nsig);
+void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite);
void crm_update_callsites(void);
void crm_log_deinit(void);
gboolean crm_log_cli_init(const char *entity);
gboolean crm_log_init(const char *entity, int level, gboolean daemon,
gboolean to_stderr, int argc, char **argv, gboolean quiet);
void crm_log_args(int argc, char **argv);
gboolean crm_add_logfile(const char *filename);
void crm_bump_log_level(int argc, char **argv);
void crm_enable_stderr(int enable);
gboolean crm_is_callsite_active(struct qb_log_callsite *cs, int level, int tags);
int log_data_element(int log_level, const char *file, const char *function, int line,
const char *prefix, xmlNode * data, int depth, gboolean formatted);
/* returns the old value */
unsigned int set_crm_log_level(unsigned int level);
unsigned int get_crm_log_level(void);
/*
* Throughout the macros below, note the leading, pre-comma, space in the
* various ' , ##args' occurences to aid portability across versions of 'gcc'.
* http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros
*/
# define CRM_TRACE_INIT_DATA(name) QB_LOG_INIT_DATA(name)
-# define do_crm_log(level, fmt, args...) do { \
- qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, 0, ##args); \
- if((level) < LOG_WARNING) { \
- crm_write_blackbox(0); \
- } \
- } while(0)
+# define do_crm_log(level, fmt, args...) qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, 0, ##args)
/* level /MUST/ be a constant or compilation will fail */
# define do_crm_log_unlikely(level, fmt, args...) do { \
static struct qb_log_callsite *trace_cs = NULL; \
if(trace_cs == NULL) { \
trace_cs = qb_log_callsite_get(__func__, __FILE__, fmt, level, __LINE__, 0); \
} \
if (crm_is_callsite_active(trace_cs, level, 0)) { \
qb_log_from_external_source( \
__func__, __FILE__, fmt, level, __LINE__, 0, ##args); \
} \
} while(0)
# define CRM_LOG_ASSERT(expr) do { \
if(__unlikely((expr) == FALSE)) { \
static struct qb_log_callsite *core_cs = NULL; \
if(core_cs == NULL) { \
core_cs = qb_log_callsite_get(__func__, __FILE__, "log-assert", LOG_TRACE, __LINE__, 0); \
} \
crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, \
core_cs?core_cs->targets:FALSE, TRUE); \
} \
} while(0)
# define CRM_CHECK(expr, failure_action) do { \
if(__unlikely((expr) == FALSE)) { \
static struct qb_log_callsite *core_cs = NULL; \
if(core_cs == NULL) { \
core_cs = qb_log_callsite_get(__func__, __FILE__, "check-assert", LOG_TRACE, __LINE__, 0); \
} \
crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, \
core_cs?core_cs->targets:FALSE, TRUE); \
failure_action; \
} \
} while(0)
# define do_crm_log_xml(level, text, xml) do { \
static struct qb_log_callsite *xml_cs = NULL; \
if(xml_cs == NULL) { \
xml_cs = qb_log_callsite_get(__func__, __FILE__, "xml-blog", level, __LINE__, 0); \
} \
if (crm_is_callsite_active(xml_cs, level, 0)) { \
log_data_element(level, __FILE__, __PRETTY_FUNCTION__, __LINE__, text, xml, 0, TRUE); \
} \
- if((level) < LOG_WARNING) { \
- crm_write_blackbox(0); \
- } \
} while(0)
# define do_crm_log_alias(level, file, function, line, fmt, args...) do { \
qb_log_from_external_source(function, file, fmt, level, line, 0, ##args); \
} while(0)
# define do_crm_log_always(level, fmt, args...) qb_log(level, "%s: " fmt, __PRETTY_FUNCTION__ , ##args)
# define crm_perror(level, fmt, args...) do { \
const char *err = strerror(errno); \
fprintf(stderr, fmt ": %s (%d)\n", ##args, err, errno); \
do_crm_log(level, fmt ": %s (%d)", ##args, err, errno); \
- if((level) < LOG_WARNING) { \
- crm_write_blackbox(0); \
- } \
- } while(0)
-
-# define crm_crit(fmt, args...) do { \
- qb_logt(LOG_CRIT, 0, fmt , ##args); \
- crm_write_blackbox(0); \
- } while(0)
-
-# define crm_err(fmt, args...) do { \
- qb_logt(LOG_ERR, 0, fmt , ##args); \
- crm_write_blackbox(0); \
} while(0)
# define crm_log_tag(level, tag, fmt, args...) do { \
static struct qb_log_callsite *trace_tag_cs = NULL; \
int converted_tag = g_quark_try_string(tag); \
if(trace_tag_cs == NULL) { \
trace_tag_cs = qb_log_callsite_get(__func__, __FILE__, fmt, level, __LINE__, converted_tag); \
} \
if (crm_is_callsite_active(trace_tag_cs, level, converted_tag)) { \
qb_log_from_external_source( __func__, __FILE__, fmt, level, __LINE__, converted_tag, ##args); \
} \
} while(0)
+# define crm_crit(fmt, args...) qb_logt(LOG_CRIT, 0, fmt , ##args)
+# define crm_err(fmt, args...) qb_logt(LOG_ERR, 0, fmt , ##args)
# define crm_warn(fmt, args...) qb_logt(LOG_WARNING, 0, fmt , ##args)
# define crm_notice(fmt, args...) qb_logt(LOG_NOTICE, 0, fmt , ##args)
# define crm_info(fmt, args...) qb_logt(LOG_INFO, 0, fmt , ##args)
# define crm_debug(fmt, args...) do_crm_log_unlikely(LOG_DEBUG, fmt , ##args)
# define crm_trace(fmt, args...) do_crm_log_unlikely(LOG_TRACE, fmt , ##args)
# define crm_log_xml_crit(xml, text) do_crm_log_xml(LOG_CRIT, text, xml)
# define crm_log_xml_err(xml, text) do_crm_log_xml(LOG_ERR, text, xml)
# define crm_log_xml_warn(xml, text) do_crm_log_xml(LOG_WARNING, text, xml)
# define crm_log_xml_notice(xml, text) do_crm_log_xml(LOG_NOTICE, text, xml)
# define crm_log_xml_info(xml, text) do_crm_log_xml(LOG_INFO, text, xml)
# define crm_log_xml_debug(xml, text) do_crm_log_xml(LOG_DEBUG, text, xml)
# define crm_log_xml_trace(xml, text) do_crm_log_xml(LOG_TRACE, text, xml)
# define crm_str(x) (const char*)(x?x:"<null>")
#endif
diff --git a/lib/common/logging.c b/lib/common/logging.c
index 7f2785cf38..3da51c7172 100644
--- a/lib/common/logging.c
+++ b/lib/common/logging.c
@@ -1,771 +1,811 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This library 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.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <libgen.h>
#include <signal.h>
#include <qb/qbdefs.h>
#include <crm/crm.h>
#include <crm/common/mainloop.h>
unsigned int crm_log_level = LOG_INFO;
static gboolean crm_tracing_enabled(void);
#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER
GLogFunc glib_log_default;
static void
crm_glib_handler(const gchar * log_domain, GLogLevelFlags flags, const gchar * message,
gpointer user_data)
{
int log_level = LOG_WARNING;
GLogLevelFlags msg_level = (flags & G_LOG_LEVEL_MASK);
switch (msg_level) {
case G_LOG_LEVEL_CRITICAL:
/* log and record how we got here */
crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, message, TRUE, TRUE);
return;
case G_LOG_LEVEL_ERROR:
log_level = LOG_ERR;
break;
case G_LOG_LEVEL_MESSAGE:
log_level = LOG_NOTICE;
break;
case G_LOG_LEVEL_INFO:
log_level = LOG_INFO;
break;
case G_LOG_LEVEL_DEBUG:
log_level = LOG_DEBUG;
break;
case G_LOG_LEVEL_WARNING:
case G_LOG_FLAG_RECURSION:
case G_LOG_FLAG_FATAL:
case G_LOG_LEVEL_MASK:
log_level = LOG_WARNING;
break;
}
do_crm_log(log_level, "%s: %s", log_domain, message);
}
#endif
#ifndef NAME_MAX
# define NAME_MAX 256
#endif
+
+static void
+crm_trigger_blackbox(int nsig)
+{
+ crm_write_blackbox(nsig, NULL);
+}
+
static const char *
daemon_option(const char *option)
{
char env_name[NAME_MAX];
const char *value = NULL;
snprintf(env_name, NAME_MAX, "PCMK_%s", option);
value = getenv(env_name);
if (value != NULL) {
return value;
}
snprintf(env_name, NAME_MAX, "HA_%s", option);
value = getenv(env_name);
if (value != NULL) {
return value;
}
return NULL;
}
static gboolean
daemon_option_enabled(const char *daemon, const char *option)
{
const char *value = daemon_option(option);
if (value != NULL && crm_is_true(value)) {
return TRUE;
} else if (value != NULL && strstr(value, daemon)) {
return TRUE;
}
return FALSE;
}
void
crm_log_deinit(void)
{
#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER
g_log_set_default_handler(glib_log_default, NULL);
#endif
}
#define FMT_MAX 256
static void
set_format_string(int method, const char *daemon)
{
int offset = 0;
char fmt[FMT_MAX];
if (method > QB_LOG_STDERR) {
/* When logging to a file */
struct utsname res;
if (uname(&res) == 0) {
offset +=
snprintf(fmt + offset, FMT_MAX - offset, "%%t [%d] %s %10s: ", getpid(),
res.nodename, daemon);
} else {
offset += snprintf(fmt + offset, FMT_MAX - offset, "%%t [%d] %10s: ", getpid(), daemon);
}
}
if (crm_tracing_enabled() && method >= QB_LOG_STDERR) {
offset += snprintf(fmt + offset, FMT_MAX - offset, "(%%-12f:%%5l %%g) %%-7p: %%n: ");
} else {
offset += snprintf(fmt + offset, FMT_MAX - offset, "%%g %%-7p: %%n: ");
}
if (method == QB_LOG_SYSLOG) {
offset += snprintf(fmt + offset, FMT_MAX - offset, "%%b");
} else {
offset += snprintf(fmt + offset, FMT_MAX - offset, "\t%%b");
}
qb_log_format_set(method, fmt);
}
gboolean
crm_add_logfile(const char *filename)
{
struct stat parent;
int fd = 0, rc = 0;
FILE *logfile = NULL;
char *parent_dir = NULL;
static gboolean have_logfile = FALSE;
if(filename == NULL && have_logfile == FALSE) {
filename = "/var/log/pacemaker.log";
}
if (filename == NULL) {
return FALSE; /* Nothing to do */
}
/* Check the parent directory and attempt to open */
parent_dir = dirname(strdup(filename));
rc = stat(parent_dir, &parent);
if (rc != 0) {
crm_err("Directory '%s' does not exist: logging to '%s' is disabled", parent_dir, filename);
return FALSE;
} else if (parent.st_uid == geteuid() && (parent.st_mode & (S_IRUSR | S_IWUSR))) {
/* all good - user */
logfile = fopen(filename, "a");
} else if (parent.st_gid == getegid() && (parent.st_mode & S_IXGRP)) {
/* all good - group */
logfile = fopen(filename, "a");
} else {
crm_err("We (uid=%u, gid=%u) do not have permission to access '%s': logging to '%s' is disabled",
geteuid(), getegid(), parent_dir, filename);
return FALSE;
}
/* Check/Set permissions if we're root */
if(logfile && geteuid() == 0) {
struct stat st;
uid_t pcmk_uid = 0;
gid_t pcmk_gid = 0;
gboolean fix = FALSE;
int logfd = fileno(logfile);
rc = fstat(logfd, &st);
if(rc < 0) {
crm_perror(LOG_WARNING, "Cannot stat %s", filename);
fclose(logfile);
return FALSE;
}
crm_user_lookup(CRM_DAEMON_USER, &pcmk_uid, &pcmk_gid);
if(st.st_gid != pcmk_gid) {
/* Wrong group */
fix = TRUE;
} else if((st.st_mode & S_IRWXG) != (S_IRGRP|S_IWGRP)) {
/* Not read/writable by the correct group */
fix = TRUE;
}
if(fix) {
rc = fchown(logfd, pcmk_uid, pcmk_gid);
if(rc < 0) {
crm_warn("Cannot change the ownership of %s to user %s and gid %d",
filename, CRM_DAEMON_USER, pcmk_gid);
}
rc = fchmod(logfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if(rc < 0) {
crm_warn("Cannot change the mode of %s to rw-rw----", filename);
}
fprintf(logfile, "Set r/w permissions for uid=%d, gid=%d on %s\n",
pcmk_uid, pcmk_gid, filename);
if(fflush(logfile) < 0 || fsync(logfd) < 0) {
crm_err("Couldn't write out logfile: %s", filename);
}
}
}
if(logfile) {
fclose(logfile);
}
/* Now open with libqb */
fd = qb_log_file_open(filename);
if(fd < 0) {
crm_perror(LOG_WARNING, "Couldn't send additional logging to %s", filename);
return FALSE;
}
crm_notice("Additional logging available in %s", filename);
qb_log_ctl(fd, QB_LOG_CONF_ENABLED, QB_TRUE);
/* Enable callsites */
crm_update_callsites();
have_logfile = TRUE;
return TRUE;
}
+static int blackbox_trigger = 0;
static char *blackbox_file_prefix = NULL;
+static void
+blackbox_logger(int32_t t, struct qb_log_callsite *cs, time_t timestamp, const char *msg)
+{
+ crm_write_blackbox(0, cs);
+}
+
void
crm_enable_blackbox(int nsig)
{
if(blackbox_file_prefix == NULL) {
pid_t pid = getpid();
blackbox_file_prefix = malloc(NAME_MAX);
snprintf(blackbox_file_prefix, NAME_MAX, "%s/blackbox-%s-%d", CRM_BLACKBOX_DIR, crm_system_name, pid);
}
if (qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 5*1024*1024); /* Any size change drops existing entries */
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE); /* Setting the size seems to disable it */
crm_notice("Initiated blackbox recorder: %s", blackbox_file_prefix);
- crm_signal(SIGSEGV, crm_write_blackbox);
+ crm_signal(SIGSEGV, crm_trigger_blackbox);
crm_update_callsites();
/* Original meanings from signal(7)
*
* Signal Value Action Comment
* SIGTRAP 5 Core Trace/breakpoint trap
*
* Our usage is as similar as possible
*/
- mainloop_add_signal(SIGTRAP, crm_write_blackbox);
+ mainloop_add_signal(SIGTRAP, crm_trigger_blackbox);
+
+ blackbox_trigger = qb_log_custom_open(blackbox_logger, NULL, NULL, NULL);
+ qb_log_ctl(blackbox_trigger, QB_LOG_CONF_ENABLED, QB_TRUE);
+ crm_info("Trigger: %d is %d %d", blackbox_trigger, qb_log_ctl(blackbox_trigger, QB_LOG_CONF_STATE_GET, 0), QB_LOG_STATE_ENABLED);
+
+ crm_update_callsites();
}
}
void
-crm_write_blackbox(int nsig)
+crm_write_blackbox(int nsig, struct qb_log_callsite *cs)
{
static int counter = 1;
static time_t last = 0;
char buffer[NAME_MAX];
time_t now = time(NULL);
if(blackbox_file_prefix == NULL) {
return;
}
switch(nsig) {
case 0:
case SIGTRAP:
/* The graceful case - such as assertion failure or user request */
snprintf(buffer, NAME_MAX, "%s.%d", blackbox_file_prefix, counter++);
if(nsig == 0 && (now - last) < 2) {
/* Prevent over-dumping */
return;
} else if(nsig == SIGTRAP) {
crm_notice("Blackbox dump requested, please see %s for contents", buffer);
+ } else if(cs) {
+ syslog(LOG_NOTICE, "Problem detected at %s:%d (%s), please see %s for additional details",
+ cs->function, cs->lineno, cs->filename, buffer);
} else {
crm_notice("Problem detected, please see %s for additional details", buffer);
}
+
last = now;
qb_log_blackbox_write_to_file(buffer);
/* Flush the existing contents
* A size change would also work
*/
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
break;
default:
/* Do as little as possible, just try to get what we have out
* We logged the filename when the blackbox was enabled
*/
crm_signal(nsig, SIG_DFL);
qb_log_blackbox_write_to_file(blackbox_file_prefix);
qb_log_fini();
raise(nsig);
break;
}
}
gboolean
crm_log_cli_init(const char *entity)
{
return crm_log_init(entity, LOG_ERR, FALSE, FALSE, 0, NULL, TRUE);
}
static const char *crm_quark_to_string(uint32_t tag)
{
const char *text = g_quark_to_string(tag);
if(text) {
return text;
}
return "";
}
static void
-crm_log_filter_source(int source, const char *trace_files, const char *trace_fns, const char *trace_fmts, const char *trace_tags, struct qb_log_callsite *cs)
+crm_log_filter_source(int source, const char *trace_files, const char *trace_fns, const char *trace_fmts, const char *trace_tags, const char *trace_blackbox, struct qb_log_callsite *cs)
{
if (qb_log_ctl(source, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
return;
} else if(source == QB_LOG_BLACKBOX) { /* Blackbox gets everything if enabled */
qb_bit_set(cs->targets, source);
+
+ } else if(source == blackbox_trigger && blackbox_trigger > 0) {
+ /* Should this log message result in the blackbox being dumped */
+ if(cs->priority <= LOG_ERR) {
+ qb_bit_set(cs->targets, source);
+
+ } else if(trace_blackbox) {
+ char *key = g_strdup_printf("%s:%d", cs->function, cs->lineno);
+ if(strstr(trace_blackbox, key) != NULL) {
+ qb_bit_set(cs->targets, source);
+ }
+ free(key);
+ }
+
} else if (source == QB_LOG_SYSLOG) { /* No tracing to syslog */
if(cs->priority <= LOG_NOTICE && cs->priority <= crm_log_level) {
qb_bit_set(cs->targets, source);
}
/* Log file tracing options... */
} else if (cs->priority <= crm_log_level) {
qb_bit_set(cs->targets, source);
} else if(trace_files && strstr(trace_files, cs->filename) != NULL) {
qb_bit_set(cs->targets, source);
} else if(trace_fns && strstr(trace_fns, cs->function) != NULL) {
qb_bit_set(cs->targets, source);
} else if(trace_fmts && strstr(trace_fmts, cs->format) != NULL) {
qb_bit_set(cs->targets, source);
} else if(trace_tags && cs->tags != 0 && g_quark_to_string(cs->tags) != NULL) {
qb_bit_set(cs->targets, source);
}
}
static void
crm_log_filter(struct qb_log_callsite *cs)
{
int lpc = 0;
static int need_init = 1;
static const char *trace_fns = NULL;
static const char *trace_tags = NULL;
static const char *trace_fmts = NULL;
static const char *trace_files = NULL;
+ static const char *trace_blackbox = NULL;
if(need_init) {
need_init = 0;
trace_fns = getenv("PCMK_trace_functions");
trace_fmts = getenv("PCMK_trace_formats");
trace_tags = getenv("PCMK_trace_tags");
trace_files = getenv("PCMK_trace_files");
+ trace_blackbox = getenv("PCMK_trace_blackbox");
if (trace_tags != NULL) {
uint32_t tag;
char token[500];
const char *offset = NULL;
const char *next = trace_tags;
do {
offset = next;
next = strchrnul(offset, ',');
snprintf(token, 499, "%.*s", (int)(next - offset), offset);
tag = g_quark_from_string(token);
crm_info("Created GQuark %u from token '%s' in '%s'", tag, token, trace_tags);
if (next[0] != 0) {
next++;
}
} while (next != NULL && next[0] != 0);
}
}
cs->targets = 0; /* Reset then find targets to enable */
for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) {
- crm_log_filter_source(lpc, trace_files, trace_fns, trace_fmts, trace_tags, cs);
+ crm_log_filter_source(lpc, trace_files, trace_fns, trace_fmts, trace_tags, trace_blackbox, cs);
}
}
gboolean
crm_is_callsite_active(struct qb_log_callsite *cs, int level, int tags)
{
gboolean refilter = FALSE;
if (cs == NULL) {
return FALSE;
}
if (cs->priority != level) {
cs->priority = level;
refilter = TRUE;
}
if (cs->tags != tags) {
cs->tags = tags;
refilter = TRUE;
}
if (refilter) {
crm_log_filter(cs);
}
if (cs->targets == 0) {
return FALSE;
}
return TRUE;
}
void
crm_update_callsites(void)
{
static gboolean log = TRUE;
if(log) {
log = FALSE;
crm_info("Enabling callsites based on priority=%d, files=%s, functions=%s, formats=%s, tags=%s",
crm_log_level,
getenv("PCMK_trace_files"),
getenv("PCMK_trace_functions"),
getenv("PCMK_trace_formats"),
getenv("PCMK_trace_tags"));
}
qb_log_filter_fn_set(crm_log_filter);
}
static gboolean
crm_tracing_enabled(void)
{
if(crm_log_level >= LOG_TRACE) {
return TRUE;
} else if(getenv("PCMK_trace_files") || getenv("PCMK_trace_functions") || getenv("PCMK_trace_formats") || getenv("PCMK_trace_tags")) {
return TRUE;
}
return FALSE;
}
gboolean
crm_log_init(const char *entity, int level, gboolean daemon, gboolean to_stderr,
int argc, char **argv, gboolean quiet)
{
int lpc = 0;
const char *logfile = daemon_option("debugfile");
const char *facility = daemon_option("logfacility");
/* Redirect messages from glib functions to our handler */
#ifdef HAVE_G_LOG_SET_DEFAULT_HANDLER
glib_log_default = g_log_set_default_handler(crm_glib_handler, NULL);
#endif
/* and for good measure... - this enum is a bit field (!) */
g_log_set_always_fatal((GLogLevelFlags) 0); /*value out of range */
if (facility == NULL) {
/* Set a default */
facility = "daemon";
}
if (entity) {
crm_system_name = entity;
} else if (argc > 0 && argv != NULL) {
char *mutable = strdup(argv[0]);
crm_system_name = basename(mutable);
if (strstr(crm_system_name, "lt-") == crm_system_name) {
crm_system_name += 3;
}
} else if (crm_system_name == NULL) {
crm_system_name = "Unknown";
}
setenv("PCMK_service", crm_system_name, 1);
if (daemon_option_enabled(crm_system_name, "debug")) {
/* Override the default setting */
level = LOG_DEBUG;
}
if (daemon_option_enabled(crm_system_name, "stderr")) {
/* Override the default setting */
to_stderr = TRUE;
}
crm_log_level = level;
qb_log_init(crm_system_name, qb_log_facility2int(facility), level);
qb_log_tags_stringify_fn_set(crm_quark_to_string);
/* Set default format strings */
for (lpc = QB_LOG_SYSLOG; lpc < QB_LOG_TARGET_MAX; lpc++) {
set_format_string(lpc, crm_system_name);
}
if (quiet) {
/* Nuke any syslog activity */
unsetenv("HA_logfacility");
unsetenv("PCMK_logfacility");
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
} else if(daemon) {
setenv("HA_logfacility", facility, TRUE);
setenv("PCMK_logfacility", facility, TRUE);
} else {
crm_log_args(argc, argv);
}
if (daemon_option_enabled(crm_system_name, "blackbox")) {
crm_enable_blackbox(0);
}
crm_enable_stderr(to_stderr);
if(logfile) {
crm_add_logfile(logfile);
}
if(daemon
&& crm_tracing_enabled()
&& qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED
&& qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
/* Make sure tracing goes somewhere */
crm_add_logfile(NULL);
}
crm_update_callsites();
/* Ok, now we can start logging... */
if (daemon) {
const char *user = getenv("USER");
if (user != NULL && safe_str_neq(user, "root") && safe_str_neq(user, CRM_DAEMON_USER)) {
crm_trace("Not switching to corefile directory for %s", user);
daemon = FALSE;
}
}
if (daemon) {
int user = getuid();
const char *base = CRM_CORE_DIR;
struct passwd *pwent = getpwuid(user);
if (pwent == NULL) {
crm_perror(LOG_ERR, "Cannot get name for uid: %d", user);
} else if (safe_str_neq(pwent->pw_name, "root")
&& safe_str_neq(pwent->pw_name, CRM_DAEMON_USER)) {
crm_trace("Don't change active directory for regular user: %s", pwent->pw_name);
} else if (chdir(base) < 0) {
crm_perror(LOG_INFO, "Cannot change active directory to %s", base);
} else if (chdir(pwent->pw_name) < 0) {
crm_perror(LOG_INFO, "Cannot change active directory to %s/%s", base, pwent->pw_name);
} else {
crm_info("Changed active directory to %s/%s", base, pwent->pw_name);
#if 0
{
char path[512];
snprintf(path, 512, "%s-%d", crm_system_name, getpid());
mkdir(path, 0750);
chdir(path);
crm_info("Changed active directory to %s/%s/%s", base, pwent->pw_name, path);
}
#endif
}
mainloop_add_signal(SIGUSR1, crm_enable_blackbox);
}
return TRUE;
}
/* returns the old value */
unsigned int
set_crm_log_level(unsigned int level)
{
unsigned int old = crm_log_level;
crm_log_level = level;
crm_update_callsites();
crm_info("New log level: %d", level);
return old;
}
void
crm_enable_stderr(int enable)
{
if (enable && qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) != QB_LOG_STATE_ENABLED) {
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
crm_update_callsites();
} else if (enable == FALSE) {
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE);
}
}
void
crm_bump_log_level(int argc, char **argv)
{
static int args = TRUE;
int level = crm_log_level;
if(args && argc > 1) {
int restore = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
args = FALSE;
crm_log_level = LOG_NOTICE; /* So that the argstring comes out */
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
crm_update_callsites();
crm_log_args(argc, argv);
crm_log_level = level; /* Revert back */
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, restore);
}
if (qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0) == QB_LOG_STATE_ENABLED) {
set_crm_log_level(level + 1);
}
/* Enable after potentially logging the argstring, not before */
crm_enable_stderr(TRUE);
}
unsigned int
get_crm_log_level(void)
{
return crm_log_level;
}
void
crm_log_args(int argc, char **argv)
{
int lpc = 0;
int len = 0;
int existing_len = 0;
char *arg_string = NULL;
if (argc == 0 || argv == NULL) {
return;
}
for (; lpc < argc; lpc++) {
if (argv[lpc] == NULL) {
break;
}
len = 2 + strlen(argv[lpc]); /* +1 space, +1 EOS */
arg_string = realloc(arg_string, len + existing_len);
existing_len += sprintf(arg_string + existing_len, "%s ", argv[lpc]);
}
do_crm_log_always(LOG_NOTICE, "Invoked: %s", arg_string);
free(arg_string);
}
const char *
pcmk_strerror(int rc)
{
int error = rc;
if(rc < 0) {
error = 0 - rc;
}
if(error == 0) {
return "OK";
} else if(error < PCMK_ERROR_OFFSET) {
return strerror(error);
}
switch(error) {
case pcmk_err_generic:
return "Generic Pacemaker error";
case pcmk_err_no_quorum:
return "Operation requires quorum";
case pcmk_err_dtd_validation:
return "Update does not conform to the configured schema";
case pcmk_err_transform_failed:
return "Schema transform failed";
case pcmk_err_old_data:
return "Update was older than existing configuration";
case pcmk_err_diff_failed:
return "Application of an update diff failed";
case pcmk_err_diff_resync:
return "Application of an update diff failed, requesting a full refresh";
/* The following cases will only be hit on systems for which they are non-standard */
/* coverity[dead_error_condition] False positive on non-Linux */
case ENOTUNIQ:
return "Name not unique on network";
/* coverity[dead_error_condition] False positive on non-Linux */
case ECOMM:
return "Communication error on send";
/* coverity[dead_error_condition] False positive on non-Linux */
case ELIBACC:
return "Can not access a needed shared library";
/* coverity[dead_error_condition] False positive on non-Linux */
case EREMOTEIO:
return "Remote I/O error";
/* coverity[dead_error_condition] False positive on non-Linux */
case EUNATCH:
return "Protocol driver not attached";
/* coverity[dead_error_condition] False positive on non-Linux */
case ENOKEY:
return "Required key not available";
}
crm_err("Unknown error code: %d", rc);
return "Unknown error";
}
diff --git a/mcp/pacemaker.sysconfig b/mcp/pacemaker.sysconfig
index 10f654b0a8..d63604d3c6 100644
--- a/mcp/pacemaker.sysconfig
+++ b/mcp/pacemaker.sysconfig
@@ -1,73 +1,76 @@
# For non-systemd based systems, prefix export to each enabled line
#==#==# Variables that control logging
# Enable debug logging globally or per-subsystem
# Multiple subsystems may me listed separated by commas
# eg. PCMK_debug=crmd,pengine
# PCMK_debug=yes|no|crmd|pengine|cib|stonith-ng|attrd|pacemakerd
# Send INFO (and higher) messages to the named log file
# Additional messages may also appear here depending on any configured debug and trace settings
# By default Pacemaker will inherit the logfile specified in corosync.conf
# PCMK_debugfile=/var/log/pacemaker.log
# Specify an alternate syslog target for NOTICE (and higher) messages
# Use 'none' to disable - not recommended
# The default value is 'daemon'
# PCMK_logfacility=none|daemon|user|local0|local1|local2|local3|local4|local5|local6|local7
# Log all messages from a comma-separated list of functions
# PCMK_trace_functions=function1,function2,function3
# Log all messages from a comma-separated list of files (no path)
# Supports wildcards eg. PCMK_trace_files=prefix*.c
# PCMK_trace_files=file.c,other.h
# Log all messages matching comma-separated list of formats
# PCMK_trace_formats="Sent delete %d"
# Log all messages from a comma-separated list of tags
# PCMK_trace_tags=tag1,tag2
+# Dump the blackbox whenever the message at function and line is printed
+# eg. PCMK_trace_blackbox=te_graph_trigger:223,unpack_clone:81
+# PCMK_trace_blackbox=fn:line,fn2:line2,...
+
# Enable blackbox logging globally or per-subsystem
-# Blackbox data is written after a crash, assertion failure and/or when SIGTRAP is recieved
-# The blackbox recorder can also be enabled for Pacemaker daemons at runtime by sending SIGUSR1
+# The blackbox contains a rolling buffer of all logs (including info+debug+trace)
+# and is written after a crash, assertion failure and/or when SIGTRAP is recieved
#
-# After the blackbox has been enabled, additional (very verbose) tracing can
-# be turned on with SIGPROF
+# The blackbox recorder can also be enabled for Pacemaker daemons at runtime by sending SIGUSR1
#
# Multiple subsystems may me listed separated by commas
# eg. PCMK_blackbox=crmd,pengine
# PCMK_blackbox=yes|no|crmd|pengine|cib|stonith-ng|attrd|pacemakerd
#==#==# Advanced use only
# Enable this for compatibility with older corosync (prior to 2.0)
# based clusters which used the nodes uname as its uuid also
# PCMK_uname_is_uuid=no
# Specify an alternate location for RNG schemas and XSL transforms
# Mostly only useful for developer testing
# PCMK_schema_directory=/some/path
#==#==# IPC
# Force use of a particular class of IPC connection
# PCMK_ipc_type=shared-mem|socket|posix|sysv
# Specify an IPC buffer size in bytes
# Useful when connecting to really big clusters that exceed the default 20k buffer
# PCMK_ipc_buffer=20480
#==#==# Profiling and memory leak testing
# Variables for running child daemons under valgrind and/or checking for memory problems
# G_SLICE=always-malloc
# MALLOC_PERTURB_=221 # or 0
# MALLOC_CHECK_=3 # or 0,1,2
# PCMK_valgrind_enabled=yes
# PCMK_valgrind_enabled=cib,crmd
# PCMK_callgrind_enabled=yes
# PCMK_callgrind_enabled=cib,crmd
# VALGRIND_OPTS="--leak-check=full --trace-children=no --num-callers=25 --log-file=/tmp/pacemaker-%p.valgrind"

File Metadata

Mime Type
text/x-diff
Expires
Mon, Sep 1, 7:05 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2280338
Default Alt Text
(37 KB)

Event Timeline