diff options
| author | Bala.FA <barumuga@redhat.com> | 2013-04-30 17:39:30 +0530 | 
|---|---|---|
| committer | Vijay Bellur <vbellur@redhat.com> | 2013-07-19 03:55:35 -0700 | 
| commit | 040319d8bced2f25bf25d8f6b937901c3a40e34b (patch) | |
| tree | 1aedfec5fb4cd12f7cdbf341bdfbafcd4d36c6c7 | |
| parent | f75957ab6baef8907c8421f44f785956fbf48038 (diff) | |
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>
| -rw-r--r-- | configure.ac | 15 | ||||
| -rw-r--r-- | glusterfs.spec.in | 6 | ||||
| -rw-r--r-- | libglusterfs/src/logging.c | 211 | 
3 files changed, 231 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 896c2415a..94e087811 100644 --- a/configure.ac +++ b/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 diff --git a/glusterfs.spec.in b/glusterfs.spec.in index 85c656d72..96918fac3 100644 --- a/glusterfs.spec.in +++ b/glusterfs.spec.in @@ -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 ) 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 <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)  {  | 
