diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | build/rhel/rsyslog/rsyslog.spec | 15 | ||||
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | doc/imrelp.html | 14 | ||||
-rw-r--r-- | doc/manual.html | 2 | ||||
-rw-r--r-- | doc/mmcount.html | 58 | ||||
-rw-r--r-- | doc/rsyslog_conf_modules.html | 1 | ||||
-rwxr-xr-x | plugins/imjournal/imjournal.c | 9 | ||||
-rw-r--r-- | plugins/imrelp/imrelp.c | 61 | ||||
-rw-r--r-- | plugins/imuxsock/imuxsock.c | 4 | ||||
-rw-r--r-- | plugins/imzmq3/imzmq3.c | 70 | ||||
-rw-r--r-- | plugins/mmcount/Makefile.am | 8 | ||||
-rw-r--r-- | plugins/mmcount/mmcount.c | 342 | ||||
-rw-r--r-- | runtime/ratelimit.c | 4 |
15 files changed, 592 insertions, 31 deletions
@@ -1,11 +1,21 @@ --------------------------------------------------------------------------- -Version 7.5.0 [devel] 2013-0?-?? +Version 7.5.0 [devel] 2013-06-11 +- imrelp: implement "ruleset" module parameter - imrelp/omrelp: add TLS & compression (zip) support - omrelp: add "rebindInterval" parameter - add -S command line option to specify IP address to use for RELP client connections Thanks to Axel Rau for the patch. --------------------------------------------------------------------------- +Version 7.4.1 [v7.4-stable] 2013-06-?? +- bugfix: potential loop in rate limiting + if the message that tells about rate-limiting gets rate-limited itself, + it will potentially create and endless loop +- bugfix: potential segfault in imjournal if journal DB is corrupted +- bugfix imzmq3: potential segfault on startup + if no problem happend at startup, everything went fine + Thanks to Hongfei Cheng and Brian Knox for the patch +--------------------------------------------------------------------------- Version 7.4.0 [v7.4-stable] 2013-06-06 This starts a new stable branch based on 7.3.15 plus the following changes: - add --enable-cached-man-pages ./configure option diff --git a/Makefile.am b/Makefile.am index ef604782..f604c1cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -241,6 +241,10 @@ if ENABLE_MMANON SUBDIRS += plugins/mmanon endif +if ENABLE_MMCOUNT +SUBDIRS += plugins/mmcount +endif + if ENABLE_MMFIELDS SUBDIRS += plugins/mmfields endif @@ -293,5 +297,5 @@ DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) # temporarily disable these checks for make distcheck 2012-09-06 rgerhards # --enable-extended-tests \ -# --enable-pgsql \ +# --enable-pgsql ACLOCAL_AMFLAGS = -I m4 diff --git a/build/rhel/rsyslog/rsyslog.spec b/build/rhel/rsyslog/rsyslog.spec index 4aa91df3..7bb367d4 100644 --- a/build/rhel/rsyslog/rsyslog.spec +++ b/build/rhel/rsyslog/rsyslog.spec @@ -47,6 +47,11 @@ Summary: ElasticSearch output module for rsyslog Group: System Environment/Daemons Requires: %name = %version-%release +%package mmcount +Summary: Message counting support for rsyslog +Group: System Environment/Daemons +Requires: %name = %version-%release + %package mmjsonparse Summary: JSON enhanced logging support Group: System Environment/Daemons @@ -154,6 +159,11 @@ relay chains. This module provides the capability for rsyslog to feed logs directly into Elasticsearch. +%description mmcount +This module provides the capability to count log messages by severity +or json property of given app-name. The count value is added into the +log message in json property named 'mmcount' + %description mmjsonparse This module provides the capability to recognize and parse JSON enhanced syslog messages. @@ -226,6 +236,7 @@ export PKG_CONFIG=/usr/bin/pkg-config %configure --disable-static \ --disable-testbench \ --enable-elasticsearch \ + --enable-mmcount \ --enable-mmjsonparse \ --enable-mmnormalize \ --enable-imzmq3 \ @@ -339,6 +350,10 @@ fi %defattr(-,root,root) %{_libdir}/rsyslog/omelasticsearch.so +%files mmcount +%defattr(-,root,root) +%{_libdir}/rsyslog/mmcount.so + %files mmjsonparse %defattr(-,root,root) %{_libdir}/rsyslog/mmjsonparse.so diff --git a/configure.ac b/configure.ac index 1d4964c3..53900b61 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[7.4.0],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[7.5.0],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -962,6 +962,19 @@ AC_ARG_ENABLE(mmanon, AM_CONDITIONAL(ENABLE_MMANON, test x$enable_mmanon = xyes) +# mmcount +AC_ARG_ENABLE(mmcount, + [AS_HELP_STRING([--enable-mmcount],[Enable message counting @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_xmpp="yes" ;; + no) enable_xmpp="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-mmcount) ;; + esac], + [enable_mmcount=no] +) +AM_CONDITIONAL(ENABLE_MMCOUNT, test x$enable_mmcount = xyes) + + # mmfields AC_ARG_ENABLE(mmfields, [AS_HELP_STRING([--enable-mmfields],[Enable building mmfields support @<:@default=no@:>@])], @@ -1491,6 +1504,7 @@ AC_CONFIG_FILES([Makefile \ plugins/mmjsonparse/Makefile \ plugins/mmaudit/Makefile \ plugins/mmanon/Makefile \ + plugins/mmcount/Makefile \ plugins/mmfields/Makefile \ plugins/omelasticsearch/Makefile \ plugins/sm_cust_bindcdr/Makefile \ @@ -1515,6 +1529,7 @@ echo " uuid support enabled: $enable_uuid" echo " Log file signing support: $enable_guardtime" echo " Log file encryption support: $enable_libgcrypt" echo " anonymization support enabled: $enable_mmanon" +echo " message counting support enabled: $enable_mmcount" echo " mmfields enabled: $enable_mmfields" echo echo "---{ input plugins }---" diff --git a/doc/imrelp.html b/doc/imrelp.html index 1fd913f9..11894668 100644 --- a/doc/imrelp.html +++ b/doc/imrelp.html @@ -28,10 +28,13 @@ nits outlined above, is a much more reliable solution than plain tcp syslog and so it is highly suggested to use RELP instead of plain tcp. Clients send messages to the RELP server via omrelp.</p> +<p><b>Module Parameters</b>:</p> +<ul> + <li><b>Ruleset</b> <name></br> + Binds the specified ruleset to <b>all</b> RELP listeners. +</ul> <p><b>Input Parameters</b>:</p> <ul> -<li><b>Ruleset</b> <name></br> -Binds the specified ruleset to all RELP listeners. <li><b>Port</b> <port><br> Starts a RELP server on selected port</li> <li><b>tls</b> (not mandatory, values "on","off", default "off")<br> @@ -59,7 +62,7 @@ not specific ones. This is due to a currently existing limitation in librelp. <p><b>Sample:</b></p> <p>This sets up a RELP server on port 20514.<br> </p> -<textarea rows="15" cols="60">module(load="imrelp") # needs to be done just once +<textarea rows="5" cols="60">module(load="imrelp") # needs to be done just once input(type="imrelp" port="20514") </textarea> @@ -72,7 +75,6 @@ equivalent to: Port</li> </ul> <b>Caveats/Known Bugs:</b> <ul> -<li>see description</li> <li>To obtain the remote system's IP address, you need to have at least librelp 1.0.0 installed. Versions below it return the hostname instead of the IP address.</li> @@ -82,14 +84,14 @@ not specific ones. This is due to a currently existing limitation in librelp. <p><b>Sample:</b></p> <p>This sets up a RELP server on port 20514.<br> </p> -<textarea rows="15" cols="60">$ModLoad imrelp # needs to be done just once +<textarea rows="5" cols="60">$ModLoad imrelp # needs to be done just once $InputRELPServerRun 20514 </textarea> <p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>] [<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p> <p><font size="2">This documentation is part of the <a href="http://www.rsyslog.com/">rsyslog</a> project.<br> -Copyright © 2008-2011 by <a href="http://www.gerhards.net/rainer">Rainer +Copyright © 2008-2013 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and <a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL version 3 or higher.</font></p> diff --git a/doc/manual.html b/doc/manual.html index dea0b82d..8cb519a5 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ professional services</a> available directly from the source!</p> <p><b>Please visit the <a href="http://www.rsyslog.com/sponsors">rsyslog sponsor's page</a> to honor the project sponsors or become one yourself!</b> We are very grateful for any help towards the project goals.</p> -<p><b>This documentation is for version 7.4.0 (v7.4-stable branch) of rsyslog.</b> +<p><b>This documentation is for version 7.5.0 (devel branch) of rsyslog.</b> Visit the <i><a href="http://www.rsyslog.com/status">rsyslog status page</a></i></b> to obtain current version information and project status. </p><p><b>If you like rsyslog, you might diff --git a/doc/mmcount.html b/doc/mmcount.html new file mode 100644 index 00000000..1d06340d --- /dev/null +++ b/doc/mmcount.html @@ -0,0 +1,58 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html><head> +<meta http-equiv="Content-Language" content="en"> +<title>mmcount</title></head> + +<body> +<a href="rsyslog_conf_modules.html">back</a> + +<h1>mmcount</h1> +<p><b>Module Name: mmcount</b></p> +<p><b>Author: </b>Bala.FA <barumuga@redhat.com></p> +<p><b>Status: </b>Non project-supported module - contact author +or rsyslog mailing list for questions +<p><b>Available since</b>: 7.5.0</p> +<p><b>Description</b>:</p> +<p> +<pre> + mmcount: message modification plugin which counts messages + + This module provides the capability to count log messages by severity + or json property of given app-name. The count value is added into the + log message as json property named 'mmcount' + + Example usage of the module in the configuration file + + module(load="mmcount") + + # count each severity of appname gluster + action(type="mmcount" appname="gluster") + + # count each value of gf_code of appname gluster + action(type="mmcount" appname="glusterd" key="!gf_code") + + # count value 9999 of gf_code of appname gluster + action(type="mmcount" appname="glusterfsd" key="!gf_code" value="9999") + + # send email for every 50th mmcount + if $app-name == 'glusterfsd' and $!mmcount <> 0 and $!mmcount % 50 == 0 then { + $ActionMailSMTPServer smtp.example.com + $ActionMailFrom rsyslog@example.com + $ActionMailTo glusteradmin@example.com + $template mailSubject,"50th message of gf_code=9999 on %hostname%" + $template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'" + $ActionMailSubject mailSubject + $ActionExecOnlyOnceEveryInterval 30 + :ommail:;RSYSLOG_SyslogProtocol23Format + } +</pre> + +<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>] [<a href="manual.html">manual +index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p> +<p><font size="2">This documentation is part of the +<a href="http://www.rsyslog.com/">rsyslog</a> project.<br> +Copyright © 2008-2013 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and +<a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL +version 3 or higher.</font></p> + +</body></html> diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html index 18d6b8a1..c8c1c5d7 100644 --- a/doc/rsyslog_conf_modules.html +++ b/doc/rsyslog_conf_modules.html @@ -111,6 +111,7 @@ probably an excellent starting base for writing a new module. Currently, the fol modules exist inside the source tree: <ul> <li><a href="mmanon.html">mmanon</a> - used to anonymize log messages. +<li><a href="mmcount.html">mmcount</a> - message modification plugin which counts messages <li><a href="mmnormalize.html">mmnormalize</a> - used to normalize log messages. Note that this actually is a <b>generic</b> module. <li><a href="mmjsonparse.html">mmjsonparse</a> - used to interpret CEE/lumberjack diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c index ae29154d..cce45b9c 100755 --- a/plugins/imjournal/imjournal.c +++ b/plugins/imjournal/imjournal.c @@ -244,7 +244,14 @@ readjournal() { SD_JOURNAL_FOREACH_DATA(j, get, l) { /* locate equal sign, this is always present */ equal_sign = memchr(get, '=', l); - assert (equal_sign != NULL); + + /* ... but we know better than to trust the specs */ + if (equal_sign == NULL) { + errmsg.LogError(0, RS_RET_ERR,"SD_JOURNAL_FOREACH_DATA()" + " returned a malformed field (has no '='): '%s'", + get); + continue; /* skip the entry */ + } /* get length of journal data prefix */ prefixlen = ((char *)equal_sign - (char *)get); diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 5994faca..7fa98617 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -4,7 +4,7 @@ * * File begun on 2008-03-13 by RGerhards * - * Copyright 2008-2012 Adiscon GmbH. + * Copyright 2008-2013 Adiscon GmbH. * * This file is part of rsyslog. * @@ -90,6 +90,16 @@ struct modConfData_s { static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "ruleset", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* input instance parameters */ static struct cnfparamdescr inppdescr[] = { { "port", eCmdHdlrString, CNFPARAM_REQUIRED }, @@ -283,19 +293,58 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + pModConf->pszBindRuleset = NULL; + pModConf->pBindRuleset = NULL; /* init legacy config variables */ cs.pszBindRuleset = NULL; ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imrelp:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "ruleset")) { + loadModConf->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("imrelp: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + BEGINendCnfLoad CODESTARTendCnfLoad - if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { - loadModConf->pszBindRuleset = NULL; + if(loadModConf->pszBindRuleset == NULL) { + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + loadModConf->pszBindRuleset = NULL; + } else { + CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + } } else { - CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + if((cs.pszBindRuleset != NULL) && (cs.pszBindRuleset[0] != '\0')) { + errmsg.LogError(0, RS_RET_DUP_PARAM, "imrelp: warning: ruleset " + "set via legacy directive ignored"); + } } - loadModConf->pBindRuleset = NULL; finalize_it: free(cs.pszBindRuleset); loadModConf = NULL; /* done loading */ @@ -312,6 +361,7 @@ CODESTARTcheckCnf if(pModConf->pszBindRuleset == NULL) { pModConf->pBindRuleset = NULL; } else { + DBGPRINTF("imrelp: using ruleset '%s'\n", pModConf->pszBindRuleset); localRet = ruleset.GetRuleset(pModConf->pConf, &pRuleset, pModConf->pszBindRuleset); if(localRet == RS_RET_NOT_FOUND) { std_checkRuleset_genErrMsg(pModConf, NULL); @@ -439,6 +489,7 @@ CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index c503852c..dad09ab4 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -1284,6 +1284,8 @@ BEGINactivateCnfPrePrivDrop instanceConf_t *inst; CODESTARTactivateCnfPrePrivDrop runModConf = pModConf; + if(runModConf->bOmitLocalLogging && nfd == 1) + ABORT_FINALIZE(RS_RET_OK); for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { addListner(inst); } @@ -1325,6 +1327,8 @@ BEGINrunInput #endif CODESTARTrunInput + if(runModConf->bOmitLocalLogging && nfd == 1) + ABORT_FINALIZE(RS_RET_OK); /* this is an endless loop - it is terminated when the thread is * signalled to do so. This, however, is handled by the framework, * right into the sleep below. diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c index 52ca5ebe..08b1dbe4 100644 --- a/plugins/imzmq3/imzmq3.c +++ b/plugins/imzmq3/imzmq3.c @@ -135,7 +135,6 @@ struct lstn_s { /* ---------------------------------------------------------------------------- * Static definitions/initializations. */ -static modConfData_t* loadModConf = NULL; static modConfData_t* runModConf = NULL; static struct lstn_s* lcnfRoot = NULL; static struct lstn_s* lcnfLast = NULL; @@ -268,7 +267,7 @@ static void setDefaults(instanceConf_t* info) { info->reconnectIVLMax = -1; info->ipv4Only = -1; info->affinity = -1; - + info->next = NULL; }; /* given a comma separated list of subscriptions, create a char* array of them @@ -442,11 +441,11 @@ static rsRetVal createInstance(instanceConf_t** pinst) { setDefaults(inst); /* add this to the config */ - if(loadModConf->tail == NULL) { - loadModConf->tail = loadModConf->root = inst; + if (runModConf->root == NULL || runModConf->tail == NULL) { + runModConf->tail = runModConf->root = inst; } else { - loadModConf->tail->next = inst; - loadModConf->tail = inst; + runModConf->tail->next = inst; + runModConf->tail = inst; } *pinst = inst; finalize_it: @@ -696,10 +695,14 @@ ENDisCompatibleWithFeature BEGINbeginCnfLoad CODESTARTbeginCnfLoad - loadModConf = pModConf; - pModConf->pConf = pConf; + /* After endCnfLoad() (BEGINendCnfLoad...ENDendCnfLoad) is called, + * the pModConf pointer must not be used to change the in-memory + * config object. It's safe to use the same pointer for accessing + * the config object until freeCnf() (BEGINfreeCnf...ENDfreeCnf). */ + runModConf = pModConf; + runModConf->pConf = pConf; /* init module config */ - loadModConf->io_threads = 0; /* 0 means don't set it */ + runModConf->io_threads = 0; /* 0 means don't set it */ ENDbeginCnfLoad @@ -718,7 +721,7 @@ CODESTARTsetModCnf if (!pvals[i].bUsed) continue; if (!strcmp(modpblk.descr[i].name, "ioThreads")) { - loadModConf->io_threads = (int)pvals[i].val.d.n; + runModConf->io_threads = (int)pvals[i].val.d.n; } else { errmsg.LogError(0, RS_RET_INVALID_PARAMS, "imzmq3: config error, unknown " @@ -735,7 +738,14 @@ ENDsetModCnf BEGINendCnfLoad CODESTARTendCnfLoad - loadModConf = NULL; /* done loading, so it becomes NULL */ + /* Last chance to make changes to the in-memory config object for this + * input module. After this call, the config object must no longer be + * changed. */ + if (pModConf != runModConf) { + errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has " + "changed - pModConf=%p, runModConf=%p", pModConf, runModConf); + } + assert(pModConf == runModConf); ENDendCnfLoad @@ -764,7 +774,12 @@ ENDcheckCnf BEGINactivateCnfPrePrivDrop CODESTARTactivateCnfPrePrivDrop - runModConf = pModConf; + if (pModConf != runModConf) { + errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has " + "changed - pModConf=%p, runModConf=%p", pModConf, runModConf); + } + assert(pModConf == runModConf); + /* first create the context */ createContext(); @@ -775,12 +790,41 @@ ENDactivateCnfPrePrivDrop BEGINactivateCnf CODESTARTactivateCnf + if (pModConf != runModConf) { + errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has " + "changed - pModConf=%p, runModConf=%p", pModConf, runModConf); + } + assert(pModConf == runModConf); ENDactivateCnf -/*TODO: Fill this in! */ BEGINfreeCnf + struct lstn_s *lstn, *lstn_r; + instanceConf_t *inst, *inst_r; + sublist *sub, *sub_r; CODESTARTfreeCnf + DBGPRINTF("imzmq3: BEGINfreeCnf ...\n"); + if (pModConf != runModConf) { + errmsg.LogError(0, NO_ERRCODE, "imzmq3: pointer of in-memory config object has " + "changed - pModConf=%p, runModConf=%p", pModConf, runModConf); + } + for (lstn = lcnfRoot; lstn != NULL; ) { + lstn_r = lstn; + lstn = lstn_r->next; + free(lstn_r); + } + for (inst = pModConf->root ; inst != NULL ; ) { + for (sub = inst->subscriptions; sub != NULL; ) { + free(sub->subscribe); + sub_r = sub; + sub = sub_r->next; + free(sub_r); + } + free(inst->pszBindRuleset); + inst_r = inst; + inst = inst->next; + free(inst_r); + } ENDfreeCnf diff --git a/plugins/mmcount/Makefile.am b/plugins/mmcount/Makefile.am new file mode 100644 index 00000000..9c8c99db --- /dev/null +++ b/plugins/mmcount/Makefile.am @@ -0,0 +1,8 @@ +pkglib_LTLIBRARIES = mmcount.la + +mmcount_la_SOURCES = mmcount.c +mmcount_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) +mmcount_la_LDFLAGS = -module -avoid-version +mmcount_la_LIBADD = + +EXTRA_DIST = diff --git a/plugins/mmcount/mmcount.c b/plugins/mmcount/mmcount.c new file mode 100644 index 00000000..56a4de55 --- /dev/null +++ b/plugins/mmcount/mmcount.c @@ -0,0 +1,342 @@ +/* mmcount.c + * count messages by priority or json property of given app-name. + * + * Copyright 2013 Red Hat Inc. + * + * This file is part of rsyslog. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" +#include "rsyslog.h" +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <stdint.h> +#include <json/json.h> +#include "conf.h" +#include "syslogd-types.h" +#include "srUtils.h" +#include "template.h" +#include "module-template.h" +#include "errmsg.h" +#include "hashtable.h" + +#define JSON_COUNT_NAME "!mmcount" +#define SEVERITY_COUNT 8 + +MODULE_TYPE_OUTPUT +MODULE_TYPE_NOKEEP +MODULE_CNFNAME("mmcount") + + +DEFobjCurrIf(errmsg); +DEF_OMOD_STATIC_DATA + +/* config variables */ + +typedef struct _instanceData { + char *pszAppName; + int severity[SEVERITY_COUNT]; + char *pszKey; + char *pszValue; + int valueCounter; + struct hashtable *ht; +} instanceData; + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ +}; +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */ + + +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "appname", eCmdHdlrGetWord, 0 }, + { "key", eCmdHdlrGetWord, 0 }, + { "value", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; +ENDbeginCnfLoad + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + +BEGINcreateInstance +CODESTARTcreateInstance +ENDcreateInstance + + +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature +ENDisCompatibleWithFeature + + +BEGINfreeInstance +CODESTARTfreeInstance +ENDfreeInstance + + +static inline void +setInstParamDefaults(instanceData *pData) +{ + int i; + + pData->pszAppName = NULL; + for (i = 0; i < SEVERITY_COUNT; i++) + pData->severity[i] = 0; + pData->pszKey = NULL; + pData->pszValue = NULL; + pData->valueCounter = 0; + pData->ht = NULL; +} + +static unsigned int +hash_from_key_fn(void *k) +{ + return *(unsigned int *)k; +} + +static int +key_equals_fn(void *k1, void *k2) +{ + return (*(unsigned int *)k1 == *(unsigned int *)k2); +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; +CODESTARTnewActInst + DBGPRINTF("newActInst (mmcount)\n"); + if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) { + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + CODE_STD_STRING_REQUESTnewActInst(1) + CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG)); + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "appname")) { + pData->pszAppName = es_str2cstr(pvals[i].val.d.estr, NULL); + continue; + } + if(!strcmp(actpblk.descr[i].name, "key")) { + pData->pszKey = es_str2cstr(pvals[i].val.d.estr, NULL); + continue; + } + if(!strcmp(actpblk.descr[i].name, "value")) { + pData->pszValue = es_str2cstr(pvals[i].val.d.estr, NULL); + continue; + } + dbgprintf("mmcount: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + + if(pData->pszAppName == NULL) { + dbgprintf("mmcount: action requires a appname"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(pData->pszKey != NULL && pData->pszValue == NULL) { + if(NULL == (pData->ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL))) { + DBGPRINTF("mmcount: error creating hash table!\n"); + ABORT_FINALIZE(RS_RET_ERR); + } + } +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo +ENDdbgPrintInstInfo + + +BEGINtryResume +CODESTARTtryResume +ENDtryResume + +static int * +getCounter(struct hashtable *ht, char *str) { + unsigned int key; + int *pCounter; + unsigned int *pKey; + + /* we dont store str as key, instead we store hash of the str + as key to reduce memory usage */ + key = hash_from_string(str); + pCounter = hashtable_search(ht, &key); + if(pCounter) { + return pCounter; + } + + /* counter is not found for the str, so add new entry and + return the counter */ + if(NULL == (pKey = (unsigned int*)malloc(sizeof(unsigned int)))) { + DBGPRINTF("mmcount: memory allocation for key failed\n"); + return NULL; + } + *pKey = key; + + if(NULL == (pCounter = (int*)malloc(sizeof(int)))) { + DBGPRINTF("mmcount: memory allocation for value failed\n"); + free(pKey); + return NULL; + } + *pCounter = 0; + + if(!hashtable_insert(ht, pKey, pCounter)) { + DBGPRINTF("mmcount: inserting element into hashtable failed\n"); + free(pKey); + free(pCounter); + return NULL; + } + return pCounter; +} + +BEGINdoAction + msg_t *pMsg; + char *appname; + struct json_object *json = NULL; + es_str_t *estr = NULL; + struct json_object *keyjson = NULL; + char *pszValue; + int *pCounter; +CODESTARTdoAction + pMsg = (msg_t*) ppString[0]; + appname = getAPPNAME(pMsg, LOCK_MUTEX); + + if(0 != strcmp(appname, pData->pszAppName)) { + /* we are not working for this appname. nothing to do */ + ABORT_FINALIZE(RS_RET_OK); + } + + if(!pData->pszKey) { + /* no key given for count, so we count severity */ + if(pMsg->iSeverity <= SEVERITY_COUNT) { + pData->severity[pMsg->iSeverity]++; + json = json_object_new_int(pData->severity[pMsg->iSeverity]); + } + ABORT_FINALIZE(RS_RET_OK); + } + + /* key is given, so get the property json */ + estr = es_newStrFromBuf(pData->pszKey, strlen(pData->pszKey)); + if(msgGetCEEPropJSON(pMsg, estr, &keyjson) != RS_RET_OK) { + /* key not found in the message. nothing to do */ + ABORT_FINALIZE(RS_RET_OK); + } + + /* key found, so get the value */ + pszValue = (char*)json_object_get_string(keyjson); + + if(pData->pszValue) { + /* value also given for count */ + if(!strcmp(pszValue, pData->pszValue)) { + /* count for (value and key and appname) matched */ + pData->valueCounter++; + json = json_object_new_int(pData->valueCounter); + } + ABORT_FINALIZE(RS_RET_OK); + } + + /* value is not given, so we count for each value of given key */ + pCounter = getCounter(pData->ht, pszValue); + if(pCounter) { + (*pCounter)++; + json = json_object_new_int(*pCounter); + } +finalize_it: + if(estr) { + es_deleteStr(estr); + } + + if(json) { + msgAddJSON(pMsg, (uchar *)JSON_COUNT_NAME, json); + } +ENDdoAction + + +BEGINparseSelectorAct +CODESTARTparseSelectorAct +CODE_STD_STRING_REQUESTparseSelectorAct(1) + if(strncmp((char*) p, ":mmcount:", sizeof(":mmcount:") - 1)) { + errmsg.LogError(0, RS_RET_LEGA_ACT_NOT_SUPPORTED, + "mmcount supports only v6+ config format, use: " + "action(type=\"mmcount\" ...)"); + } + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); +CODE_STD_FINALIZERparseSelectorAct +ENDparseSelectorAct + + +BEGINmodExit +CODESTARTmodExit + objRelease(errmsg, CORE_COMPONENT); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +ENDqueryEtryPt + + + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + DBGPRINTF("mmcount: module compiled with rsyslog version %s.\n", VERSION); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); +ENDmodInit diff --git a/runtime/ratelimit.c b/runtime/ratelimit.c index d83da2dd..ec248550 100644 --- a/runtime/ratelimit.c +++ b/runtime/ratelimit.c @@ -167,13 +167,13 @@ withinRatelimit(ratelimit_t *ratelimit, time_t tt) ratelimit->done++; ret = 1; } else { - if(ratelimit->missed == 0) { + ratelimit->missed++; + if(ratelimit->missed == 1) { snprintf((char*)msgbuf, sizeof(msgbuf), "%s: begin to drop messages due to rate-limiting", ratelimit->name); logmsgInternal(RS_RET_RATE_LIMITED, LOG_SYSLOG|LOG_INFO, msgbuf, 0); } - ratelimit->missed++; ret = 0; } |