log: send current gf_log to syslog conditionally

When compile time option GF_USE_SYSLOG is enabled (which is default),
generated logs are sent to syslog with error code ERR_DEV.

User can opt to use traditional log at run time by creating
/var/log/glusterd/logger.conf file and restarting respective gluster
services.

Change-Id: I9837d0f99da1afc2189d7ecd214c4293ec53715a
BUG: 928648
Signed-off-by: Bala.FA <barumuga@redhat.com>
Reviewed-on: http://review.gluster.org/5002
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
Bala.FA 2013-05-14 14:53:07 +05:30 committed by Vijay Bellur
parent 040319d8bc
commit 41b721baee
3 changed files with 170 additions and 19 deletions

65
doc/logging.txt Normal file
View File

@ -0,0 +1,65 @@
New logging framework in glusterfs is targeted for end users like
customers, community members, testers etc. This aims to bring clear,
understandable logs called user logs whereas the current logging are
considered as developer logs. The new framework brings with following
features
* Each message is logged with proper well defined error code and each
error code has well known error message.
* A logbook has defined error code and error messages. It helps to
keep track of possible causes and remedies
* Log are sent to syslog. The syslog application can be configured to
pass them to centralized logging system
* It brings
- Remove repeated log messages
- Send alerts to users on certain events
- Run a program on events
- Call home service on events
Log book:
=========
A log book is a JSON formatted file error-codes.json located in top
level of glusterfs source repository. At compile time, gen-headers.py
generates libglusterfs/src/gf-error-codes.h using the log book and
gf-error-codes.h.template file. libglusterfs/src/gf-error-codes.h
consists of header definitions and helper functions to get message by
code for given locale. Currently it has _gf_get_message() function
returns message for locale 'en'.
New entry to log book is added like
{
"IO_ERROR": {"code": 2233,
"message": {"en": "I/O error occurred"}},
"SETUP_ERROR": {"code": 2240,
"message": {"en": "Setup error"}},
}
Logging:
========
The framework provides two functions
void gf_openlog (const char *ident, int option, int facility);
void gf_syslog (int error_code, int facility_priority, char *format, ...);
Consumers need to call gf_openlog() prior to gf_syslog() like the way
traditional syslog function calls. error_code is mandatory when using
gf_syslog(). For example,
gf_openlog (NULL, -1, -1);
gf_syslog (GF_ERR_DEV, LOG_ERR, "error reading configuration file");
The logs are sent in CEE format (http://cee.mitre.org/) to syslog.
Its targeted to rsyslog syslog server.
This log framework can be disabled either at compile time or run time
- for compile time by passing '--disable-syslog' to ./configure or
'--without syslog' to rpmbuild (or)
- for run time by having a file /var/log/glusterd/logger.conf and
restarting gluster services
Currently all gluster logs are sent with error code GF_ERR_DEV.

View File

@ -25,11 +25,13 @@
#ifdef GF_USE_SYSLOG
#include <libintl.h>
#include <syslog.h>
#include <sys/stat.h>
#include "gf-error-codes.h"
#define GF_JSON_MSG_LENGTH 8192
#define GF_SYSLOG_CEE_FORMAT \
"@cee: {\"msg\": \"%s\", \"gf_code\": \"%u\", \"gf_message\": \"%s\"}"
#define GF_LOG_CONTROL_FILE "/var/lib/glusterd/logger.conf"
#endif /* GF_USE_SYSLOG */
#include "xlator.h"
@ -324,7 +326,20 @@ gf_log_globals_init (void *data)
ctx->log.gf_log_syslog = 1;
ctx->log.sys_log_level = GF_LOG_CRITICAL;
#ifdef GF_LINUX_HOST_OS
#if defined(GF_USE_SYSLOG)
{
/* use default ident and option */
/* TODO: make FACILITY configurable than LOG_DAEMON */
struct stat buf;
if (stat (GF_LOG_CONTROL_FILE, &buf) == 0) {
ctx->log.log_control_file_found = 1; /* use gf_log */
} else {
ctx->log.log_control_file_found = 0;
gf_openlog (NULL, -1, LOG_DAEMON);
}
}
#elif defined(GF_LINUX_HOST_OS)
/* For the 'syslog' output. one can grep 'GlusterFS' in syslog
for serious logs */
openlog ("GlusterFS", LOG_PID, LOG_DAEMON);
@ -426,6 +441,12 @@ _gf_log_nomem (const char *domain, const char *file,
return -1;
}
basename = strrchr (file, '/');
if (basename)
basename++;
else
basename = file;
#if HAVE_BACKTRACE
/* Print 'calling function' */
do {
@ -452,6 +473,25 @@ _gf_log_nomem (const char *domain, const char *file,
} while (0);
#endif /* HAVE_BACKTRACE */
#if defined(GF_USE_SYSLOG)
if (!(ctx->log.log_control_file_found))
{
int priority;
/* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and
other level as is */
if (GF_LOG_TRACE == level || GF_LOG_NONE == level) {
priority = LOG_DEBUG;
} else {
priority = level - 1;
}
gf_syslog (GF_ERR_DEV, priority,
"[%s:%d:%s] %s %s: no memory "
"available for size (%"GF_PRI_SIZET")",
basename, line, function, callstr, domain,
size);
goto out;
}
#endif /* GF_USE_SYSLOG */
ret = gettimeofday (&tv, NULL);
if (-1 == ret)
goto out;
@ -459,12 +499,6 @@ _gf_log_nomem (const char *domain, const char *file,
snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr),
".%"GF_PRI_SUSECONDS, tv.tv_usec);
basename = strrchr (file, '/');
if (basename)
basename++;
else
basename = file;
ret = sprintf (msg, "[%s] %s [%s:%d:%s] %s %s: no memory "
"available for size (%"GF_PRI_SIZET")",
timestr, level_strings[level],
@ -542,6 +576,12 @@ _gf_log_callingfn (const char *domain, const char *file, const char *function,
return -1;
}
basename = strrchr (file, '/');
if (basename)
basename++;
else
basename = file;
#if HAVE_BACKTRACE
/* Print 'calling function' */
do {
@ -568,6 +608,32 @@ _gf_log_callingfn (const char *domain, const char *file, const char *function,
} while (0);
#endif /* HAVE_BACKTRACE */
#if defined(GF_USE_SYSLOG)
if (!(ctx->log.log_control_file_found))
{
int priority;
/* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and
other level as is */
if (GF_LOG_TRACE == level || GF_LOG_NONE == level) {
priority = LOG_DEBUG;
} else {
priority = level - 1;
}
va_start (ap, fmt);
vasprintf (&str2, fmt, ap);
va_end (ap);
gf_syslog (GF_ERR_DEV, priority,
"[%s:%d:%s] %s %d-%s: %s",
basename, line, function,
callstr,
((this->graph) ? this->graph->id:0), domain,
str2);
goto out;
}
#endif /* GF_USE_SYSLOG */
ret = gettimeofday (&tv, NULL);
if (-1 == ret)
goto out;
@ -576,12 +642,6 @@ _gf_log_callingfn (const char *domain, const char *file, const char *function,
snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr),
".%"GF_PRI_SUSECONDS, tv.tv_usec);
basename = strrchr (file, '/');
if (basename)
basename++;
else
basename = file;
ret = gf_asprintf (&str1, "[%s] %s [%s:%d:%s] %s %d-%s: ",
timestr, level_strings[level],
basename, line, function, callstr,
@ -679,6 +739,35 @@ _gf_log (const char *domain, const char *file, const char *function, int line,
return -1;
}
basename = strrchr (file, '/');
if (basename)
basename++;
else
basename = file;
#if defined(GF_USE_SYSLOG)
if (!(ctx->log.log_control_file_found))
{
int priority;
/* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and
other level as is */
if (GF_LOG_TRACE == level || GF_LOG_NONE == level) {
priority = LOG_DEBUG;
} else {
priority = level - 1;
}
va_start (ap, fmt);
vasprintf (&str2, fmt, ap);
va_end (ap);
gf_syslog (GF_ERR_DEV, priority,
"[%s:%d:%s] %d-%s: %s",
basename, line, function,
((this->graph) ? this->graph->id:0), domain, str2);
goto err;
}
#endif /* GF_USE_SYSLOG */
if (ctx->log.logrotate) {
ctx->log.logrotate = 0;
@ -720,12 +809,6 @@ log:
snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr),
".%"GF_PRI_SUSECONDS, tv.tv_usec);
basename = strrchr (file, '/');
if (basename)
basename++;
else
basename = file;
ret = gf_asprintf (&str1, "[%s] %s [%s:%d:%s] %d-%s: ",
timestr, level_strings[level],
basename, line, function,

View File

@ -72,6 +72,9 @@ typedef struct gf_log_handle_ {
FILE *gf_log_logfile;
char *cmd_log_filename;
FILE *cmdlogfile;
#ifdef GF_USE_SYSLOG
int log_control_file_found;
#endif /* GF_USE_SYSLOG */
} gf_log_handle_t;