summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBala.FA <barumuga@redhat.com>2013-04-30 17:39:30 +0530
committerVijay Bellur <vbellur@redhat.com>2013-07-19 03:55:35 -0700
commit040319d8bced2f25bf25d8f6b937901c3a40e34b (patch)
tree1aedfec5fb4cd12f7cdbf341bdfbafcd4d36c6c7
parentf75957ab6baef8907c8421f44f785956fbf48038 (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.ac15
-rw-r--r--glusterfs.spec.in6
-rw-r--r--libglusterfs/src/logging.c211
3 files changed, 231 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 896c2415..94e08781 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 85c656d7..96918fac 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 65613f98..b74a4866 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)
{