rsyslog/plugins/mmfields/mmfields.c
2018-07-31 09:44:27 +02:00

276 lines
6.0 KiB
C

/* mmfields.c
* Parse all fields of the message into structured data inside the
* JSON tree.
*
* Copyright 2013 Adiscon GmbH.
*
* This file is part of rsyslog.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* -or-
* see COPYING.ASL20 in the source distribution
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include "rsyslog.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include "conf.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "template.h"
#include "module-template.h"
#include "errmsg.h"
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
MODULE_CNFNAME("mmfields")
DEF_OMOD_STATIC_DATA
/* config variables */
/* define operation modes we have */
#define SIMPLE_MODE 0 /* just overwrite */
#define REWRITE_MODE 1 /* rewrite IP address, canoninized */
typedef struct _instanceData {
char separator;
uchar *jsonRoot; /**< container where to store fields */
} instanceData;
typedef struct wrkrInstanceData {
instanceData *pData;
} wrkrInstanceData_t;
struct modConfData_s {
rsconf_t *pConf; /* our overall config object */
};
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */
/* tables for interfacing with the v6 config system */
/* action (instance) parameters */
static struct cnfparamdescr actpdescr[] = {
{ "separator", eCmdHdlrGetChar, 0 },
{ "jsonroot", eCmdHdlrString, 0 }
};
static struct cnfparamblk actpblk =
{ CNFPARAMBLK_VERSION,
sizeof(actpdescr)/sizeof(struct cnfparamdescr),
actpdescr
};
BEGINbeginCnfLoad
CODESTARTbeginCnfLoad
loadModConf = pModConf;
pModConf->pConf = pConf;
ENDbeginCnfLoad
BEGINendCnfLoad
CODESTARTendCnfLoad
ENDendCnfLoad
BEGINcheckCnf
CODESTARTcheckCnf
ENDcheckCnf
BEGINactivateCnf
CODESTARTactivateCnf
runModConf = pModConf;
ENDactivateCnf
BEGINfreeCnf
CODESTARTfreeCnf
ENDfreeCnf
BEGINcreateInstance
CODESTARTcreateInstance
ENDcreateInstance
BEGINcreateWrkrInstance
CODESTARTcreateWrkrInstance
ENDcreateWrkrInstance
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
ENDisCompatibleWithFeature
BEGINfreeInstance
CODESTARTfreeInstance
free(pData->jsonRoot);
ENDfreeInstance
BEGINfreeWrkrInstance
CODESTARTfreeWrkrInstance
ENDfreeWrkrInstance
static inline void
setInstParamDefaults(instanceData *pData)
{
pData->separator = ',';
pData->jsonRoot = NULL;
}
BEGINnewActInst
struct cnfparamvals *pvals;
int i;
CODESTARTnewActInst
DBGPRINTF("newActInst (mmfields)\n");
if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
}
CODE_STD_STRING_REQUESTnewActInst(1)
CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG));
CHKiRet(createInstance(&pData));
setInstParamDefaults(pData);
for(i = 0 ; i < actpblk.nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
if(!strcmp(actpblk.descr[i].name, "separator")) {
pData->separator = es_getBufAddr(pvals[i].val.d.estr)[0];
} else if(!strcmp(actpblk.descr[i].name, "jsonroot")) {
pData->jsonRoot = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else {
dbgprintf("mmfields: program error, non-handled "
"param '%s'\n", actpblk.descr[i].name);
}
}
if(pData->jsonRoot == NULL) {
CHKmalloc(pData->jsonRoot = (uchar*) strdup("!"));
}
CODE_STD_FINALIZERnewActInst
cnfparamvalsDestruct(pvals, &actpblk);
ENDnewActInst
BEGINdbgPrintInstInfo
CODESTARTdbgPrintInstInfo
ENDdbgPrintInstInfo
BEGINtryResume
CODESTARTtryResume
ENDtryResume
static rsRetVal
extractField(instanceData *pData, uchar *msgtext, int lenMsg, int *curridx, uchar *fieldbuf)
{
int i, j;
DEFiRet;
i = *curridx;
j = 0;
while(i < lenMsg && msgtext[i] != pData->separator) {
fieldbuf[j++] = msgtext[i++];
}
fieldbuf[j] = '\0';
if(i < lenMsg)
++i;
*curridx = i;
RETiRet;
}
static rsRetVal
parse_fields(instanceData *pData, smsg_t *pMsg, uchar *msgtext, int lenMsg)
{
uchar fieldbuf[32*1024];
uchar fieldname[512];
struct json_object *json;
struct json_object *jval;
int field;
uchar *buf;
int currIdx = 0;
DEFiRet;
if(lenMsg < (int) sizeof(fieldbuf)) {
buf = fieldbuf;
} else {
CHKmalloc(buf = malloc(lenMsg+1));
}
json = json_object_new_object();
if(json == NULL) {
ABORT_FINALIZE(RS_RET_ERR);
}
field = 1;
while(currIdx < lenMsg) {
CHKiRet(extractField(pData, msgtext, lenMsg, &currIdx, buf));
DBGPRINTF("mmfields: field %d: '%s'\n", field, buf);
snprintf((char*)fieldname, sizeof(fieldname), "f%d", field);
fieldname[sizeof(fieldname)-1] = '\0';
jval = json_object_new_string((char*)buf);
json_object_object_add(json, (char*)fieldname, jval);
field++;
}
msgAddJSON(pMsg, pData->jsonRoot, json, 0, 0);
finalize_it:
if(buf != fieldbuf)
free(buf);
RETiRet;
}
BEGINdoAction_NoStrings
smsg_t **ppMsg = (smsg_t **) pMsgData;
smsg_t *pMsg = ppMsg[0];
uchar *msg;
int lenMsg;
CODESTARTdoAction
lenMsg = getMSGLen(pMsg);
msg = getMSG(pMsg);
iRet = parse_fields(pWrkrData->pData, pMsg, msg, lenMsg);
ENDdoAction
NO_LEGACY_CONF_parseSelectorAct
BEGINmodExit
CODESTARTmodExit
ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_OMOD_QUERIES
CODEqueryEtryPt_STD_OMOD8_QUERIES
CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
DBGPRINTF("mmfields: module compiled with rsyslog version %s.\n", VERSION);
ENDmodInit