From 040319d8bced2f25bf25d8f6b937901c3a40e34b Mon Sep 17 00:00:00 2001 From: "Bala.FA" Date: Tue, 30 Apr 2013 17:39:30 +0530 Subject: 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 Reviewed-on: http://review.gluster.org/4915 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- libglusterfs/src/logging.c | 211 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) (limited to 'libglusterfs') diff --git a/libglusterfs/src/logging.c b/libglusterfs/src/logging.c index 65613f985..b74a48669 100644 --- a/libglusterfs/src/logging.c +++ b/libglusterfs/src/logging.c @@ -22,6 +22,16 @@ #include #include +#ifdef GF_USE_SYSLOG +#include +#include +#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) { -- cgit