core: add setting to permit compact json format

Adds the ability to remove unnecessary spaces from genrated json
to conserve space, e.g. on disk.

Maintainer edit: this replaces orginal PR which was too hard to
  rebase. This was caused by too-slow reaction of the rsyslog team.

see also: https://github.com/rsyslog/rsyslog/pull/2925
  (this is the original PR)

closes: https://github.com/rsyslog/rsyslog/issues/2913
This commit is contained in:
zhuyan 2025-09-09 17:57:39 +02:00 committed by Rainer Gerhards
parent 565d4f9eb0
commit 59235f8396
No known key found for this signature in database
GPG Key ID: 0CB6B2A8BE80B499
3 changed files with 41 additions and 16 deletions

View File

@ -40,6 +40,7 @@
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <json.h>
#include "rsyslog.h"
#include "obj.h"
@ -93,6 +94,13 @@ char **glblDbgFiles = NULL;
size_t glblDbgFilesNum = 0;
int glblDbgWhitelist = 1;
int glblPermitCtlC = 0;
/* For global option CompactJsonString:
* Compact the JSON variable string, without extra space.
* Considering compatibility issues, the default options(CompactJsonString = "off")
* keep the same as before.
*/
int glblJsonFormatOpt = JSON_C_TO_STRING_SPACED;
pid_t glbl_ourpid;
#ifndef HAVE_ATOMIC_BUILTINS
@ -109,6 +117,7 @@ static struct cnfparamdescr cnfparamdescr[] = {
{"operatingstatefile", eCmdHdlrString, 0},
{"dropmsgswithmaliciousdnsptrrecords", eCmdHdlrBinary, 0},
{"localhostname", eCmdHdlrGetWord, 0},
{"compactjsonstring", eCmdHdlrBinary, 0},
{"preservefqdn", eCmdHdlrBinary, 0},
{"debug.onshutdown", eCmdHdlrBinary, 0},
{"debug.logfile", eCmdHdlrString, 0},
@ -1224,6 +1233,12 @@ rsRetVal glblDoneLoadCnf(void) {
setNetstrmDrvrCAExtraFiles(NULL, cstr);
} else if (!strcmp(paramblk.descr[i].name, "preservefqdn")) {
bPreserveFQDN = (int)cnfparamvals[i].val.d.n;
} else if (!strcmp(paramblk.descr[i].name, "compactjsonstring")) {
if (cnfparamvals[i].val.d.n) {
glblJsonFormatOpt = JSON_C_TO_STRING_PLAIN;
} else {
glblJsonFormatOpt = JSON_C_TO_STRING_SPACED;
}
} else if (!strcmp(paramblk.descr[i].name, "dropmsgswithmaliciousdnsptrrecords")) {
loadConf->globals.bDropMalPTRMsgs = (int)cnfparamvals[i].val.d.n;
} else if (!strcmp(paramblk.descr[i].name, "action.reportsuspension")) {

View File

@ -117,6 +117,7 @@ ENDinterface(glbl)
/* the remaining prototypes */
PROTOTYPEObj(glbl);
extern int glblJsonFormatOpt;
extern int glblUnloadModules;
extern short janitorInterval;
extern char **glblDbgFiles;

View File

@ -965,6 +965,15 @@ ENDobjDestruct
#undef tmpCOPYSZ
#undef tmpCOPYCSTR
static const char *jsonToString(struct json_object *const json) {
if (!json) return NULL;
if (json_object_get_type(json) == json_type_string) {
return json_object_get_string(json);
}
return json_object_to_json_string_ext(json, glblJsonFormatOpt);
}
/* This method serializes a message object. That means the whole
* object is modified into text form. That text form is suitable for
@ -1011,13 +1020,13 @@ static rsRetVal MsgSerialize(smsg_t *pThis, strm_t *pStrm) {
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszStrucData"), PROPTYPE_PSZ, (void *)psz));
if (pThis->json != NULL) {
MsgLock(pThis);
psz = (uchar *)json_object_get_string(pThis->json);
psz = (uchar *)jsonToString(pThis->json);
MsgUnlock(pThis);
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("json"), PROPTYPE_PSZ, (void *)psz));
}
if (pThis->localvars != NULL) {
MsgLock(pThis);
psz = (uchar *)json_object_get_string(pThis->localvars);
psz = (uchar *)jsonToString(pThis->localvars);
MsgUnlock(pThis);
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("localvars"), PROPTYPE_PSZ, (void *)psz));
}
@ -2147,7 +2156,7 @@ const uchar *msgGetJSONMESG(smsg_t *__restrict__ const pMsg) {
json_object_object_add(json, "$!", json_object_get(pMsg->json));
pRes = (uchar *)strdup(json_object_get_string(json));
pRes = (uchar *)strdup(jsonToString(json));
json_object_put(json);
return pRes;
}
@ -2839,7 +2848,7 @@ rsRetVal getJSONPropVal(
if (jsonVarExtract(parent, (char *)leaf, &field) == FALSE) field = NULL;
}
if (field != NULL) {
*pRes = (uchar *)strdup(json_object_get_string(field));
*pRes = (uchar *)strdup(jsonToString(field));
*buflen = (int)ustrlen(*pRes);
*pbMustBeFreed = 1;
}
@ -2897,7 +2906,7 @@ rsRetVal msgGetJSONPropJSONorString(smsg_t *const pMsg,
*pcstr = (uchar *)strdup("");
} else {
if (json_object_get_type(*pjson) == json_type_string) {
*pcstr = (uchar *)strdup(json_object_get_string(*pjson));
*pcstr = (uchar *)strdup(jsonToString(*pjson));
*pjson = NULL;
}
}
@ -4317,18 +4326,18 @@ static rsRetVal msgSetPropViaJSON(smsg_t *__restrict__ const pMsg,
int bNeedFree = 1;
DEFiRet;
/* note: json_object_get_string() manages the memory of the returned
/* note: jsonToString() manages the memory of the returned
* string. So we MUST NOT free it!
*/
dbgprintf("DDDD: msgSetPropViaJSON key: '%s'\n", name);
if (!strcmp(name, "rawmsg")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetRawMsg(pMsg, psz, strlen(psz));
} else if (!strcmp(name, "msg")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgReplaceMSG(pMsg, (const uchar *)psz, strlen(psz));
} else if (!strcmp(name, "syslogtag")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetTAG(pMsg, (const uchar *)psz, strlen(psz));
} else if (!strcmp(name, "pri")) {
val = json_object_get_int(json);
@ -4346,23 +4355,23 @@ static rsRetVal msgSetPropViaJSON(smsg_t *__restrict__ const pMsg,
else
DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val);
} else if (!strcmp(name, "procid")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetPROCID(pMsg, psz);
} else if (!strcmp(name, "msgid")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetMSGID(pMsg, psz);
} else if (!strcmp(name, "structured-data")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetStructuredData(pMsg, psz);
} else if (!strcmp(name, "hostname") || !strcmp(name, "source")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetHOSTNAME(pMsg, (const uchar *)psz, strlen(psz));
} else if (!strcmp(name, "fromhost")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetRcvFromStr(pMsg, (const uchar *)psz, strlen(psz), &propFromHost);
prop.Destruct(&propFromHost);
} else if (!strcmp(name, "fromhost-ip")) {
psz = json_object_get_string(json);
psz = jsonToString(json);
MsgSetRcvFromIPStr(pMsg, (const uchar *)psz, strlen(psz), &propRcvFromIP);
prop.Destruct(&propRcvFromIP);
} else if (!strcmp(name, "$!")) {
@ -4818,7 +4827,7 @@ struct json_object *jsonDeepCopy(struct json_object *src) {
dst = json_object_new_int64(json_object_get_int64(src));
break;
case json_type_string:
dst = json_object_new_string(json_object_get_string(src));
dst = json_object_new_string(jsonToString(src));
break;
case json_type_object:
dst = json_object_new_object();