summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2009-04-02 12:48:07 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2009-04-02 12:48:07 +0200
commit3954f2e166c3cbd78c71819c8d6c25120042dbcf (patch)
tree2c70fa3bb36f763490146e1fa6e205600f5afb34
parente4f012eb60f6531f964557ba9eac54048ae2bef8 (diff)
downloadrsyslog-3954f2e166c3cbd78c71819c8d6c25120042dbcf.tar.gz
rsyslog-3954f2e166c3cbd78c71819c8d6c25120042dbcf.tar.xz
rsyslog-3954f2e166c3cbd78c71819c8d6c25120042dbcf.zip
added new "csv" property replacer option
to enable simple creation of CSV-formatted outputs (format from RFC4180 is used)
-rw-r--r--ChangeLog2
-rw-r--r--doc/property_replacer.html14
-rw-r--r--runtime/msg.c34
-rw-r--r--template.c5
-rw-r--r--template.h7
5 files changed, 58 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 23a2e3e0..42fda5b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,8 @@
I only tweaked a very little bit.
---------------------------------------------------------------------------
Version 4.1.6 [DEVEL] (rgerhards), 2009-03-??
+- added new "csv" property replacer options to enable simple creation
+ of CSV-formatted outputs (format from RFC4180 is used)
- implemented function support in RainerScript. That means the engine
parses and compile functions, as well as executes a few build-in
ones. Dynamic loading and registration of functions is not yet
diff --git a/doc/property_replacer.html b/doc/property_replacer.html
index baf053f2..a6e9b518 100644
--- a/doc/property_replacer.html
+++ b/doc/property_replacer.html
@@ -314,6 +314,18 @@ case-insensitive. Currently, the following options are defined:
<td>convert property text to uppercase only</td>
</tr>
<tr>
+<td valign="top"><b>csv</b></td>
+<td>formats the resulting field (after all modifications) in CSV format
+as specified in <a href="http://www.ietf.org/rfc/rfc4180.txt">RFC 4180</a>.
+Rsyslog will always use double quotes. Note that in order to have full CSV-formatted
+text, you need to define a proper template. An example is this one:
+<br>$template csvline,"%syslogtag:::csv%,%msg:::csv%"
+<br>Most importantly, you need to provide the commas between the fields
+inside the template.
+<br><i>This feature was introduced in rsyslog 4.1.6.</i>
+</td>
+</tr>
+<tr>
<td><b>drop-last-lf</b></td>
<td>The last LF in the message (if any), is dropped.
Especially useful for PIX.</td>
@@ -411,7 +423,7 @@ syntax</a>, this is where you actually use the property replacer.</li>
[<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; 2008 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2008, 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>
diff --git a/runtime/msg.c b/runtime/msg.c
index 9aa2ce84..5d1f21fd 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -2405,6 +2405,40 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
}
+ /* finally, we need to check if the property should be formatted in CSV
+ * format (we use RFC 4180, and always use double quotes). As of this writing,
+ * this should be the last action carried out on the property, but in the
+ * future there may be reasons to change that. -- rgerhards, 2009-04-02
+ */
+ if(pTpe->data.field.options.bCSV) {
+ /* we need to obtain a private copy, as we need to at least add the double quotes */
+ int iBufLen = strlen(pRes);
+ char *pBStart;
+ char *pDst;
+ char *pSrc;
+ /* the malloc may be optimized, we currently use the worst case... */
+ pBStart = pDst = malloc((2 * iBufLen + 3) * sizeof(char));
+ if(pDst == NULL) {
+ if(*pbMustBeFreed == 1)
+ free(pRes);
+ *pbMustBeFreed = 0;
+ return "**OUT OF MEMORY**";
+ }
+ pSrc = pRes;
+ *pDst++ = '"'; /* starting quote */
+ while(*pSrc) {
+ if(*pSrc == '"')
+ *pDst++ = '"'; /* need to add double double quote (see RFC4180) */
+ *pDst++ = *pSrc++;
+ }
+ *pDst++ = '"'; /* ending quote */
+ *pDst = '\0';
+ if(*pbMustBeFreed == 1)
+ free(pRes);
+ pRes = pBStart;
+ *pbMustBeFreed = 1;
+ }
+
/*dbgprintf("MsgGetProp(\"%s\"): \"%s\"\n", pName, pRes); only for verbose debug logging */
return(pRes);
}
diff --git a/template.c b/template.c
index 6fb7ba2b..4f507ff6 100644
--- a/template.c
+++ b/template.c
@@ -460,6 +460,8 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe)
pTpe->data.field.options.bSecPathDrop = 1;
} else if(!strcmp((char*)Buf, "secpath-replace")) {
pTpe->data.field.options.bSecPathReplace = 1;
+ } else if(!strcmp((char*)Buf, "csv")) {
+ pTpe->data.field.options.bCSV = 1;
} else {
dbgprintf("Invalid field option '%s' specified - ignored.\n", Buf);
}
@@ -1105,6 +1107,9 @@ void tplPrintList(void)
if(pTpe->data.field.options.bSPIffNo1stSP) {
dbgprintf("[SP iff no first SP] ");
}
+ if(pTpe->data.field.options.bCSV) {
+ dbgprintf("[format as CSV (RFC4180)]");
+ }
if(pTpe->data.field.options.bDropLastLF) {
dbgprintf("[drop last LF in msg] ");
}
diff --git a/template.h b/template.h
index 04137b09..6ca8dc6c 100644
--- a/template.h
+++ b/template.h
@@ -94,9 +94,10 @@ struct templateEntry {
unsigned bSpaceCC: 1; /* change control characters to spaceescape? */
unsigned bEscapeCC: 1; /* escape control characters? */
unsigned bDropLastLF: 1; /* drop last LF char in msg (PIX!) */
- unsigned bSecPathDrop: 1; /* drop slashes, replace dots, empty string */
- unsigned bSecPathReplace: 1; /* replace slashes, replace dots, empty string */
- unsigned bSPIffNo1stSP: 1; /* replace slashes, replace dots, empty string */
+ unsigned bSecPathDrop: 1; /* drop slashes, replace dots, empty string */
+ unsigned bSecPathReplace: 1; /* replace slashes, replace dots, empty string */
+ unsigned bSPIffNo1stSP: 1; /* replace slashes, replace dots, empty string */
+ unsigned bCSV: 1; /* format field in CSV (RFC 4180) format */
} options; /* options as bit fields */
} field;
} data;