Blob Blame History Raw
From effa35d1ae33c1ac825317802b6e970e68f98af2 Mon Sep 17 00:00:00 2001
From: Tomas Heinrich <theinric@redhat.com>
Date: Fri, 31 Jan 2014 11:35:55 +0100
Subject: [PATCH] Improve handling of messages without syslog properties

* Don't drop messages without the MESSAGE field
* Set default severity for all messages
  Some messages comming from journald don't have the SYSLOG_PRIORITY
  field. These are typically the messages logged through journald's
  native API. Set the default severity for these messages to 'notice'.
* Set default facility for all messages
  Some messages comming from journald don't have the SYSLOG_FACILITY
  field. These are typically the messages logged through journald's
  native API. Set the default facility for these messages to 'user'.
* Make default priority configurable
---
 doc/imjournal.html            |  16 ++++++
 plugins/imjournal/imjournal.c | 124 +++++++++++++++++++++++++++++++-----------
 2 files changed, 109 insertions(+), 31 deletions(-)

diff --git a/doc/imjournal.html b/doc/imjournal.html
index 8f29169..b4d2105 100644
--- a/doc/imjournal.html
+++ b/doc/imjournal.html
@@ -69,6 +69,18 @@ journal and read only new messages. This option is only used when there is
 no StateFile to avoid message loss.
 </ul>
 
+<li><b>DefaultSeverity</b> &lt;severity&gt;<br>
+Some messages comming from journald don't have the SYSLOG_PRIORITY
+field. These are typically the messages logged through journald's
+native API. This option specifies the default severity for these
+messages. Defaults to 'notice'.
+
+<li><b>DefaultFacility</b> &lt;facility&gt;<br>
+Some messages comming from journald don't have the SYSLOG_FACILITY
+field. These are typically the messages logged through journald's
+native API. This option specifies the default facility for these
+messages. Defaults to 'user'.
+
 <b>Caveats/Known Bugs:</b>
 <p>
 <ul>
@@ -105,6 +117,10 @@ Equivalent to: ratelimit.interval</li>
 Equivalent to: ratelimit.burst</li>
 <li><strong>$ImjournalIgnorePreviousMessages</strong><br>
 Equivalent to: ignorePreviousMessages</li>
+<li><strong>$ImjournalDefaultSeverity</strong><br>
+Equivalent to: DefaultSeverity</li>
+<li><strong>$ImjournalDefaultFacility</strong><br>
+Equivalent to: DefaultFacility</li>
 </ul>
 
 </body>
diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c
index 36c7e04..7d42b84 100755
--- a/plugins/imjournal/imjournal.c
+++ b/plugins/imjournal/imjournal.c
@@ -68,15 +68,21 @@ static struct configSettings_s {
 	int ratelimitInterval;
 	int ratelimitBurst;
 	int bIgnorePrevious;
+	int iDfltSeverity;
+	int iDfltFacility;
 } cs;
 
+static rsRetVal facilityHdlr(uchar **pp, void *pVal);
+
 /* module-global parameters */
 static struct cnfparamdescr modpdescr[] = {
 	{ "statefile", eCmdHdlrGetWord, 0 },
 	{ "ratelimit.interval", eCmdHdlrInt, 0 },
 	{ "ratelimit.burst", eCmdHdlrInt, 0 },
 	{ "persiststateinterval", eCmdHdlrInt, 0 },
-	{ "ignorepreviousmessages", eCmdHdlrBinary, 0 }
+	{ "ignorepreviousmessages", eCmdHdlrBinary, 0 },
+	{ "defaultseverity", eCmdHdlrSeverity, 0 },
+	{ "defaultfacility", eCmdHdlrString, 0 }
 };
 static struct cnfparamblk modpblk =
 	{ CNFPARAMBLK_VERSION,
@@ -85,6 +91,8 @@ static struct cnfparamblk modpblk =
 	};
 
 #define DFLT_persiststateinterval 10
+#define DFLT_SEVERITY LOG_PRI(LOG_NOTICE)
+#define DFLT_FACILITY LOG_FAC(LOG_USER)
 
 static int bLegacyCnfModGlobalsPermitted = 1;/* are legacy module-global config parameters permitted? */
 
@@ -94,6 +102,37 @@ static prop_t *pLocalHostIP = NULL;	/* a pseudo-constant propterty for 127.0.0.1
 static ratelimit_t *ratelimiter = NULL;
 static sd_journal *j;
 
+/* ugly workaround to handle facility numbers; values
+   derived from names need to be eight times smaller */
+static rsRetVal facilityHdlr(uchar **pp, void *pVal)
+{
+	DEFiRet;
+	char *p;
+
+	skipWhiteSpace(pp);
+	p = (char *) *pp;
+
+	if (isdigit((int) *p)) {
+		*((int *) pVal) = (int) strtol(p, (char **) pp, 10);
+	} else {
+		int len;
+		syslogName_t *c;
+
+		for (len = 0; p[len] && !isspace((int) p[len]); len++)
+			/* noop */;
+		for (c = syslogFacNames; c->c_name; c++) {
+			if (!strncasecmp(p, (char *) c->c_name, len)) {
+				*((int *) pVal) = LOG_FAC(c->c_val);
+				break;
+			}
+		}
+		*pp += len;
+	}
+
+	RETiRet;
+}
+
+
 /* enqueue the the journal message into the message queue.
  * The provided msg string is not freed - thus must be done
  * by the caller.
@@ -158,7 +197,6 @@ readjournal() {
 	const void *get;
 	const void *pidget;
 	char *parse;
-	char *get2;
 	size_t length;
 	size_t pidlength;
 
@@ -170,45 +208,52 @@ readjournal() {
 
 	long prefixlen = 0;
 
-	int priority = 0;
-	int facility = 0;
+	int severity = cs.iDfltSeverity;
+	int facility = cs.iDfltFacility;
 
 	/* Get message text */
 	if (sd_journal_get_data(j, "MESSAGE", &get, &length) < 0) {
-		logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar *)"log message from journal doesn't have MESSAGE", 0);
-		iRet = RS_RET_OK;
-		goto ret;
-	}
-	message = strndup(get+8, length-8);
-	if (message == NULL) {
-		iRet = RS_RET_OUT_OF_MEMORY;
-		goto ret;
+		message = strdup("");
+	} else {
+		message = strndup(get+8, length-8);
+		if (message == NULL) {
+			iRet = RS_RET_OUT_OF_MEMORY;
+			goto ret;
+		}
 	}
 
