summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2009-05-11 17:38:33 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2009-05-11 17:38:33 +0200
commit8e430258fdc9b0577ea8e54dae21cc5942f90104 (patch)
treec24a069a78c960334d2d54b5bcbde7be26a08ea1
parent9823c73d1d07e50e6bec7f7c02c88d61d6955526 (diff)
downloadrsyslog-8e430258fdc9b0577ea8e54dae21cc5942f90104.tar.gz
rsyslog-8e430258fdc9b0577ea8e54dae21cc5942f90104.tar.xz
rsyslog-8e430258fdc9b0577ea8e54dae21cc5942f90104.zip
added capability to draw configuration graphs
- added $GenerateConfigGraph configuration command which can be used to generate nice-looking (and very informative) rsyslog configuration graphs. - added $ActionName configuration directive (currently only used for graph generation, but may find other uses)
-rw-r--r--ChangeLog13
-rw-r--r--action.c11
-rw-r--r--action.h1
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/rsconf1_generateconfiggraph.html121
-rw-r--r--doc/rsyslog_conf_global.html3
-rw-r--r--doc/rsyslog_confgraph_complex.conf108
-rw-r--r--doc/rsyslog_confgraph_complex.pngbin0 -> 143204 bytes
-rw-r--r--doc/rsyslog_confgraph_std.conf79
-rw-r--r--doc/rsyslog_confgraph_std.pngbin0 -> 167756 bytes
-rw-r--r--doc/troubleshoot.html9
-rw-r--r--runtime/rsyslog.h1
-rw-r--r--tools/syslogd.c194
13 files changed, 530 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index 98f59e9e..d37b8e0b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,15 +1,20 @@
---------------------------------------------------------------------------
Version 4.3.1 [DEVEL] (rgerhards), 2009-04-??
+- performance enhancemnt: imtcp calls parser no longer on input thread
+ but rather inside on of the potentially many main msg queue worker
+ threads (an enhancement scheduled for all input plugins where this is
+ possible)
+- added $GenerateConfigGraph configuration command which can be used
+ to generate nice-looking (and very informative) rsyslog configuration
+ graphs.
+- added $ActionName configuration directive (currently only used for
+ graph generation, but may find other uses)
- improved doc
* added (hopefully) easier to grasp queue explanation
- improved testbench
* added tests for queue disk-only mode (checks disk queue logic)
- bugfix: light and full delay watermarks had invalid values, badly
affecting performance for delayable inputs
-- performance enhancemnt: imtcp calls parser no longer on input thread
- but rather inside on of the potentially many main msg queue worker
- threads (an enhancement scheduled for all input plugins where this is
- possible)
---------------------------------------------------------------------------
Version 4.3.0 [DEVEL] (rgerhards), 2009-04-17
- new feature: new output plugin omprog, which permits to start program
diff --git a/action.c b/action.c
index 03073153..51620fce 100644
--- a/action.c
+++ b/action.c
@@ -60,6 +60,7 @@ static int glbliActionResumeInterval = 30;
int glbliActionResumeRetryCount = 0; /* how often should suspended actions be retried? */
static int bActionRepMsgHasMsg = 0; /* last messsage repeated... has msg fragment in it */
+static uchar *pszActionName; /* short name for the action */
/* main message queue and its configuration parameters */
static queueType_t ActionQueType = QUEUETYPE_DIRECT; /* type of the main message queue above */
static int iActionQueueSize = 1000; /* size of the main message queue above */
@@ -163,8 +164,7 @@ actionResetQueueParams(void)
glbliActionResumeRetryCount = 0; /* I guess it is smart to reset this one, too */
- if(pszActionQFName != NULL)
- d_free(pszActionQFName);
+ d_free(pszActionQFName);
pszActionQFName = NULL; /* prefix for the main message queue file */
RETiRet;
@@ -191,8 +191,8 @@ rsRetVal actionDestruct(action_t *pThis)
SYNC_OBJ_TOOL_EXIT(pThis);
pthread_mutex_destroy(&pThis->mutActExec);
- if(pThis->ppTpl != NULL)
- d_free(pThis->ppTpl);
+ d_free(pThis->pszName);
+ d_free(pThis->ppTpl);
d_free(pThis);
RETiRet;
@@ -829,6 +829,7 @@ actionAddCfSysLineHdrl(void)
{
DEFiRet;
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionname", 0, eCmdHdlrGetWord, NULL, &pszActionName, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszActionQFName, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesize", 0, eCmdHdlrInt, NULL, &iActionQueueSize, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iActionQueMaxDiskSpace, NULL));
@@ -881,6 +882,8 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques
CHKiRet(actionConstruct(&pAction)); /* create action object first */
pAction->pMod = pMod;
pAction->pModData = pModData;
+ pAction->pszName = pszActionName;
+ pszActionName = NULL; /* free again! */
pAction->bExecWhenPrevSusp = bActExecWhenPrevSusp;
pAction->iSecsExecOnceInterval = iActExecOnceInterval;
pAction->iExecEveryNthOccur = iActExecEveryNthOccur;
diff --git a/action.h b/action.h
index f2706af6..2a1487a5 100644
--- a/action.h
+++ b/action.h
@@ -72,6 +72,7 @@ struct action_s {
*/
qqueue_t *pQueue; /* action queue */
SYNC_OBJ_TOOL; /* required for mutex support */
+ uchar *pszName; /* action name (for documentation) */
pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */
};
typedef struct action_s action_t;
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 4d9d94ff..0703b8fc 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -78,6 +78,7 @@ html_files = \
rsconf1_filecreatemode.html \
rsconf1_filegroup.html \
rsconf1_fileowner.html \
+ rsconf1_generateconfiggraph.html \
rsconf1_gssforwardservicename.html \
rsconf1_gsslistenservicename.html \
rsconf1_gssmode.html \
@@ -113,6 +114,8 @@ html_files = \
src/classes.dia
grfx_files = \
+ rsyslog_confgraph_complex.png\
+ rsyslog_confgraph_std.png \
direct_queue0.png \
direct_queue1.png \
direct_queue2.png \
diff --git a/doc/rsconf1_generateconfiggraph.html b/doc/rsconf1_generateconfiggraph.html
new file mode 100644
index 00000000..0b18463a
--- /dev/null
+++ b/doc/rsconf1_generateconfiggraph.html
@@ -0,0 +1,121 @@
+<html>
+<head>
+<title>rsyslog.conf file</title>
+</head>
+<body>
+<a href="rsyslog_conf_global.html">back</a>
+
+<h2>$GenerateConfigGraph</h2>
+<p><b>Type:</b> global configuration directive</p>
+<p><b>Default:</b> </p>
+<p><b>Available Since:</b> 4.3.1</p>
+<p><b>Description:</b></p>
+<p>This directive permits to create (hopefully) good-looking visualizations of rsyslogd's
+configuration. It does not affect rsyslog operation. If the directive is specified multiple
+times, all but the last are ignored. If it is specified, a graph is created. This happens
+both during a regular startup as well a config check run. It is recommended to include
+this directive only for documentation purposes and remove it from a production
+configuraton.
+<p>The graph is not drawn by rsyslog itself. Instead, it uses the great open source tool
+<a href="http://www.graphviz.org">Graphviz</a> to do the actual drawing. This has at least
+two advantages:
+<ul>
+<li>the graph drawing support code in rsyslog is extremly slim and without overhead
+<li>the user may change or further annotate the generated file, thus potentially
+improving his documentation
+</ul>
+The drawback, of course, is that you need to run Graphviz once you have generated
+the control file with rsyslog. Fortunately, the process to do so is rather easy:
+<ol>
+<li>add &quot;$GenerateConfigGraph /path/to/file.dot&quot; to rsyslog.conf (from now on, I
+will call the file just file.dot). Optionally, add &quot;$ActionName&quot; statement
+<b>in front of</b> those actions that you like to use friendly names with. If you do
+this, keep the names short.
+<li>run rsyslog at least once (either in regular or configuration check mode)
+<li>remember to remove the $GenerateConfigGraph directive when you no longer need it (or
+comment it out)
+<li>change your working directory to where you place the dot file
+<li>if you would like to edit the rsyslog-generated file, now is the time to do so
+<li>do &quot;dot -Tpng file.dot &gt; file.png&quot;
+<li>remember that you can use &quot;convert -resize 50% file.png resized.png&quot; if
+dot's output is too large (likely) or too small. Resizing can be especially useful if
+you intend to get a rough overview over your configuration.
+</ol>
+After completing these steps, you should have a nice graph of your configuration. Details
+are missing, but that is exactly the point. At the start of the graph is always (at least
+in this version, could be improved) a node called &quot;inputs&quot; in a tripple hexagon
+shape. This represents all inputs active in the system (assuming you have defined some,
+what the current version does not check). Next comes the main queue. It is given in a
+hexagon shape. That shape indicates that a queue is peresent and used to de-couple
+the inbound from the outbound part of the graph. In technical terms, here is a
+threading boundary. Action with &quot;real&quot; queues (other than in direct mode)
+also utilize this shape. For actions, notice that a &quot;hexagon action&quot; creates
+a deep copy of the message. As such, a &quot;discard hexagon action&quot; actually does
+nothing, because it duplicates the message and then discards <b>the duplicate</b>.
+At the end of the diagram, you always see a &quot;discard&quot; action. This indicates
+that rsyslog discards messages which have been run through all available rules.
+<p>Edges are labeled with information about when they are taken. For filters, the type of
+filter, but not any specifics, are given. It is also indicated if no filter is
+applied in the configuration file (by using a &quot;*.*&quot; selector). Edges without
+labels are unconditionally taken. The actions themselfs are labeled with the name of
+the output module that handles them. If provided, the name given via
+&quot;ActionName&quot; is used instead. No further details are provided.
+<p>If there is anything in red, this should draw your attention. In this case, rsyslogd
+has detected something that does not look quite right. A typical example is a discard
+action which is followed by some other actions in an action unit. Even though something
+may be red, it can be valid - rsyslogd's graph generator does not yet check each and
+every speciality, so the configuration may just cover a very uncommon case.
+<p>Now let's look at some examples. The graph below was generated on a fairly standard
+Fedora rsyslog.conf file. It had only the usually commented-out last forwarding action
+activated:
+<p align="center">
+<img src="rsyslog_confgraph_std.png" alt="rsyslog configuration graph for a default fedora rsyslog.conf">
+<p>This is the typical structure for a simple rsyslog configuration. There are a couple of
+actions, each guarded by a filter. Messages run from top to bottom and control branches
+whenever a filter evaluates to true. As there is no discard action, all messages will
+run through all filters and discarded in the system default discard action right after
+all configured actions.
+</p>
+<p>A more complex example can be seen in the next graph. This is a configuration I
+created for testing the graph-creation features, so it contains a little bit of
+everything. However, real-world configurations can look quite complex, too (and I
+wouldn't say this one is very complex):
+<p align="center">
+<img src="rsyslog_confgraph_complex.png">
+</p>
+<p>Here, we have a user-defined discard action. You can immediately see this because
+processing branches after the first &quot;builtin-file&quot; action. Those messages
+where the filter evaluates to true for will never run through the left-hand action
+branch. However, there is also a configuration error present: there are two more
+actions (now shown red) after the discard action. As the message is discarded, these will
+never be executed. Note that the discard branch contains no further filters. This is
+because these actions are all part of the same action unit, which is guarded only by
+an entry filter. The same is present a bit further down at the node labeled
+&quot;write_system_log_2&quot;. This note has one more special feature, that is label
+was set via &quot;ActionName&quot;, thus is does not have standard form (the same
+happened to the node named &quot;Forward&quot; right at the top of the diagram.
+Inside this diagram, the &quot;Forward&quot; node is executed asynchonously on its own
+queue. All others are executed synchronously.
+<p>Configuration graphs are useful for documenting a setup, but are also a great
+<a href="troubleshoot.html">troubleshooting</a> resource. It is important to
+remember that <b>these graphs are generated
+from rsyslogd's in-memory action processing structures</b>. You can not get closer
+to understanding on how rsyslog interpreted its configuration files.
+So if the graph does not look
+what you intended to do, there is probably something worng in rsyslog.conf.
+<p>If something is not working as expected, but you do not spot the error immediately,
+I recommend to generate a graph and zoom it so that you see all of it in one great picture.
+You may not be able to read anything, but the structure should look good to you and
+so you can zoom into those areas that draw your attention.
+<p><b>Sample:</b></p>
+<p><code><b>$DirOwner /path/to/graphfile-file.dot</b></code></p>
+
+<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 &copy; 2009 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 2 or higher.</font></p>
+</body>
+</html>
diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html
index 3e33f0da..43eacc43 100644
--- a/doc/rsyslog_conf_global.html
+++ b/doc/rsyslog_conf_global.html
@@ -18,6 +18,8 @@ many parameter settings modify queue parameters. If in doubt, use the
default, it is usually well-chosen and applicable in most cases.</p>
<ul>
<li><a href="rsconf1_actionexeconlywhenpreviousissuspended.html">$ActionExecOnlyWhenPreviousIsSuspended</a></li>
+<li>$ActionName &lt;a_single_word&gt; - used primarily for documentation, e.g. when
+generating a configuration graph. Available sice 4.3.1.
<li>$ActionExecOnlyOnceEveryInterval &lt;seconds&gt; -
execute action only if the last execute is at last
&lt;seconds&gt; seconds in the past (more info in <a href="ommail.html">ommail</a>,
@@ -116,6 +118,7 @@ default 60000 (1 minute)]</li>
<li><a href="rsconf1_filecreatemode.html">$FileCreateMode</a></li>
<li><a href="rsconf1_filegroup.html">$FileGroup</a></li>
<li><a href="rsconf1_fileowner.html">$FileOwner</a></li>
+<li><a href="rsconf1_generateconfiggraph.html">$GenerateConfigGraph</a></li>
<li><a href="rsconf1_gssforwardservicename.html">$GssForwardServiceName</a></li>
<li><a href="rsconf1_gsslistenservicename.html">$GssListenServiceName</a></li>
<li><a href="rsconf1_gssmode.html">$GssMode</a></li>
diff --git a/doc/rsyslog_confgraph_complex.conf b/doc/rsyslog_confgraph_complex.conf
new file mode 100644
index 00000000..3d7ec0a3
--- /dev/null
+++ b/doc/rsyslog_confgraph_complex.conf
@@ -0,0 +1,108 @@
+$DebugPrintTemplateList off
+$DebugPrintCfSysLineHandlerList off
+$DebugPrintModuleList off
+#$ResetConfigVariables
+$ErrorMessagesToStderr off
+$ModLoad /home/rger/proj/rsyslog/plugins/imuxsock/.libs/imuxsock.so
+#$ModLoad /home/rger/proj/rsyslog/plugins/imklog/.libs/imklog
+#$ModLoad /home/rger/proj/rsyslog/plugins/imtcp/.libs/imtcp
+$ModLoad /home/rger/proj/rsyslog/plugins/imtcp/.libs/imtcp
+$ModLoad /home/rger/proj/rsyslog/plugins/imudp/.libs/imudp
+$ModLoad /home/rger/proj/rsyslog/plugins/omstdout/.libs/omstdout
+$ModLoad /home/rger/proj/rsyslog/plugins/omprog/.libs/omprog
+$ModLoad /home/rger/proj/rsyslog/plugins/omtesting/.libs/omtesting
+#$ModLoad /home/rger/proj/rsyslog/plugins/ommail/.libs/ommail
+#
+#
+# PGSQL testing
+$ModLoad /home/rger/proj/rsyslog/plugins/ompgsql/.libs/ompgsql.so
+$template pgfmt,"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%');",STDSQL
+#$ActionQueueType linkedlist
+#*.* :ompgsql:127.0.0.1,rsyslog,postgres,;pgfmt
+
+#$ActionOMStdoutArrayInterface on
+#*.* :omstdout:
+
+$ActionResumeInterval 4
+$ActionResumeRetryCount 3
+$ActionQueueType LinkedList # run asynchronously
+$ActionName Forward to 172.19.3.9
+*.* @@172.19.3.9:10514
+#*.* :omtesting:randfail
+#*.* :omtesting:always_suspend
+#*.* :omtesting:fail 2 2
+
+#$UDPServerTimeRequery 10
+$UDPServerRun 514
+$inputtcpmaxsessions 2000
+$InputTCPServerRun 12514
+
+#$PrivDropToUser rger
+#$InputTCPServerInputName tcp/514
+#$InputTCPServerAddtlFrameDelimiter 10
+#$InputTCPServerRun 514
+#$AllowedSender UDP,127.0.0.1/32
+#$AllowedSender TCP,127.0.0.1/32
+
+$PreserveFQDN off
+
+#$HUPisRestart on
+
+#$MainMsgQueueType direct
+$MainMsgQueueType linkedlist
+$MainMsgQueueDequeueBatchSize 200
+#$MainMsgQueueWorkerTimeoutThreadShutdown -1
+
+#---- test DA mode
+# set spool locations and switch queue to disk assisted mode
+$WorkDirectory spool
+$MainMsgQueueSize 200 # this *should* trigger moving on to DA mode...
+# note: we must set QueueSize sufficiently high, so that 70% (light delay mark)
+# is high enough above HighWatermark!
+$MainMsgQueueHighWatermark 80
+$MainMsgQueueLowWatermark 40
+$MainMsgQueueFilename mainq
+$MainMsgQueueType linkedlist
+# ucomment, as we now have an issue (finally the test case works ;))
+#$MainMsgQueueDequeueBatchSize 80
+#---- end test DA mode
+
+#$template test,"%timereported:::date-rfc3339%,%timereported:::date-mysql%,%timereported:::date-subseconds%, %timegenerated:::date-mysql%, %timegenerated:::date-subseconds%, msg: %msg%\n"
+#$template db,"re: '%msg:R,ERE,1,FIELD:dsn=([0-9]+\.[0-9]+\.[0-9])--end%', msg: '%msg%'\n"
+#$template db,"re: '%msg:R,ERE,1,ZERO:dsn=([0-9]+\.[0-9]+\.[0-9])--end%', msg: '%msg%'\n"
+#$template DEBUG,"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%, HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\nrawmsg: '%rawmsg%'\n\n"
+$template csv,"%syslogtag:::csv%,%msg:::upppercase,csv%,%msg%\n"
+*.* -/home/rger/proj/rsyslog/logfile
+kern.* -/home/rger/proj/rsyslog/logfile
+$ActionExecOnlyWhenPreviousIsSuspended on
+& -/tmp/xyz/uuu
+$ActionExecOnlyWhenPreviousIsSuspended off
+& ~
+& -/tmp/xyz/uuu2
+& -/tmp/xyz/uuu3
+
+
+#$template dynfile,"/home/rger/proj/rsyslog/test-%syslogtag%"
+#*.* -?dynfile
+#:msg, ereregex, "test|tast" /home/rger/proj/rsyslog/ere
+#if strlen($syslogtag & strlen($msg)) > 10 then /home/rger/proj/rsyslog/longlog
+#if strlen($msg) > 10 then /home/rger/proj/rsyslog/longlog
+#if tolower($msg) contains 'test' then /home/rger/proj/rsyslog/longlog
+#if $msg contains 'test' then /home/rger/proj/rsyslog/longlog
+
+#$ActionOMProgBinary /home/rger/proj/rsyslog/consumer
+#*.* :omprog:
+
+#$actionresumeretryCount -1
+#$actionResumeInterval 4
+#$template dynfile,"/mnt2/logs/logfile.log"
+#*.* /mnt2/logs/logfile.log
+#if $msg contains 'test' then ?dynfile
+#*.* ?dynfile
+:msg, contains, "test " /tmpo/sdafsdf
+
+$ActionName write_system_log_2
+if $msg == 'test' then /tmpo/sdafsdf2
+& /tmpo/234234
+*.* @@(o,z9)172.19.3.21:10514
+$GenerateConfigGraph /home/rger/proj/rsyslog/rsyslog.dot
diff --git a/doc/rsyslog_confgraph_complex.png b/doc/rsyslog_confgraph_complex.png
new file mode 100644
index 00000000..21c04c57
--- /dev/null
+++ b/doc/rsyslog_confgraph_complex.png
Binary files differ
diff --git a/doc/rsyslog_confgraph_std.conf b/doc/rsyslog_confgraph_std.conf
new file mode 100644
index 00000000..64c9a18a
--- /dev/null
+++ b/doc/rsyslog_confgraph_std.conf
@@ -0,0 +1,79 @@
+#rsyslog v3 config file
+
+# if you experience problems, check
+# http://www.rsyslog.com/troubleshoot for assistance
+
+#### MODULES ####
+
+$ModLoad imuxsock.so # provides support for local system logging (e.g. via logger command)
+$ModLoad imklog.so # provides kernel logging support (previously done by rklogd)
+#$ModLoad immark.so # provides --MARK-- message capability
+
+# Provides UDP syslog reception
+#$ModLoad imudp.so
+#$UDPServerRun 514
+
+# Provides TCP syslog reception
+#$ModLoad imtcp.so
+#$InputTCPServerRun 514
+
+
+#### GLOBAL DIRECTIVES ####
+
+# Use default timestamp format
+$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
+
+# File syncing capability is disabled by default. This feature is usually not required,
+# not useful and an extreme performance hit
+#$ActionFileEnableSync on
+
+
+#### RULES ####
+
+# Log all kernel messages to the console.
+# Logging much else clutters up the screen.
+#kern.* /dev/console
+
+# Log anything (except mail) of level info or higher.
+# Don't log private authentication messages!
+*.info;mail.none;authpriv.none;cron.none /var/log/messages
+
+# The authpriv file has restricted access.
+authpriv.* /var/log/secure
+
+# Log all the mail messages in one place.
+mail.* -/var/log/maillog
+
+
+# Log cron stuff
+cron.* /var/log/cron
+
+# Everybody gets emergency messages
+*.emerg *
+
+# Save news errors of level crit and higher in a special file.
+uucp,news.crit /var/log/spooler
+
+# Save boot messages also to boot.log
+local7.* /var/log/boot.log
+
+
+
+# ### begin forwarding rule ###
+# The statement between the begin ... end define a SINGLE forwarding
+# rule. They belong together, do NOT split them. If you create multiple
+# forwarding rules, duplicate the whole block!
+# Remote Logging (we use TCP for reliable delivery)
+#
+# An on-disk queue is created for this action. If the remote host is
+# down, messages are spooled to disk and sent when it is up again.
+#$WorkDirectory /var/spppl/rsyslog # where to place spool files
+#$ActionQueueFileName fwdRule1 # unique name prefix for spool files
+#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible)
+#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
+$ActionQueueType LinkedList # run asynchronously
+#$ActionResumeRetryCount -1 # infinite retries if host is down
+# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional
+*.* @@remote-host:514
+# ### end of the forwarding rule ###
+$GenerateConfigGraph /home/rger/proj/rsyslog/rsyslog.dot
diff --git a/doc/rsyslog_confgraph_std.png b/doc/rsyslog_confgraph_std.png
new file mode 100644
index 00000000..655a7f82
--- /dev/null
+++ b/doc/rsyslog_confgraph_std.png
Binary files differ
diff --git a/doc/troubleshoot.html b/doc/troubleshoot.html
index e655c2ef..cb4367f6 100644
--- a/doc/troubleshoot.html
+++ b/doc/troubleshoot.html
@@ -28,6 +28,15 @@ mode can be used in parallel to a running instance of rsyslogd.
<p><b><i>/path/to/rsyslogd -f/path/to/config-file -N1</i></b>
<p>You should also specify other options you usually give (like -c3 and whatever else).
Any problems experienced are reported to stderr [aka "your screen" (if not redirected)].
+<p><b>Configuration Graphs</b>
+<p>Starting with rsyslog 4.3.1, the
+&quot;<a href="rsconf1_generateconfiggraph.html">$GenerateConfigGraph</a>&quot;
+command is supported, a very valuable troubleshooting tool. It permits to
+generate a graph of how rsyslogd understood its configuration file. It is assumed that
+many configuration issues can easily be detected just by looking at the configuration graph.
+Full details of how to generate the graphs, and what to look for can be found in the
+&quot;<a href="rsconf1_generateconfiggraph.html">$GenerateConfigGraph</a>&quot;
+manual page.
<p><b>Asking for Help</b>
<p>If you can't find the answer yourself, you should look at these places for
community help.
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 026fbbed..fd5a5371 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -267,6 +267,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_ERR_FORK = -2118, /**< error during fork() */
RS_RET_ERR_WRITE_PIPE = -2119, /**< error writing to pipe */
RS_RET_RSCORE_TOO_OLD = -2120, /**< rsyslog core is too old for ... (eg this plugin) */
+ RS_RET_FILENAME_INVALID = -2140, /**< filename invalid, not found, no access, ... */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 8c86c12e..3a751a30 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -284,6 +284,7 @@ static int gidDropPriv = 0; /* group-id to which priveleges should be dropped to
extern int errno;
+static uchar *pszConfDAGFile = NULL; /* name of config DAG file, non-NULL means generate one */
/* main message queue and its configuration parameters */
static qqueue_t *pMsgQueue = NULL; /* the main message queue */
static int iMainMsgQueueSize = 10000; /* size of the main message queue above */
@@ -1939,10 +1940,9 @@ static void doDie(int sig)
static void
freeAllDynMemForTermination(void)
{
- if(pszMainMsgQFName != NULL)
- free(pszMainMsgQFName);
- if(pModDir != NULL)
- free(pModDir);
+ free(pszMainMsgQFName);
+ free(pModDir);
+ free(pszConfDAGFile);
}
@@ -2210,6 +2210,184 @@ static void freeSelectors(void)
}
+/* helper to generateConfigDAG, to print out all actions via
+ * the llExecFunc() facility.
+ * rgerhards, 2007-08-02
+ */
+struct dag_info {
+ FILE *fp; /* output file */
+ int iActUnit; /* current action unit number */
+ int iAct; /* current action in unit */
+ int bDiscarded; /* message discarded (config error) */
+ };
+DEFFUNC_llExecFunc(generateConfigDAGAction)
+{
+ action_t *pAction;
+ uchar *pszModName;
+ uchar *pszVertexName;
+ struct dag_info *pDagInfo;
+ DEFiRet;
+
+ pDagInfo = (struct dag_info*) pParam;
+ pAction = (action_t*) pData;
+
+ pszModName = module.GetStateName(pAction->pMod);
+
+ /* vertex */
+ if(pAction->pszName == NULL) {
+ if(!strcmp((char*)pszModName, "builtin-discard"))
+ pszVertexName = (uchar*)"discard";
+ else
+ pszVertexName = pszModName;
+ } else {
+ pszVertexName = pAction->pszName;
+ }
+
+ fprintf(pDagInfo->fp, "\tact%d_%d\t\t[label=\"%s\"%s%s]\n",
+ pDagInfo->iActUnit, pDagInfo->iAct, pszVertexName,
+ pDagInfo->bDiscarded ? " style=dotted color=red" : "",
+ (pAction->pQueue->qType == QUEUETYPE_DIRECT) ? "" : " shape=hexagon"
+ );
+
+ /* edge */
+ if(pDagInfo->iAct == 0) {
+ } else {
+ fprintf(pDagInfo->fp, "\tact%d_%d -> act%d_%d[%s%s]\n",
+ pDagInfo->iActUnit, pDagInfo->iAct - 1,
+ pDagInfo->iActUnit, pDagInfo->iAct,
+ pDagInfo->bDiscarded ? " style=dotted color=red" : "",
+ pAction->bExecWhenPrevSusp ? " label=\"only if\\nsuspended\"" : "" );
+ }
+
+ /* check for discard */
+ if(!strcmp((char*) pszModName, "builtin-discard")) {
+ fprintf(pDagInfo->fp, "\tact%d_%d\t\t[shape=box]\n",
+ pDagInfo->iActUnit, pDagInfo->iAct);
+ pDagInfo->bDiscarded = 1;
+ }
+
+
+ ++pDagInfo->iAct;
+
+ RETiRet;
+}
+
+
+/* create config DAG
+ * This functions takes a rsyslog config and produces a .dot file for use
+ * with graphviz (http://www.graphviz.org). This is done in an effort to
+ * document, and also potentially troubleshoot, configurations. Plus, I
+ * consider it a nice feature to explain some concepts. Note that the
+ * current version only produces a graph with relatively little information.
+ * This is a foundation that may be later expanded (if it turns out to be
+ * useful enough).
+ * rgerhards, 2009-05-11
+ */
+static rsRetVal
+generateConfigDAG(uchar *pszDAGFile)
+{
+ selector_t *f;
+ FILE *fp;
+ int iActUnit = 1;
+ int bHasFilter = 0; /* filter associated with this action unit? */
+ int bHadFilter;
+ int i;
+ struct dag_info dagInfo;
+ char *pszFilterName;
+ char szConnectingNode[64];
+ DEFiRet;
+
+ assert(pszDAGFile != NULL);
+
+ if((fp = fopen((char*) pszDAGFile, "w")) == NULL) {
+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)
+ "configuraton graph output file could not be opened, none generated", 0);
+ ABORT_FINALIZE(RS_RET_FILENAME_INVALID);
+ }
+
+ dagInfo.fp = fp;
+
+ /* from here on, we assume writes go well. This here is a really
+ * unimportant utility function and if something goes wrong, it has
+ * almost no effect. So let's not overdo this...
+ */
+ fprintf(fp, "# graph created by rsyslog " VERSION "\n\n"
+ "# use the dot tool from http://www.graphviz.org to visualize!\n"
+ "digraph rsyslogConfig {\n"
+ "\tinputs [shape=tripleoctagon]\n"
+ "\tinputs -> act0_0\n"
+ "\tact0_0 [label=\"main\\nqueue\" shape=hexagon]\n"
+ /*"\tmainq -> act1_0\n"*/
+ );
+ strcpy(szConnectingNode, "act0_0");
+ dagInfo.bDiscarded = 0;
+
+ for(f = Files; f != NULL ; f = f->f_next) {
+ /* BSD-Style filters are currently ignored */
+ bHadFilter = bHasFilter;
+ if(f->f_filter_type == FILTER_PRI) {
+ bHasFilter = 0;
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ if (f->f_filterData.f_pmask[i] != 0xff) {
+ bHasFilter = 1;
+ break;
+ }
+ } else {
+ bHasFilter = 1;
+ }
+
+ /* we know we have a filter, so it can be false */
+ switch(f->f_filter_type) {
+ case FILTER_PRI:
+ pszFilterName = "pri filter";
+ break;
+ case FILTER_PROP:
+ pszFilterName = "property filter";
+ break;
+ case FILTER_EXPR:
+ pszFilterName = "script filter";
+ break;
+ }
+
+ /* write action unit node */
+ if(bHasFilter) {
+ fprintf(fp, "\t%s -> act%d_end\t[label=\"%s:\\nfalse\"]\n",
+ szConnectingNode, iActUnit, pszFilterName);
+ fprintf(fp, "\t%s -> act%d_0\t[label=\"%s:\\ntrue\"]\n",
+ szConnectingNode, iActUnit, pszFilterName);
+ fprintf(fp, "\tact%d_end\t\t\t\t[shape=point]\n", iActUnit);
+ snprintf(szConnectingNode, sizeof(szConnectingNode), "act%d_end", iActUnit);
+ } else {
+ fprintf(fp, "\t%s -> act%d_0\t[label=\"no filter\"]\n",
+ szConnectingNode, iActUnit);
+ snprintf(szConnectingNode, sizeof(szConnectingNode), "act%d_0", iActUnit);
+ }
+
+ /* draw individual nodes */
+ dagInfo.iActUnit = iActUnit;
+ dagInfo.iAct = 0;
+ dagInfo.bDiscarded = 0;
+ llExecFunc(&f->llActList, generateConfigDAGAction, &dagInfo); /* actions */
+
+ /* finish up */
+ if(bHasFilter && !dagInfo.bDiscarded) {
+ fprintf(fp, "\tact%d_%d -> %s\n",
+ iActUnit, dagInfo.iAct - 1, szConnectingNode);
+ }
+
+ ++iActUnit;
+ }
+
+ fprintf(fp, "\t%s -> act%d_0\n", szConnectingNode, iActUnit);
+ fprintf(fp, "\tact%d_0\t\t[label=discard shape=box]\n"
+ "}\n", iActUnit);
+ fclose(fp);
+
+finalize_it:
+ RETiRet;
+}
+
+
/* helper to dbPrintInitInfo, to print out all actions via
* the llExecFunc() facility.
* rgerhards, 2007-08-02
@@ -2223,6 +2401,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
RETiRet;
}
+
/* print debug information as part of init(). This pretty much
* outputs the whole config of rsyslogd. I've moved this code
* out of init() to clean it somewhat up.
@@ -2230,7 +2409,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
*/
static void dbgPrintInitInfo(void)
{
- register selector_t *f;
+ selector_t *f;
int iSelNbr = 1;
int i;
@@ -2467,6 +2646,10 @@ init(void)
}
}
+ /* check if we need to generate a config DAG and, if so, do that */
+ if(pszConfDAGFile != NULL)
+ generateConfigDAG(pszConfDAGFile);
+
/* we are done checking the config - now validate if we should actually run or not.
* If not, terminate. -- rgerhards, 2008-07-25
*/
@@ -2903,6 +3086,7 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary,
NULL, &bDebugPrintCfSysLineHandlerList, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, NULL, &pszConfDAGFile, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL));