log: enhance syslog logging using CEE format
This patch enables to use syslog as log target in addition to the default. The logs are sent in CEE format (http://cee.mitre.org/). This logging can be disabled using compile time option by ./configure --disable-syslog (or) rpmbuild glusterfs.tar.gz --without syslog The framework provides two api 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"); Using syslog, admin is free to configure logger to * reduce repeated log messages * forward logs to remote logger * execute a command on certain log pattern * alert people for certain log pattern by email, snmp etc * and many more Change-Id: Ibacbcbbc547192893fc4a46b387496b622e4811f BUG: 928648 Signed-off-by: Bala.FA <barumuga@redhat.com> Reviewed-on: http://review.gluster.org/4915 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
parent
f75957ab6b
commit
040319d8bc
15
configure.ac
15
configure.ac
@ -658,6 +658,20 @@ fi
|
||||
AC_SUBST(CFLAGS)
|
||||
# end enable debug section
|
||||
|
||||
# syslog section
|
||||
AC_ARG_ENABLE([syslog],
|
||||
AC_HELP_STRING([--disable-syslog],
|
||||
[Disable syslog for logging]))
|
||||
|
||||
USE_SYSLOG="yes"
|
||||
if test "x$enable_syslog" != "xno"; then
|
||||
AC_DEFINE(GF_USE_SYSLOG, 1, [Use syslog for logging])
|
||||
else
|
||||
USE_SYSLOG="no"
|
||||
fi
|
||||
AM_CONDITIONAL([ENABLE_SYSLOG], [test x$USE_SYSLOG = xyes])
|
||||
#end syslog section
|
||||
|
||||
BUILD_READLINE=no
|
||||
AC_CHECK_LIB([readline -lcurses],[readline],[RLLIBS="-lreadline -lcurses"])
|
||||
AC_CHECK_LIB([readline -ltermcap],[readline],[RLLIBS="-lreadline -ltermcap"])
|
||||
@ -768,4 +782,5 @@ echo "Enable Debug : $BUILD_DEBUG"
|
||||
echo "systemtap : $BUILD_SYSTEMTAP"
|
||||
echo "Block Device backend : $BUILD_BD_XLATOR"
|
||||
echo "glupy : $BUILD_GLUPY"
|
||||
echo "Use syslog : $USE_SYSLOG"
|
||||
echo
|
||||
|
@ -31,6 +31,10 @@
|
||||
# rpmbuild -ta @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz --without ocf
|
||||
%{?_without_ocf:%global _without_ocf --without-ocf}
|
||||
|
||||
# if you wish to build rpms without syslog logging, compile like this
|
||||
# rpmbuild -ta @PACKAGE_NAME@-@PACKAGE_VERSION@tar.gz --without syslog
|
||||
%{?_without_syslog:%global _without_syslog --disable-syslog}
|
||||
|
||||
%if ( 0%{?fedora} && 0%{?fedora} > 16 ) || ( 0%{?rhel} && 0%{?rhel} > 6 )
|
||||
%global _with_systemd true
|
||||
%endif
|
||||
@ -323,7 +327,7 @@ This package provides the api include files.
|
||||
|
||||
%build
|
||||
./autogen.sh
|
||||
%configure %{?_without_rdma} %{?_without_epoll} %{?_without_fusermount} %{?_without_georeplication} %{?_without_ocf}
|
||||
%configure %{?_without_rdma} %{?_without_epoll} %{?_without_fusermount} %{?_without_georeplication} %{?_without_ocf} %{?_without_syslog}
|
||||
|
||||
# fix hardening and remove rpath in shlibs
|
||||
%if ( 0%{?fedora} && 0%{?fedora} > 17 ) || ( 0%{?rhel} && 0%{?rhel} > 6 )
|
||||
|
@ -22,6 +22,16 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef GF_USE_SYSLOG
|
||||
#include <libintl.h>
|
||||
#include <syslog.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\"}"
|
||||
#endif /* GF_USE_SYSLOG */
|
||||
|
||||
#include "xlator.h"
|
||||
#include "logging.h"
|
||||
#include "defaults.h"
|
||||
@ -102,6 +112,207 @@ gf_log_fini (void)
|
||||
}
|
||||
|
||||
|
||||
#ifdef GF_USE_SYSLOG
|
||||
/**
|
||||
* gf_get_error_message -function to get error message for given error code
|
||||
* @error_code: error code defined by log book
|
||||
*
|
||||
* @return: success: string
|
||||
* failure: NULL
|
||||
*/
|
||||
const char *
|
||||
gf_get_error_message (int error_code) {
|
||||
return _gf_get_message (error_code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gf_openlog -function to open syslog specific to gluster based on
|
||||
* existent of file /var/lib/glusterd/logger.conf
|
||||
* @ident: optional identification string similar to openlog()
|
||||
* @option: optional value to option to openlog(). Passing -1 uses
|
||||
* 'LOG_PID | LOG_NDELAY' as default
|
||||
* @facility: optional facility code similar to openlog(). Passing -1
|
||||
* uses LOG_DAEMON as default
|
||||
*
|
||||
* @return: void
|
||||
*/
|
||||
void
|
||||
gf_openlog (const char *ident, int option, int facility)
|
||||
{
|
||||
int _option = option;
|
||||
int _facility = facility;
|
||||
|
||||
if (-1 == _option) {
|
||||
_option = LOG_PID | LOG_NDELAY;
|
||||
}
|
||||
if (-1 == _facility) {
|
||||
_facility = LOG_LOCAL1;
|
||||
}
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain("gluster", "/usr/share/locale");
|
||||
textdomain("gluster");
|
||||
|
||||
openlog(ident, _option, _facility);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* _json_escape -function to convert string to json encoded string
|
||||
* @str: input string
|
||||
* @buf: buffer to store encoded string
|
||||
* @len: length of @buf
|
||||
*
|
||||
* @return: success: last unprocessed character position by pointer in @str
|
||||
* failure: NULL
|
||||
*
|
||||
* Internal function. Heavily inspired by _ul_str_escape() function in
|
||||
* libumberlog
|
||||
*
|
||||
* Sample output:
|
||||
* [1] str = "devel error"
|
||||
* buf = "devel error"
|
||||
* [2] str = "devel error"
|
||||
* buf = "devel\terror"
|
||||
* [3] str = "I/O error on "/tmp/foo" file"
|
||||
* buf = "I/O error on \"/tmp/foo\" file"
|
||||
* [4] str = "I/O erroron /tmp/bar file"
|
||||
* buf = "I/O error\u001bon /tmp/bar file"
|
||||
*
|
||||
*/
|
||||
char *
|
||||
_json_escape(const char *str, char *buf, size_t len)
|
||||
{
|
||||
static const unsigned char json_exceptions[UCHAR_MAX + 1] =
|
||||
{
|
||||
[0x01] = 1, [0x02] = 1, [0x03] = 1, [0x04] = 1,
|
||||
[0x05] = 1, [0x06] = 1, [0x07] = 1, [0x08] = 1,
|
||||
[0x09] = 1, [0x0a] = 1, [0x0b] = 1, [0x0c] = 1,
|
||||
[0x0d] = 1, [0x0e] = 1, [0x0f] = 1, [0x10] = 1,
|
||||
[0x11] = 1, [0x12] = 1, [0x13] = 1, [0x14] = 1,
|
||||
[0x15] = 1, [0x16] = 1, [0x17] = 1, [0x18] = 1,
|
||||
[0x19] = 1, [0x1a] = 1, [0x1b] = 1, [0x1c] = 1,
|
||||
[0x1d] = 1, [0x1e] = 1, [0x1f] = 1,
|
||||
['\\'] = 1, ['"'] = 1
|
||||
};
|
||||
static const char json_hex_chars[16] = "0123456789abcdef";
|
||||
unsigned char *p = NULL;
|
||||
size_t pos = 0;
|
||||
|
||||
if (!str || !buf || len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = (unsigned char *)str;
|
||||
*p && (pos + 1) < len;
|
||||
p++)
|
||||
{
|
||||
if (json_exceptions[*p] == 0) {
|
||||
buf[pos++] = *p;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pos + 2) >= len) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*p)
|
||||
{
|
||||
case '\b':
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = 'b';
|
||||
break;
|
||||
case '\n':
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = 't';
|
||||
break;
|
||||
case '\\':
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = '\\';
|
||||
break;
|
||||
case '"':
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = '"';
|
||||
break;
|
||||
default:
|
||||
if ((pos + 6) >= len) {
|
||||
buf[pos] = '\0';
|
||||
return (char *)p;
|
||||
}
|
||||
buf[pos++] = '\\';
|
||||
buf[pos++] = 'u';
|
||||
buf[pos++] = '0';
|
||||
buf[pos++] = '0';
|
||||
buf[pos++] = json_hex_chars[(*p) >> 4];
|
||||
buf[pos++] = json_hex_chars[(*p) & 0xf];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buf[pos] = '\0';
|
||||
return (char *)p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gf_syslog -function to submit message to syslog specific to gluster
|
||||
* @error_code: error code defined by log book
|
||||
* @facility_priority: facility_priority of syslog()
|
||||
* @format: optional format string to syslog()
|
||||
*
|
||||
* @return: void
|
||||
*/
|
||||
void
|
||||
gf_syslog (int error_code, int facility_priority, char *format, ...)
|
||||
{
|
||||
char *msg = NULL;
|
||||
char json_msg[GF_JSON_MSG_LENGTH];
|
||||
char *p = NULL;
|
||||
const char *error_message = NULL;
|
||||
char json_error_message[GF_JSON_MSG_LENGTH];
|
||||
va_list ap;
|
||||
|
||||
error_message = gf_get_error_message (error_code);
|
||||
|
||||
va_start (ap, format);
|
||||
if (format) {
|
||||
vasprintf (&msg, format, ap);
|
||||
p = _json_escape (msg, json_msg, GF_JSON_MSG_LENGTH);
|
||||
if (error_message) {
|
||||
p = _json_escape (error_message, json_error_message,
|
||||
GF_JSON_MSG_LENGTH);
|
||||
syslog (facility_priority, GF_SYSLOG_CEE_FORMAT,
|
||||
json_msg, error_code, json_error_message);
|
||||
} else {
|
||||
/* ignore the error code because no error message for it
|
||||
and use normal syslog */
|
||||
syslog (facility_priority, "%s", msg);
|
||||
}
|
||||
free (msg);
|
||||
} else {
|
||||
if (error_message) {
|
||||
/* no user message: treat error_message as msg */
|
||||
syslog (facility_priority, GF_SYSLOG_CEE_FORMAT,
|
||||
json_error_message, error_code,
|
||||
json_error_message);
|
||||
} else {
|
||||
/* cannot produce log as neither error_message nor
|
||||
msg available */
|
||||
}
|
||||
}
|
||||
va_end (ap);
|
||||
}
|
||||
#endif /* GF_USE_SYSLOG */
|
||||
|
||||
void
|
||||
gf_log_globals_init (void *data)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user