Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F5465515
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
37 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment