Blame SOURCES/rsyslog-8.37.0-rhbz1627941-imfile-support-for-endmsg.regex.patch

763e28
From e8d64cbd15fa84907dc23f8b52d6f2f847b46fec Mon Sep 17 00:00:00 2001
763e28
From: Rich Megginson <rmeggins@redhat.com>
763e28
Date: Mon, 10 Sep 2018 17:25:38 -0600
763e28
Subject: [PATCH] imfile: support for endmsg.regex
763e28
763e28
This adds support for endmsg.regex.  It is similar to
763e28
startmsg.regex except that it matches the line that denotes
763e28
the end of the message, rather than the start of the next message.
763e28
This is primarily for container log file use cases such as this:
763e28
763e28
    date stdout P start of message
763e28
    date stdout P  middle of message
763e28
    date stdout F  end of message
763e28
763e28
The `F` means this is the line which contains the final part of
763e28
the message.  The fully assembled message should be
763e28
`start of message middle of message end of message`.
763e28
`startmsg.regex="^[^ ]+ stdout F "` will match.
763e28
763e28
(cherry picked from commit c902a0938fe163b5351829d2b72001d024895c16)
763e28
(cherry picked from commit dd4a72c4d52d8da98ed6b86114868e1a450ccb41)
763e28
---
763e28
 plugins/imfile/imfile.c                      |  44 ++++--
763e28
 plugins/imptcp/imptcp.c                      |  10 +-
763e28
 runtime/stream.c                             |  28 +++-
763e28
 runtime/stream.h                             |   2 +-
763e28
 4 files changed, 62 insertions(+), 20 deletions(-)
763e28
763e28
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
763e28
index 7767c9f02..87706082f 100644
763e28
--- a/plugins/imfile/imfile.c
763e28
+++ b/plugins/imfile/imfile.c
763e28
@@ -126,7 +126,9 @@ struct instanceConf_s {
763e28
 	sbool bRMStateOnDel;
763e28
 	uint8_t readMode;
763e28
 	uchar *startRegex;
763e28
-	regex_t end_preg;	/* compiled version of startRegex */
763e28
+	uchar *endRegex;
763e28
+	regex_t start_preg;	/* compiled version of startRegex */
763e28
+	regex_t end_preg;	/* compiled version of endRegex */
763e28
 	sbool discardTruncatedMsg;
763e28
 	sbool msgDiscardingError;
763e28
 	sbool escapeLF;
763e28
@@ -281,6 +283,7 @@ static struct cnfparamdescr inppdescr[] = {
763e28
 	{ "ruleset", eCmdHdlrString, 0 },
763e28
 	{ "readmode", eCmdHdlrInt, 0 },
763e28
 	{ "startmsg.regex", eCmdHdlrString, 0 },
763e28
+	{ "endmsg.regex", eCmdHdlrString, 0 },
763e28
 	{ "discardtruncatedmsg", eCmdHdlrBinary, 0 },
763e28
 	{ "msgdiscardingerror", eCmdHdlrBinary, 0 },
763e28
 	{ "escapelf", eCmdHdlrBinary, 0 },
763e28
@@ -1421,6 +1424,7 @@ pollFileReal(act_obj_t *act, cstr_t **pCStr)
763e28
 	int64 strtOffs;
763e28
 	DEFiRet;
763e28
 	int nProcessed = 0;
763e28
+	regex_t *start_preg = NULL, *end_preg = NULL;
763e28
 
763e28
 	DBGPRINTF("pollFileReal enter, pStrm %p, name '%s'\n", act->pStrm, act->name);
763e28
 	DBGPRINTF("pollFileReal enter, edge %p\n", act->edge);
763e28
@@ -1432,15 +1436,18 @@ pollFileReal(act_obj_t *act, cstr_t **pCStr)
763e28
 		CHKiRet(openFile(act)); /* open file */
763e28
 	}
763e28
 
763e28
+	start_preg = (inst->startRegex == NULL) ? NULL : &inst->start_preg;
763e28
+	end_preg = (inst->endRegex == NULL) ? NULL : &inst->end_preg;
763e28
+
763e28
 	/* loop below will be exited when strmReadLine() returns EOF */
763e28
 	while(glbl.GetGlobalInputTermState() == 0) {
763e28
 		if(inst->maxLinesAtOnce != 0 && nProcessed >= inst->maxLinesAtOnce)
763e28
 			break;
763e28
-		if(inst->startRegex == NULL) {
763e28
+		if((start_preg == NULL) && (end_preg == NULL)) {
763e28
 			CHKiRet(strm.ReadLine(act->pStrm, pCStr, inst->readMode, inst->escapeLF,
763e28
 				inst->trimLineOverBytes, &strtOffs));
763e28
 		} else {
763e28
-			CHKiRet(strmReadMultiLine(act->pStrm, pCStr, &inst->end_preg,
763e28
+			CHKiRet(strmReadMultiLine(act->pStrm, pCStr, start_preg, end_preg,
763e28
 				inst->escapeLF, inst->discardTruncatedMsg, inst->msgDiscardingError, &strtOffs));
763e28
 		}
763e28
 		++nProcessed;
763e28
@@ -1506,6 +1513,7 @@ createInstance(instanceConf_t **const pinst)
763e28
 	inst->iPersistStateInterval = 0;
763e28
 	inst->readMode = 0;
763e28
 	inst->startRegex = NULL;
763e28
+	inst->endRegex = NULL;
763e28
 	inst->discardTruncatedMsg = 0;
763e28
 	inst->msgDiscardingError = 1;
763e28
 	inst->bRMStateOnDel = 1;
763e28
@@ -1713,6 +1721,8 @@ CODESTARTnewInpInst
763e28
 			inst->readMode = (sbool) pvals[i].val.d.n;
763e28
 		} else if(!strcmp(inppblk.descr[i].name, "startmsg.regex")) {
763e28
 			inst->startRegex = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
763e28
+		} else if(!strcmp(inppblk.descr[i].name, "endmsg.regex")) {
763e28
+			inst->endRegex = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
763e28
 		} else if(!strcmp(inppblk.descr[i].name, "discardtruncatedmsg")) {
763e28
 			inst->discardTruncatedMsg = (sbool) pvals[i].val.d.n;
763e28
 		} else if(!strcmp(inppblk.descr[i].name, "msgdiscardingerror")) {
763e28
@@ -1753,19 +1763,31 @@ CODESTARTnewInpInst
763e28
 			  "param '%s'\n", inppblk.descr[i].name);
763e28
 		}
763e28
 	}
763e28
-	if(inst->readMode != 0 &&  inst->startRegex != NULL) {
763e28
+	i = (inst->readMode > 0) ? 1 : 0;
763e28
+	i = (NULL != inst->startRegex) ? (i+1) : i;
763e28
+	i = (NULL != inst->endRegex) ? (i+1) : i;
763e28
+	if(i > 1) {
763e28
 		LogError(0, RS_RET_PARAM_NOT_PERMITTED,
763e28
-			"readMode and startmsg.regex cannot be set "
763e28
-			"at the same time --- remove one of them");
763e28
+			"only one of readMode or startmsg.regex or endmsg.regex can be set "
763e28
+			"at the same time");
763e28
 			ABORT_FINALIZE(RS_RET_PARAM_NOT_PERMITTED);
763e28
 	}
763e28
 
763e28
 	if(inst->startRegex != NULL) {
763e28
-		const int errcode = regcomp(&inst->end_preg, (char*)inst->startRegex, REG_EXTENDED);
763e28
+		const int errcode = regcomp(&inst->start_preg, (char*)inst->startRegex, REG_EXTENDED);
763e28
+		if(errcode != 0) {
763e28
+			char errbuff[512];
763e28
+			regerror(errcode, &inst->start_preg, errbuff, sizeof(errbuff));
763e28
+			parser_errmsg("imfile: error in startmsg.regex expansion: %s", errbuff);
763e28
+			ABORT_FINALIZE(RS_RET_ERR);
763e28
+		}
763e28
+	}
763e28
+	if(inst->endRegex != NULL) {
763e28
+		const int errcode = regcomp(&inst->end_preg, (char*)inst->endRegex, REG_EXTENDED);
763e28
 		if(errcode != 0) {
763e28
 			char errbuff[512];
763e28
 			regerror(errcode, &inst->end_preg, errbuff, sizeof(errbuff));
763e28
-			parser_errmsg("imfile: error in regex expansion: %s", errbuff);
763e28
+			parser_errmsg("imfile: error in endmsg.regex expansion: %s", errbuff);
763e28
 			ABORT_FINALIZE(RS_RET_ERR);
763e28
 		}
763e28
 	}
763e28
@@ -1970,9 +1992,13 @@ CODESTARTfreeCnf
763e28
 		free(inst->pszStateFile);
763e28
 		free(inst->pszFileName_forOldStateFile);
763e28
 		if(inst->startRegex != NULL) {
763e28
-			regfree(&inst->end_preg);
763e28
+			regfree(&inst->start_preg);
763e28
 			free(inst->startRegex);
763e28
 		}
763e28
+		if(inst->endRegex != NULL) {
763e28
+			regfree(&inst->end_preg);
763e28
+			free(inst->endRegex);
763e28
+		}
763e28
 		del = inst;
763e28
 		inst = inst->next;
763e28
 		free(del);
763e28
diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c
763e28
index 9b6be0f40..a94b97f41 100644
763e28
--- a/plugins/imptcp/imptcp.c
763e28
+++ b/plugins/imptcp/imptcp.c
763e28
@@ -162,7 +162,7 @@ struct instanceConf_s {
763e28
 	int ratelimitInterval;
763e28
 	int ratelimitBurst;
763e28
 	uchar *startRegex;
763e28
-	regex_t end_preg;	/* compiled version of startRegex */
763e28
+	regex_t start_preg;	/* compiled version of startRegex */
763e28
 	struct instanceConf_s *next;
763e28
 };
763e28
 
763e28
@@ -961,7 +961,7 @@ processDataRcvd_regexFraming(ptcpsess_t *const __restrict__ pThis,
763e28
 	if(c == '\n') {
763e28
 		pThis->iCurrLine = pThis->iMsg;
763e28
 	} else {
763e28
-		const int isMatch = !regexec(&inst->end_preg, (char*)pThis->pMsg+pThis->iCurrLine, 0, NULL, 0);
763e28
+		const int isMatch = !regexec(&inst->start_preg, (char*)pThis->pMsg+pThis->iCurrLine, 0, NULL, 0);
763e28
 		if(isMatch) {
763e28
 			DBGPRINTF("regex match (%d), framing line: %s\n", pThis->iCurrLine, pThis->pMsg);
763e28
 			strcpy((char*)pThis->pMsg_save, (char*) pThis->pMsg+pThis->iCurrLine);
763e28
@@ -2188,10 +2188,10 @@ CODESTARTnewInpInst
763e28
 	}
763e28
 
763e28
 	if(inst->startRegex != NULL) {
763e28
-		const int errcode = regcomp(&inst->end_preg, (char*)inst->startRegex, REG_EXTENDED);
763e28
+		const int errcode = regcomp(&inst->start_preg, (char*)inst->startRegex, REG_EXTENDED);
763e28
 		if(errcode != 0) {
763e28
 			char errbuff[512];
763e28
-			regerror(errcode, &inst->end_preg, errbuff, sizeof(errbuff));
763e28
+			regerror(errcode, &inst->start_preg, errbuff, sizeof(errbuff));
763e28
 			parser_errmsg("imptcp: error in framing.delimiter.regex expansion: %s", errbuff);
763e28
 			ABORT_FINALIZE(RS_RET_ERR);
763e28
 		}
763e28
@@ -2348,7 +2348,7 @@ CODESTARTfreeCnf
763e28
 		free(inst->pszInputName);
763e28
 		free(inst->dfltTZ);
763e28
 		if(inst->startRegex != NULL) {
763e28
-			regfree(&inst->end_preg);
763e28
+			regfree(&inst->start_preg);
763e28
 			free(inst->startRegex);
763e28
 		}
763e28
 		del = inst;
763e28
diff --git a/runtime/stream.c b/runtime/stream.c
763e28
index 6b7e7028e..0f4197103 100644
763e28
--- a/runtime/stream.c
763e28
+++ b/runtime/stream.c
763e28
@@ -942,12 +942,12 @@ strmReadMultiLine_isTimedOut(const strm_t *const __restrict__ pThis)
763e28
 
763e28
 /* read a multi-line message from a strm file.
763e28
  * The multi-line message is terminated based on the user-provided
763e28
- * startRegex (Posix ERE). For performance reasons, the regex
763e28
+ * startRegex or endRegex (Posix ERE). For performance reasons, the regex
763e28
  * must already have been compiled by the user.
763e28
  * added 2015-05-12 rgerhards
763e28
  */
763e28
 rsRetVal
763e28
-strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEscapeLF,
763e28
+strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *start_preg, regex_t *end_preg, const sbool bEscapeLF,
763e28
 	const sbool discardTruncatedMsg, const sbool msgDiscardingError, int64 *const strtOffs)
763e28
 {
763e28
 	uchar c;
763e28
@@ -979,9 +979,14 @@ strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEs
763e28
 		cstrFinalize(thisLine);
763e28
 
763e28
 		/* we have a line, now let's assemble the message */
763e28
-		const int isMatch = !regexec(preg, (char*)rsCStrGetSzStrNoNULL(thisLine), 0, NULL, 0);
763e28
-
763e28
-		if(isMatch) {
763e28
+		const int isStartMatch = start_preg ?
763e28
+				!regexec(start_preg, (char*)rsCStrGetSzStrNoNULL(thisLine), 0, NULL, 0) :
763e28
+				0;
763e28
+		const int isEndMatch = end_preg ?
763e28
+				!regexec(end_preg, (char*)rsCStrGetSzStrNoNULL(thisLine), 0, NULL, 0) :
763e28
+				0;
763e28
+
763e28
+		if(isStartMatch) {
763e28
 			/* in this case, the *previous* message is complete and we are
763e28
 			 * at the start of a new one.
763e28
 			 */
763e28
@@ -1047,6 +1052,19 @@ strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEs
763e28
 				}
763e28
 			}
763e28
 		}
763e28
+		if(isEndMatch) {
763e28
+			/* in this case, the *current* message is complete and we are
763e28
+			 * at the end of it.
763e28
+			 */
763e28
+			if(pThis->ignoringMsg == 0) {
763e28
+				if(pThis->prevMsgSegment != NULL) {
763e28
+					finished = 1;
763e28
+					*ppCStr = pThis->prevMsgSegment;
763e28
+					pThis->prevMsgSegment= NULL;
763e28
+				}
763e28
+			}
763e28
+			pThis->ignoringMsg = 0;
763e28
+		}
763e28
 		cstrDestruct(&thisLine);
763e28
 	} while(finished == 0);
763e28
 
763e28
diff --git a/runtime/stream.h b/runtime/stream.h
763e28
index 71596879e..7dc597ff5 100644
763e28
--- a/runtime/stream.h
763e28
+++ b/runtime/stream.h
763e28
@@ -225,7 +225,7 @@ ENDinterface(strm)
763e28
 /* prototypes */
763e28
 PROTOTYPEObjClassInit(strm);
763e28
 rsRetVal strmMultiFileSeek(strm_t *pThis, unsigned int fileNum, off64_t offs, off64_t *bytesDel);
763e28
-rsRetVal strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg,
763e28
+rsRetVal strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *start_preg, regex_t *end_preg,
763e28
 	sbool bEscapeLF, sbool discardTruncatedMsg, sbool msgDiscardingError, int64 *const strtOffs);
763e28
 int strmReadMultiLine_isTimedOut(const strm_t *const __restrict__ pThis);
763e28
 void strmDebugOutBuf(const strm_t *const pThis);