diff options
author | Michael Biebl <biebl@debian.org> | 2013-06-17 17:29:30 +0200 |
---|---|---|
committer | Michael Biebl <biebl@debian.org> | 2013-06-17 17:29:30 +0200 |
commit | b4de5700d683edcb8b79e54f8cc6efffb8f480e7 (patch) | |
tree | 550a0533cf3c13c8df599e54e3f6d1c5a6a5059a | |
parent | 58550fd4d693f4c877bc0dd79b78d0c6f154b4ef (diff) | |
parent | c62e2e3b0f562a4ce54f7edcbb76400d90118717 (diff) | |
download | rsyslog-b4de5700d683edcb8b79e54f8cc6efffb8f480e7.tar.gz |
Merge tag 'upstream/7.4.1'
Upstream version 7.4.1
-rw-r--r-- | ChangeLog | 19 | ||||
-rwxr-xr-x | configure | 20 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/imjournal.html | 86 | ||||
-rw-r--r-- | doc/imrelp.html | 6 | ||||
-rw-r--r-- | doc/manual.html | 2 | ||||
-rw-r--r-- | doc/omfile.html | 8 | ||||
-rw-r--r-- | doc/omjournal.html | 3 | ||||
-rwxr-xr-x | plugins/imjournal/imjournal.c | 116 | ||||
-rw-r--r-- | plugins/imzmq3/imzmq3.c | 70 | ||||
-rw-r--r-- | rsyslog.service.in | 3 | ||||
-rw-r--r-- | runtime/ratelimit.c | 26 | ||||
-rw-r--r-- | runtime/ratelimit.h | 2 | ||||
-rw-r--r-- | tools/syslogd.c | 2 |
14 files changed, 296 insertions, 69 deletions
@@ -1,4 +1,23 @@ --------------------------------------------------------------------------- +Version 7.4.1 [v7.4-stable] 2013-06-17 +- imjournal: add ratelimiting capability + The original imjournal code did not support ratelimiting at all. We + now have our own ratelimiter. This can mitigate against journal + database corruption, when the journal re-sends old data. This is a + current bug in systemd journal, but we won't outrule this to happen + in the future again. So it is better to have a safeguard in place. + By default, we permit 20,000 messages witin 10 minutes. This may + be a bit restrictive, but given the risk potential it seems reasonable. + Users requiring larger traffic flows can always adjust the value. +- 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: prevent a segfault in imjournal if state file is not defined +- 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 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for rsyslog 7.4.0. +# Generated by GNU Autoconf 2.69 for rsyslog 7.4.1. # # Report bugs to <rsyslog@lists.adiscon.com>. # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rsyslog' PACKAGE_TARNAME='rsyslog' -PACKAGE_VERSION='7.4.0' -PACKAGE_STRING='rsyslog 7.4.0' +PACKAGE_VERSION='7.4.1' +PACKAGE_STRING='rsyslog 7.4.1' PACKAGE_BUGREPORT='rsyslog@lists.adiscon.com' PACKAGE_URL='' @@ -1612,7 +1612,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures rsyslog 7.4.0 to adapt to many kinds of systems. +\`configure' configures rsyslog 7.4.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1682,7 +1682,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rsyslog 7.4.0:";; + short | recursive ) echo "Configuration of rsyslog 7.4.1:";; esac cat <<\_ACEOF @@ -1929,7 +1929,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rsyslog configure 7.4.0 +rsyslog configure 7.4.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2509,7 +2509,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rsyslog $as_me 7.4.0, which was +It was created by rsyslog $as_me 7.4.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3333,7 +3333,7 @@ fi # Define the identity of the package. PACKAGE='rsyslog' - VERSION='7.4.0' + VERSION='7.4.1' cat >>confdefs.h <<_ACEOF @@ -20624,7 +20624,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rsyslog $as_me 7.4.0, which was +This file was extended by rsyslog $as_me 7.4.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20690,7 +20690,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -rsyslog config.status 7.4.0 +rsyslog config.status 7.4.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index ce24f53..bb0de0c 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.4.1],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/doc/imjournal.html b/doc/imjournal.html index e3f6450..28b4701 100644 --- a/doc/imjournal.html +++ b/doc/imjournal.html @@ -1,6 +1,6 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head> -<meta http-equiv="Content-Language" content="en"><title>Text File Input Monitor</title></head> +<meta http-equiv="Content-Language" content="en"><title>Systemd Journal Input Module</title></head> <body> <a href="rsyslog_conf_modules.html">back</a> @@ -11,35 +11,101 @@ <p><b>Description</b>:</p> <p>Provides the ability to import structured log messages from systemd journal to syslog.</p> +<p>Note that this module reads the journal database, what is considered a +relativly performance-intense operation. As such, the performance of a +configuration utilizing this +module may be notably slower then when using +<a href="imuxsock.html">imuxsock</a>. The journal provides imuxsock with a +copy of all "classical" syslog messages, however, it does not provide +structured data. If the latter is needed, imjournal must be used. Otherwise, +imjournal may be simply replaced by imuxsock. +<p>We suggest to check out our short presentation on +<a href="http://youtu.be/GTS7EuSdFKE">rsyslog journal integration</a> to +learn more details of anticipated use cases. + +<p><b>Warning:</b> Some versions of systemd journal have problems with database +corruption, which leads to the journal to return the same data endlessly +in a thight loop. This results in massive message duplication inside rsyslog +probably resulting in a denial-of-service when the system ressouces get +exhausted. This can be somewhat mitigated by using proper rate-limiters, but +even then there are spikes of old data which are endlessly repeated. By default, +ratelimiting is activated and permits to process 20,000 messages within 10 +seconds, what should be well enough for most use cases. If insufficient, use +the parameters described below to adjust the permitted volume. +<b>It is strongly recommended to use this plugin only if there +is hard need to do so.</b> <p><b>Configuration Directives</b>:</p> <p><b>Module Directives</b></p> <ul> -<li><span style="font-weight: bold;">PersistStateInterval -messages</span><br> +<li><b>PersistStateInterval</b> number-of-messages<br> This is a global setting. It specifies how often should the journal state be persisted. +The persists happens after each <i>number-of-messages</i>. This option is useful for rsyslog to start reding from the last journal message it read. -<li><span style="font-weight: bold;">StateFile -/path/to/file</span><br> +<li><b>StateFile</b> /path/to/file<br> This is a global setting. It specifies where the state file for persisting journal state is located. + +<li><b>ratelimit.interval</b> seconds (default: 600)<br> +Specifies the interval in seconds onto which rate-limiting is to be applied. +If more than ratelimit.burst messages are read during that interval, further +messages up to the end of the interval are discarded. The number of messages +discarded is emitted at the end of the interval (if there were any discards). +<br>Setting this to value zero turns off ratelimiting. Note that it is +<b>not recommended to turn of ratelimiting</b>, except that you know for +sure journal database entries will never be corrupted. Without ratelimiting, +a corrupted systemd journal database may cause a kind of denial of service (we +are stressing this point as multiple users have reported us such problems +with the journal database - information current as of June 2013). + +<li><b>ratelimit.burst</b> messages (default: 20000)<br> +Specifies the maximum number of messages that can be emitted within the +ratelimit.interval interval. For futher information, see description there. + +<li><b>IgnorePreviousMessages</b> [<b>off</b>/on]<br> +This option specifies whether imjournal should ignore messages currently in +journal and read only new messages. This option is only used when there is +no StateFile to avoid message loss. </ul> + <b>Caveats/Known Bugs:</b> <p> +<ul> +<li>As stated above, a corrupted systemd journal database can cause major +problems, depending on what the corruption results in. This is beyond the +control of the rsyslog team. +</ul> </p> <p><b>Sample:</b></p> <p> -The following example shows pulling structured imjournal messages and saving them into /var/log/ceelog +The following example shows pulling structured imjournal messages and saving them into /var/log/ceelog. </p> -<textarea rows="15" cols="60"> +<textarea rows="11" cols="80"> module(load="imjournal" PersistStateInterval="100" StateFile="/path/to/file") #load imjournal module module(load="mmjsonparse") #load mmjsonparse module for structured logs -$template CEETemplate,"%TIMESTAMP% %HOSTNAME% %syslogtag% @cee: %$!all-json%\n" #template for messages +template(name="CEETemplate" type="string" + string="%TIMESTAMP% %HOSTNAME% %syslogtag% @cee: %$!all-json%\n" + ) #template for messages -*.* :mmjsonparse: -*.* /var/log/ceelog;CEETemplate +action(type="mmjsonparse") +action(type="omfile" file="/var/log/ceelog" template="CEETemplate") </textarea> + +<p><b>Legacy Configuration Directives</b>:</p> +<ul> +<li><b>$imjournalPersistStateInterval</b><br> +Equivalent to: PersistStateInterval</li> +<li><b>$imjournalStateFile</b><br> +Equivalent to: StateFile</li> +<li><b>$imjournalRatelimitInterval</b><br> +Equivalent to: ratelimit.interval</li> +<li><b>$imjournalRatelimitBurst</b><br> +Equivalent to: ratelimit.burst</li> +<li><strong>$ImjournalIgnorePreviousMessages</strong><br> +Equivalent to: ignorePreviousMessages</li> +</ul> + </body> </html> diff --git a/doc/imrelp.html b/doc/imrelp.html index 9f3e487..f7fcc4b 100644 --- a/doc/imrelp.html +++ b/doc/imrelp.html @@ -30,14 +30,12 @@ Clients send messages to the RELP server via omrelp.</p> <p><b>Configuration Directives</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> </ul> <b>Caveats/Known Bugs:</b> <ul> -<li>see description</li> +<li>ruleset can only be bound via legacy configuration format</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> @@ -54,7 +52,7 @@ input(type="imrelp" port="20514") <p><b>Legacy Configuration Directives</b>:</p> <ul> <li>InputRELPServerBindRuleset <name> (available in 6.3.6+)</br> -equivalent to: RuleSet +Binds the specified ruleset to all RELP listeners. <li>InputRELPServerRun <port><br> equivalent to: Port</li> </ul> diff --git a/doc/manual.html b/doc/manual.html index dea0b82..bc57c13 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.4.1 (v7.4-stable 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/omfile.html b/doc/omfile.html index a5c3bb3..438d694 100644 --- a/doc/omfile.html +++ b/doc/omfile.html @@ -111,8 +111,12 @@ File="/var/log/messages") <p><b>Legacy Configuration Directives</b>:</p> <ul> - <li><strong>$DynaFileCacheSize </strong>(not mandatory, default will be used)<br> - Defines a template to be used for the output. <br></li><br> + <li><strong>$DynaFileCacheSize </strong>(not mandatory, default 10)<br> + defines the maximum size of the dynafile cache for <b>this</b> + action. Cache size greatly affects performance and should be + set so that it matches the actual need. Note that files + inside the cache are kept open until either rsyslogd + is HUPed or the file is evicted from the cache.<br></li><br> <li><strong>$OMFileZipLevel </strong>0..9 [default 0]<br> if greater 0, turns on gzip compression of the output file. The higher the number, the better the compression, but also the more CPU is required for zipping.<br></li><br> diff --git a/doc/omjournal.html b/doc/omjournal.html index c42d984..6124e40 100644 --- a/doc/omjournal.html +++ b/doc/omjournal.html @@ -19,6 +19,9 @@ and processed by its tools. <p>A typical use case we had on our mind is a SOHO environment, where the user wants to include syslog data obtained from the local router to be part of the journal data. +<p>We suggest to check out our short presentation on +<a href="http://youtu.be/GTS7EuSdFKE">rsyslog journal integration</a> to +learn more details of anticipated use cases. <p> </p> <p><b>Module Configuration Parameters</b>:</p> diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c index ae29154..36c7e04 100755 --- a/plugins/imjournal/imjournal.c +++ b/plugins/imjournal/imjournal.c @@ -3,7 +3,7 @@ * To test under Linux: * emmit log message into systemd journal * - * Copyright (C) 2008-2012 Adiscon GmbH + * Copyright (C) 2008-2013 Adiscon GmbH * * This file is part of rsyslog. * @@ -33,6 +33,7 @@ #include <sys/poll.h> #include <sys/socket.h> #include <errno.h> +#include <systemd/sd-journal.h> #include "dirty.h" #include "cfsysline.h" @@ -47,7 +48,7 @@ #include "errmsg.h" #include "srUtils.h" #include "unicode-helper.h" -#include <systemd/sd-journal.h> +#include "ratelimit.h" MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP @@ -64,12 +65,18 @@ DEFobjCurrIf(errmsg) static struct configSettings_s { char *stateFile; int iPersistStateInterval; + int ratelimitInterval; + int ratelimitBurst; + int bIgnorePrevious; } cs; -/* module-gloval parameters */ +/* module-global parameters */ static struct cnfparamdescr modpdescr[] = { { "statefile", eCmdHdlrGetWord, 0 }, - { "persiststateinterval", eCmdHdlrInt, 0 } + { "ratelimit.interval", eCmdHdlrInt, 0 }, + { "ratelimit.burst", eCmdHdlrInt, 0 }, + { "persiststateinterval", eCmdHdlrInt, 0 }, + { "ignorepreviousmessages", eCmdHdlrBinary, 0 } }; static struct cnfparamblk modpblk = { CNFPARAMBLK_VERSION, @@ -79,11 +86,12 @@ static struct cnfparamblk modpblk = #define DFLT_persiststateinterval 10 -static int bLegacyCnfModGlobalsPermitted = 0;/* are legacy module-global config parameters permitted? */ +static int bLegacyCnfModGlobalsPermitted = 1;/* are legacy module-global config parameters permitted? */ static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ static prop_t *pLocalHostIP = NULL; /* a pseudo-constant propterty for 127.0.0.1 */ +static ratelimit_t *ratelimiter = NULL; static sd_journal *j; /* enqueue the the journal message into the message queue. @@ -121,7 +129,7 @@ enqMsg(uchar *msg, uchar *pszTag, int iFacility, int iSeverity, struct timeval * msgAddJSON(pMsg, (uchar*)"!", json); } - CHKiRet(submitMsg2(pMsg)); + CHKiRet(ratelimitAddMsg(ratelimiter, NULL, pMsg)); finalize_it: RETiRet; @@ -244,7 +252,13 @@ 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); @@ -427,12 +441,13 @@ finalize_it: } -BEGINrunInput -CODESTARTrunInput - /* 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. - */ +/* This function loads a journal cursor from the state file. + */ +static rsRetVal +loadJournalState() +{ + DEFiRet; + if (cs.stateFile[0] != '/') { char *new_stateFile; @@ -470,8 +485,48 @@ CODESTARTrunInput errmsg.LogError(0, RS_RET_FOPEN_FAILURE, "imjournal: " "open on state file `%s' failed\n", cs.stateFile); } + } else { + /* when IgnorePrevious, seek to the end of journal */ + if (cs.bIgnorePrevious) { + if (sd_journal_seek_tail(j) < 0) { + char errStr[256]; + + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_ERR, + "sd_journal_seek_tail() failed: '%s'", errStr); + ABORT_FINALIZE(RS_RET_ERR); + } + + if (sd_journal_previous(j) < 0) { + char errStr[256]; + + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_ERR, + "sd_journal_previous() failed: '%s'", errStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } + } + +finalize_it: + RETiRet; +} + +BEGINrunInput +CODESTARTrunInput + CHKiRet(ratelimitNew(&ratelimiter, "imjournal", NULL)); + dbgprintf("imjournal: ratelimiting burst %d, interval %d\n", cs.ratelimitBurst, + cs.ratelimitInterval); + ratelimitSetLinuxLike(ratelimiter, cs.ratelimitInterval, cs.ratelimitBurst); + ratelimitSetNoTimeCache(ratelimiter); + + if (cs.stateFile) { + CHKiRet(loadJournalState()); } + /* this is an endless loop - it is terminated when the thread is + * signalled to do so. This, however, is handled by the framework. + */ while (glbl.GetGlobalInputTermState() == 0) { int count = 0, r; @@ -492,11 +547,13 @@ CODESTARTrunInput } CHKiRet(readjournal()); - /* TODO: This could use some finer metric. */ - count++; - if (count == cs.iPersistStateInterval) { - count = 0; - persistJournalState(); + if (cs.stateFile) { /* can't persist without a state file */ + /* TODO: This could use some finer metric. */ + count++; + if (count == cs.iPersistStateInterval) { + count = 0; + persistJournalState(); + } } } @@ -510,6 +567,8 @@ CODESTARTbeginCnfLoad cs.iPersistStateInterval = DFLT_persiststateinterval; cs.stateFile = NULL; + cs.ratelimitBurst = 20000; + cs.ratelimitInterval = 600; ENDbeginCnfLoad @@ -545,8 +604,11 @@ ENDwillRun /* close journal */ BEGINafterRun CODESTARTafterRun - persistJournalState(); + if (cs.stateFile) { /* can't persist without a state file */ + persistJournalState(); + } sd_journal_close(j); + ratelimitDestruct(ratelimiter); ENDafterRun @@ -589,6 +651,12 @@ CODESTARTsetModCnf cs.iPersistStateInterval = (int) pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "statefile")) { cs.stateFile = (char *)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "ratelimit.burst")) { + cs.ratelimitBurst = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "ratelimit.interval")) { + 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 { dbgprintf("imjournal: program error, non-handled " "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); @@ -632,10 +700,16 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(prop.CreateStringProp(&pInputName, UCHAR_CONSTANT("imjournal"), sizeof("imjournal") - 1)); CHKiRet(prop.CreateStringProp(&pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"persiststateinterval", 0, eCmdHdlrInt, + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalpersiststateinterval", 0, eCmdHdlrInt, NULL, &cs.iPersistStateInterval, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"statefile", 0, eCmdHdlrGetWord, + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalratelimitinterval", 0, eCmdHdlrInt, + NULL, &cs.ratelimitInterval, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalratelimitburst", 0, eCmdHdlrInt, + NULL, &cs.ratelimitBurst, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalstatefile", 0, eCmdHdlrGetWord, NULL, &cs.stateFile, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalignorepreviousmessages", 0, eCmdHdlrBinary, + NULL, &cs.bIgnorePrevious, STD_LOADABLE_MODULE_ID)); ENDmodInit diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c index 52ca5eb..08b1dbe 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/rsyslog.service.in b/rsyslog.service.in index 08a4870..8e2d64c 100644 --- a/rsyslog.service.in +++ b/rsyslog.service.in @@ -1,9 +1,10 @@ [Unit] Description=System Logging Service +Requires=syslog.socket [Service] +Type=notify ExecStart=@sbindir@/rsyslogd -n -Sockets=syslog.socket StandardOutput=null [Install] diff --git a/runtime/ratelimit.c b/runtime/ratelimit.c index d83da2d..a808e04 100644 --- a/runtime/ratelimit.c +++ b/runtime/ratelimit.c @@ -128,8 +128,8 @@ tellLostCnt(ratelimit_t *ratelimit) snprintf((char*)msgbuf, sizeof(msgbuf), "%s: %u messages lost due to rate-limiting", ratelimit->name, ratelimit->missed); - logmsgInternal(RS_RET_RATE_LIMITED, LOG_SYSLOG|LOG_INFO, msgbuf, 0); ratelimit->missed = 0; + logmsgInternal(RS_RET_RATE_LIMITED, LOG_SYSLOG|LOG_INFO, msgbuf, 0); } } @@ -150,16 +150,25 @@ withinRatelimit(ratelimit_t *ratelimit, time_t tt) goto finalize_it; } + /* we primarily need "NoTimeCache" mode for imjournal, as it + * sets the message generation time to the journal timestamp. + * As such, we do not get a proper indication of the actual + * message rate. To prevent this, we need to query local + * system time ourselvs. + */ + if(ratelimit->bNoTimeCache) + tt = time(NULL); + assert(ratelimit->burst != 0); if(ratelimit->begin == 0) ratelimit->begin = tt; - /* resume if we go out of out time window */ + /* resume if we go out of time window */ if(tt > ratelimit->begin + ratelimit->interval) { - tellLostCnt(ratelimit); ratelimit->begin = 0; ratelimit->done = 0; + tellLostCnt(ratelimit); } /* do actual limit check */ @@ -167,13 +176,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; } @@ -318,6 +327,12 @@ ratelimitSetThreadSafe(ratelimit_t *ratelimit) ratelimit->bThreadSafe = 1; pthread_mutex_init(&ratelimit->mut, NULL); } +void +ratelimitSetNoTimeCache(ratelimit_t *ratelimit) +{ + ratelimit->bNoTimeCache = 1; + pthread_mutex_init(&ratelimit->mut, NULL); +} /* Severity level determines which messages are subject to * ratelimiting. Default (no value set) is all messages. @@ -368,4 +383,3 @@ ratelimitModInit(void) finalize_it: RETiRet; } - diff --git a/runtime/ratelimit.h b/runtime/ratelimit.h index a058b06..563777f 100644 --- a/runtime/ratelimit.h +++ b/runtime/ratelimit.h @@ -35,6 +35,7 @@ struct ratelimit_s { unsigned nsupp; /**< nbr of msgs suppressed */ msg_t *pMsg; sbool bThreadSafe; /**< do we need to operate in Thread-Safe mode? */ + sbool bNoTimeCache; /**< if we shall not used cached reception time */ pthread_mutex_t mut; /**< mutex if thread-safe operation desired */ }; @@ -42,6 +43,7 @@ struct ratelimit_s { rsRetVal ratelimitNew(ratelimit_t **ppThis, char *modname, char *dynname); void ratelimitSetThreadSafe(ratelimit_t *ratelimit); void ratelimitSetLinuxLike(ratelimit_t *ratelimit, unsigned short interval, unsigned short burst); +void ratelimitSetNoTimeCache(ratelimit_t *ratelimit); void ratelimitSetSeverity(ratelimit_t *ratelimit, intTiny severity); rsRetVal ratelimitMsg(ratelimit_t *ratelimit, msg_t *pMsg, msg_t **ppRep); rsRetVal ratelimitAddMsg(ratelimit_t *ratelimit, multi_submit_t *pMultiSub, msg_t *pMsg); diff --git a/tools/syslogd.c b/tools/syslogd.c index 7a8e21c..a8a733d 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2033,6 +2033,8 @@ int realMain(int argc, char **argv) ourConf->globals.bErrMsgToStderr = 0; } + sd_notify(0, "READY=1"); + mainloop(); /* do any de-init's that need to be done AFTER this comment */ |