-	/* Get message priority */
+	/* Get message severity ("priority" in journald's terminology) */
 	if (sd_journal_get_data(j, "PRIORITY", &get, &length) >= 0) {
-		get2 = strndup(get, length);
-		priority = ((char *)get2)[9] - '0';
-		free (get2);
+		if (length == 10) {
+			severity = ((char *)get)[9] - '0';
+			if (severity < 0 || 7 < severity) {
+				dbgprintf("The value of the 'PRIORITY' field is "
+					"out of bounds: %d, resetting\n", severity);
+				severity = cs.iDfltSeverity;
+			}
+		} else {
+			dbgprintf("The value of the 'PRIORITY' field has an "
+				"unexpected length: %d\n", length);
+		}
 	}
 
 	/* Get syslog facility */
 	if (sd_journal_get_data(j, "SYSLOG_FACILITY", &get, &length) >= 0) {
-		get2 = strndup(get, length);
-		char f = ((char *)get2)[16];
-		if (f >= '0' && f <= '9') {
-			facility += f - '0';
-		}
-		f = ((char *)get2)[17];
-		if (f >= '0' && f <= '9') {
-			facility *= 10;
-			facility += (f - '0');
+		if (length == 17 || length == 18) {
+			facility = ((char *)get)[16] - '0';
+			if (length == 18) {
+				facility *= 10;
+				facility += ((char *)get)[17] - '0';
+			}
+			if (facility < 0 || 23 < facility) {
+				dbgprintf("The value of the 'FACILITY' field is "
+					"out of bounds: %d, resetting\n", facility);
+				facility = cs.iDfltFacility;
+			}
+		} else {
+			dbgprintf("The value of the 'FACILITY' field has an "
+				"unexpected length: %d\n", length);
 		}
-		free (get2);
-	} else {
-		/* message is missing facility -> internal systemd journal msg, drop */
-		iRet = RS_RET_OK;
-		goto free_message;
 	}
 
 	/* Get message identifier, client pid and add ':' */
@@ -349,7 +394,7 @@ readjournal() {
 	}
 
 	/* submit message */
-	enqMsg((uchar *)message, (uchar *) sys_iden_help, facility, priority, &tv, json);
+	enqMsg((uchar *)message, (uchar *) sys_iden_help, facility, severity, &tv, json);
 
 finalize_it:
 	free(sys_iden_help);
@@ -569,6 +614,8 @@ CODESTARTbeginCnfLoad
 	cs.stateFile = NULL;
 	cs.ratelimitBurst = 20000;
 	cs.ratelimitInterval = 600;
+	cs.iDfltSeverity = DFLT_SEVERITY;
+	cs.iDfltFacility = DFLT_FACILITY;
 ENDbeginCnfLoad
 
 
@@ -657,6 +704,17 @@ CODESTARTsetModCnf
 			cs.ratelimitInterval = (int) pvals[i].val.d.n;
 		} else if (!strcmp(modpblk.descr[i].name, "ignorepreviousmessages")) {
 			cs.bIgnorePrevious = (int) pvals[i].val.d.n; 
+		} else if (!strcmp(modpblk.descr[i].name, "defaultseverity")) {
+			cs.iDfltSeverity = (int) pvals[i].val.d.n;
+		} else if (!strcmp(modpblk.descr[i].name, "defaultfacility")) {
+			/* ugly workaround to handle facility numbers; values
+			   derived from names need to be eight times smaller */
+
+			char *fac, *p;
+
+			fac = p = es_str2cstr(pvals[i].val.d.estr, NULL);
+			facilityHdlr((uchar **) &p, (void *) &cs.iDfltFacility);
+			free(fac);
 		} else {
 			dbgprintf("imjournal: program error, non-handled "
 				"param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
@@ -710,6 +768,10 @@ CODEmodInit_QueryRegCFSLineHdlr
 		NULL, &cs.stateFile, STD_LOADABLE_MODULE_ID));
 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalignorepreviousmessages", 0, eCmdHdlrBinary,
 		NULL, &cs.bIgnorePrevious, STD_LOADABLE_MODULE_ID)); 
+	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournaldefaultseverity", 0, eCmdHdlrSeverity,
+		NULL, &cs.iDfltSeverity, STD_LOADABLE_MODULE_ID));
+	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournaldefaultfacility", 0, eCmdHdlrCustomHandler,
+		facilityHdlr, &cs.iDfltFacility, STD_LOADABLE_MODULE_ID));
 
 
 ENDmodInit
-- 
1.8.4.3