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)
This commit is contained in:
Rainer Gerhards 2009-05-11 17:38:33 +02:00
parent 9823c73d1d
commit 8e430258fd
13 changed files with 530 additions and 13 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 \

View File

@ -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>

View File

@ -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>

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@ -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.

View File

@ -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) */

View File

@ -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));