diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2010-12-01 17:28:36 +0100 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2010-12-01 17:28:36 +0100 |
commit | 48877c8ef41787d59a062ab07f5b6ee37eba7ce1 (patch) | |
tree | d94876c7521bdd81f0028fe7824bad228b67a5fd | |
parent | b030fe7b1f8fb26dad24ce23243f11603b5c9d4e (diff) | |
download | rsyslog-48877c8ef41787d59a062ab07f5b6ee37eba7ce1.tar.gz rsyslog-48877c8ef41787d59a062ab07f5b6ee37eba7ce1.tar.bz2 rsyslog-48877c8ef41787d59a062ab07f5b6ee37eba7ce1.zip |
milestone: added support for CEE-properties in property-based filters
-rw-r--r-- | action.c | 1 | ||||
-rw-r--r-- | doc/rsyslog_conf_filter.html | 7 | ||||
-rw-r--r-- | parse.c | 7 | ||||
-rw-r--r-- | plugins/mmnormalize/mmnormalize.c | 6 | ||||
-rw-r--r-- | runtime/conf.c | 27 | ||||
-rw-r--r-- | runtime/msg.c | 17 | ||||
-rw-r--r-- | runtime/msg.h | 3 | ||||
-rw-r--r-- | runtime/rule.c | 53 | ||||
-rw-r--r-- | runtime/rule.h | 2 | ||||
-rw-r--r-- | runtime/typedefs.h | 3 | ||||
-rw-r--r-- | template.c | 6 |
11 files changed, 99 insertions, 33 deletions
@@ -775,7 +775,6 @@ finalize_it: */ switch(pThis->eParamPassing) { case ACT_STRING_PASSING: - /* nothing to do in that case */ break; case ACT_ARRAY_PASSING: cleanupDoActionParams(pThis, actParams); /* iRet ignored! */ diff --git a/doc/rsyslog_conf_filter.html b/doc/rsyslog_conf_filter.html index 63c29817..27f4a8a6 100644 --- a/doc/rsyslog_conf_filter.html +++ b/doc/rsyslog_conf_filter.html @@ -117,6 +117,13 @@ currently supported:</p> the property. There must be an exact match, wildcards are not supported.</td> </tr> <tr> +<td>isempty</td> +<td>Checks if the property is empty. The value is discarded. This is +especially useful when working with normalized data, where some fields +may be populated based on normalization result. +Available since 6.6.2. +</tr> +<tr> <td>isequal</td> <td>Compares the "value" string provided and the property contents. These two values must be exactly equal to match. The @@ -231,7 +231,8 @@ rsRetVal parsSkipWhitespace(rsParsObj *pThis) /* Parse string up to a delimiter. * * Input: - * cDelim - the delimiter + * cDelim - the delimiter. Note that SP within a value always is a delimiter, + * so cDelim is actually an *additional* delimiter. * The following two are for whitespace stripping, * 0 means "no", 1 "yes" * - bTrimLeading @@ -256,13 +257,13 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrim pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; - while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) { + while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim && *pC != ' ') { CHKiRet(cstrAppendChar(pCStr, bConvLower ? tolower(*pC) : *pC)); ++pThis->iCurrPos; ++pC; } - if(*pC == cDelim) { + if(pThis->iCurrPos < cstrLen(pThis->pCStr)) { //BUGFIX!! ++pThis->iCurrPos; /* eat delimiter */ } diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c index d9d64687..8c4efd81 100644 --- a/plugins/mmnormalize/mmnormalize.c +++ b/plugins/mmnormalize/mmnormalize.c @@ -126,18 +126,17 @@ CODESTARTdoAction if(r != 0) { DBGPRINTF("error %d during ln_normalize\n", r); } + es_deleteStr(str); /***DEBUG***/ // TODO: remove after initial testing - 2010-12-01 { - dbgprintf("mmnormalize: event ptr now is %p\n", pMsg->event); char *cstr; - es_emptyStr(str); ee_fmtEventToJSON(pMsg->event, &str); cstr = es_str2cstr(str, NULL); dbgprintf("mmnormalize generated: %s\n", cstr); free(cstr); + es_deleteStr(str); } /***END DEBUG***/ - es_deleteStr(str); ENDdoAction @@ -192,6 +191,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) /* all config vars auto-reset! */ cs.bUseRawMsg = 0; + free(cs.sampdb); cs.sampdb = NULL; CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct diff --git a/runtime/conf.c b/runtime/conf.c index 1f0badcb..e12cf82b 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -874,6 +874,14 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) rsParsDestruct(pPars); return(iRet); } + if(f->f_filterData.prop.propID == PROP_CEE) { + /* in CEE case, we need to preserve the actual property name */ + if((f->f_filterData.prop.propName = + es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { + cstrDestruct(&pCSPropName); + return(RS_RET_ERR); + } + } cstrDestruct(&pCSPropName); /* read operation */ @@ -902,10 +910,13 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) iOffset = 0; } +dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { f->f_filterData.prop.operation = FIOP_CONTAINS; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { f->f_filterData.prop.operation = FIOP_ISEQUAL; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { + f->f_filterData.prop.operation = FIOP_ISEMPTY; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { f->f_filterData.prop.operation = FIOP_STARTSWITH; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { @@ -918,12 +929,15 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) } rsCStrDestruct(&pCSCompOp); /* no longer needed */ - /* read compare value */ - iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); +dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); + if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { + /* read compare value */ + iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } } /* skip to action part */ @@ -1065,7 +1079,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) * and, if so, we copy them over. rgerhards, 2005-10-18 */ if(pDfltProgNameCmp != NULL) { -RUNLOG_STR("dflt ProgNameCmp != NULL, setting opCSProgNameComp"); CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); } diff --git a/runtime/msg.c b/runtime/msg.c index 7299b5bf..cca9d5f6 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -530,6 +530,10 @@ uchar *propIDToName(propid_t propID) return UCHAR_CONSTANT("$MINUTE"); case PROP_SYS_MYHOSTNAME: return UCHAR_CONSTANT("$MYHOSTNAME"); + case PROP_CEE: + return UCHAR_CONSTANT("*CEE-based property*"); + case PROP_CEE_ALL_JSON: + return UCHAR_CONSTANT("$!all-json"); default: return UCHAR_CONSTANT("*invalid property id*"); } @@ -2233,7 +2237,7 @@ static uchar *getNOW(eNOWType eNow) * function here, as the context seems good enough. -- rgerhards, 2010-12-01 */ static inline void -getCEEPropVal(msg_t *pMsg, struct templateEntry *pTpe, uchar **pRes, unsigned short *pbMustBeFreed) +getCEEPropVal(msg_t *pMsg, es_str_t *propName, uchar **pRes, int *buflen, unsigned short *pbMustBeFreed) { struct ee_field *field; es_str_t *str; @@ -2243,7 +2247,7 @@ getCEEPropVal(msg_t *pMsg, struct templateEntry *pTpe, uchar **pRes, unsigned sh *pRes = NULL; if(pMsg->event == NULL) goto finalize_it; - if((field = ee_getEventField(pMsg->event, pTpe->data.field.propName)) == NULL) + if((field = ee_getEventField(pMsg->event, propName)) == NULL) goto finalize_it; /* right now, we always extract data from the first field value. A reason for this * is that as of now (2010-12-01) liblognorm never populates more than one ;) @@ -2251,6 +2255,7 @@ getCEEPropVal(msg_t *pMsg, struct templateEntry *pTpe, uchar **pRes, unsigned sh if((str = ee_getFieldValueAsStr(field, 0)) == NULL) goto finalize_it; *pRes = (unsigned char*) es_str2cstr(str, "#000"); es_deleteStr(str); + *buflen = (int) ustrlen(*pRes); *pbMustBeFreed = 1; finalize_it: @@ -2303,7 +2308,7 @@ finalize_it: *pPropLen = sizeof("**OUT OF MEMORY**") - 1; \ return(UCHAR_CONSTANT("**OUT OF MEMORY**"));} uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, - propid_t propid, size_t *pPropLen, + propid_t propid, es_str_t *propName, size_t *pPropLen, unsigned short *pbMustBeFreed) { uchar *pRes; /* result pointer */ @@ -2460,14 +2465,13 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, pRes = glbl.GetLocalHostName(); break; case PROP_CEE_ALL_JSON: - str = es_newStr(512); ee_fmtEventToJSON(pMsg->event, &str); pRes = (uchar*) es_str2cstr(str, "#000"); es_deleteStr(str); *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */ break; case PROP_CEE: - getCEEPropVal(pMsg, pTpe, &pRes, pbMustBeFreed); + getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed); break; default: /* there is no point in continuing, we may even otherwise render the @@ -2481,6 +2485,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, /* If we did not receive a template pointer, we are already done... */ if(pTpe == NULL) { + *pPropLen = (bufLen == -1) ? ustrlen(pRes) : bufLen; return pRes; } @@ -3096,7 +3101,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar) /* always call MsgGetProp() without a template specifier */ /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ propNameToID(pstrPropName, &propid); - pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, &propLen, &bMustBeFreed); + pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); /* now create a string object out of it and hand that over to the var */ CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp)); diff --git a/runtime/msg.h b/runtime/msg.h index 6a680da6..9d9df8d0 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -164,7 +164,8 @@ void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg); void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg, size_t lenMsg); rsRetVal MsgReplaceMSG(msg_t *pThis, uchar* pszMSG, int lenMSG); uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, - propid_t propid, size_t *pPropLen, unsigned short *pbMustBeFreed); + propid_t propid, es_str_t *propName, + size_t *pPropLen, unsigned short *pbMustBeFreed); char *textpri(char *pRes, size_t pResLen, int pri); rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar); rsRetVal MsgEnableThreadSafety(void); diff --git a/runtime/rule.c b/runtime/rule.c index 42773768..fc1ee17c 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -70,6 +70,12 @@ getFIOPName(unsigned iFIOP) case FIOP_REGEX: pRet = "regex"; break; + case FIOP_EREREGEX: + pRet = "ereregex"; + break; + case FIOP_ISEMPTY: + pRet = "isempty"; + break; default: pRet = "NOP"; break; @@ -190,7 +196,8 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac bRet = (pResult->val.num) ? 1 : 0; } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ - pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, &propLen, &pbMustBeFreed); + pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, + pRule->f_filterData.prop.propName, &propLen, &pbMustBeFreed); /* Now do the compares (short list currently ;)) */ switch(pRule->f_filterData.prop.operation ) { @@ -198,6 +205,10 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1) bRet = 1; break; + case FIOP_ISEMPTY: + if(propLen == 0) + bRet = 1; /* process message! */ + break; case FIOP_ISEQUAL: if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue, pszPropVal, ustrlen(pszPropVal)) == 0) @@ -230,14 +241,28 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac bRet = (bRet == 1) ? 0 : 1; if(Debug) { - dbgprintf("Filter: check for property '%s' (value '%s') ", - propIDToName(pRule->f_filterData.prop.propID), pszPropVal); + char *cstr; + if(pRule->f_filterData.prop.propID == PROP_CEE) { + cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL); + dbgprintf("Filter: check for CEE property '%s' (value '%s') ", + cstr, pszPropVal); + free(cstr); + } else { + dbgprintf("Filter: check for property '%s' (value '%s') ", + propIDToName(pRule->f_filterData.prop.propID), pszPropVal); + } if(pRule->f_filterData.prop.isNegated) dbgprintf("NOT "); - dbgprintf("%s '%s': %s\n", - getFIOPName(pRule->f_filterData.prop.operation), - rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), - bRet ? "TRUE" : "FALSE"); + if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) { + dbgprintf("%s : %s\n", + getFIOPName(pRule->f_filterData.prop.operation), + bRet ? "TRUE" : "FALSE"); + } else { + dbgprintf("%s '%s': %s\n", + getFIOPName(pRule->f_filterData.prop.operation), + rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), + bRet ? "TRUE" : "FALSE"); + } } /* cleanup */ @@ -324,6 +349,8 @@ CODESTARTobjDestruct(rule) rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue); if(pThis->f_filterData.prop.regex_cache != NULL) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); + if(pThis->f_filterData.prop.propName != NULL) + es_deleteStr(pThis->f_filterData.prop.propName); } else if(pThis->f_filter_type == FILTER_EXPR) { if(pThis->f_filterData.f_expr != NULL) expr.Destruct(&pThis->f_filterData.f_expr); @@ -368,6 +395,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction) /* debugprint for the rule object */ BEGINobjDebugPrint(rule) /* be sure to specify the object type also in END and CODESTART macros! */ int i; + char *cstr; CODESTARTobjDebugPrint(rule) dbgoprint((obj_t*) pThis, "rsyslog rule:\n"); if(pThis->pCSProgNameComp != NULL) @@ -388,12 +416,19 @@ CODESTARTobjDebugPrint(rule) } else { dbgprintf("PROPERTY-BASED Filter:\n"); dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID)); + if(pThis->f_filterData.prop.propName != NULL) { + cstr = es_str2cstr(pThis->f_filterData.prop.propName, NULL); + dbgprintf("\tCEE-Prop.: '%s'\n", cstr); + free(cstr); + } dbgprintf("\tOperation: "); if(pThis->f_filterData.prop.isNegated) dbgprintf("NOT "); dbgprintf("'%s'\n", getFIOPName(pThis->f_filterData.prop.operation)); - dbgprintf("\tValue....: '%s'\n", - rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue)); + if(pThis->f_filterData.prop.pCSCompValue != NULL) { + dbgprintf("\tValue....: '%s'\n", + rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue)); + } dbgprintf("\tAction...: "); } diff --git a/runtime/rule.h b/runtime/rule.h index 309a2ed8..3b34e11a 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -25,6 +25,7 @@ #ifndef INCLUDED_RULE_H #define INCLUDED_RULE_H +#include "libestr.h" #include "linkedlist.h" #include "regexp.h" #include "expr.h" @@ -49,6 +50,7 @@ struct rule_s { cstr_t *pCSCompValue; /* value to "compare" against */ sbool isNegated; propid_t propID; /* ID of the requested property */ + es_str_t *propName; /* name of property for CEE-based filters */ } prop; expr_t *f_expr; /* expression object */ } f_filterData; diff --git a/runtime/typedefs.h b/runtime/typedefs.h index 38bc02d5..1f624f7a 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -127,7 +127,8 @@ typedef enum { FIOP_ISEQUAL = 2, /* is (exactly) equal? */ FIOP_STARTSWITH = 3, /* starts with a string? */ FIOP_REGEX = 4, /* matches a (BRE) regular expression? */ - FIOP_EREREGEX = 5 /* matches a ERE regular expression? */ + FIOP_EREREGEX = 5, /* matches a ERE regular expression? */ + FIOP_ISEMPTY = 6 /* string empty <=> strlen(s) == 0 ?*/ } fiop_t; /* types of configuration handlers @@ -113,7 +113,8 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t * iLenVal = pTpe->data.constant.iLenConstant; bMustBeFreed = 0; } else if(pTpe->eEntryType == FIELD) { - pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &iLenVal, &bMustBeFreed); + pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, + pTpe->data.field.propName, &iLenVal, &bMustBeFreed); /* we now need to check if we should use SQL option. In this case, * we must go over the generated string and escape '\'' characters. * rgerhards, 2005-09-22: the option values below look somewhat misplaced, @@ -192,7 +193,8 @@ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr) if(pTpe->eEntryType == CONSTANT) { CHKmalloc(pArr[iArr] = (uchar*)strdup((char*) pTpe->data.constant.pConstant)); } else if(pTpe->eEntryType == FIELD) { - pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &propLen, &bMustBeFreed); + pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, + pTpe->data.field.propName, &propLen, &bMustBeFreed); if(bMustBeFreed) { /* if it must be freed, it is our own private copy... */ pArr[iArr] = pVal; /* ... so we can use it! */ } else { |