rsyslog/runtime/statsobj.h
Rainer Gerhards 7d3ff39e88 atomic: remove trailing semicolons from helper macros
Trailing semicolons in atomic helper macros caused double
semicolons when the macros expanded, producing build warnings.
Macros now omit semicolons and call sites add them explicitly.
STATSCOUNTER_DEF updated to terminate the generated mutex line.

AI-Agent: ChatGPT
2025-08-19 16:06:44 +02:00

229 lines
9.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* The statsobj object.
*
* Copyright 2010-2016 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
* 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.
*/
/**
* @file statsobj.h
* @brief Interface of the rsyslog statistics object
*
* A statistics object (statsobj_t) represents a set of counters that
* describe activity within a subsystem. Each object keeps a doubly
* linked list of counters and all objects are maintained in a global
* list protected by a mutex. The counters are either 64 bit integers
* (ctrType_IntCtr) or plain int values (ctrType_Int) and can be marked
* resettable. Statistics are only gathered while the global
* ::GatherStats flag is non-zero.
*
* Counters can be reported in multiple formats via the GetAllStatsLines()
* interface:
* - ::statsFmt_Legacy classic key=value pairs
* - ::statsFmt_JSON valid JSON structures
* - ::statsFmt_JSON_ES JSON with dot replacement for Elasticsearch
* - ::statsFmt_CEE Project Lumberjack / CEE format
* - ::statsFmt_Prometheus Prometheus text exposition format
*
* The caller supplies a callback that receives each generated line.
* After emission counters flagged with CTR_FLAG_RESETTABLE may be
* cleared if requested.
*/
#ifndef INCLUDED_STATSOBJ_H
#define INCLUDED_STATSOBJ_H
#include "atomic.h"
/* The following data item is somewhat dirty, in that it does not follow
* our usual object calling conventions. However, much like with "Debug", we
* do this to gain speed. If we finally come to a platform that does not
* provide resolution of names for dynamically loaded modules, we need to find
* a work-around, but until then, we use the direct access.
* If set to 0, statistics are not gathered, otherwise they are.
*/
extern int GatherStats;
/* our basic counter type -- need 32 bit on 32 bit platform.
* IMPORTANT: this type *MUST* be supported by atomic instructions!
*/
typedef uint64 intctr_t;
/* counter types */
typedef enum statsCtrType_e { ctrType_IntCtr, ctrType_Int } statsCtrType_t;
/* stats line format types */
typedef enum statsFmtType_e {
statsFmt_Legacy,
statsFmt_JSON,
statsFmt_JSON_ES,
statsFmt_CEE,
/**
* Prometheus textexposition format:
* For each counter, emit:
* # HELP <obj>_<ctr> (optional generic text)
* # TYPE <obj>_<ctr> counter
* <obj>_<ctr> <value>
*/
statsFmt_Prometheus
} statsFmtType_t;
/* counter flags */
#define CTR_FLAG_NONE 0
#define CTR_FLAG_RESETTABLE 1
#define CTR_FLAG_MUST_RESET 2
/* statsobj flags */
#define STATSOBJ_FLAG_NONE 0
#define STATSOBJ_FLAG_DO_PREPEND 1
/* helper entity, the counter */
typedef struct ctr_s {
uchar *name;
statsCtrType_t ctrType;
union {
intctr_t *pIntCtr;
int *pInt;
} val;
int8_t flags;
struct ctr_s *next, *prev;
} ctr_t;
/* the statsobj object */
struct statsobj_s {
BEGINobjInstance
; /* Data to implement generic object - MUST be the first data element! */
uchar *name;
uchar *origin;
uchar *reporting_ns;
statsobj_read_notifier_t read_notifier;
void *read_notifier_ctx;
pthread_mutex_t mutCtr; /* to guard counter linked-list ops */
ctr_t *ctrRoot; /* doubly-linked list of statsobj counters */
ctr_t *ctrLast;
int flags;
/* used to link ourselves together */
statsobj_t *prev;
statsobj_t *next;
};
struct sender_stats {
const uchar *sender;
uint64_t nMsgs;
time_t lastSeen;
};
/* interfaces */
BEGINinterface(statsobj) /* name must also be changed in ENDinterface macro! */
INTERFACEObjDebugPrint(statsobj);
rsRetVal (*Construct)(statsobj_t **ppThis);
rsRetVal (*ConstructFinalize)(statsobj_t *pThis);
rsRetVal (*Destruct)(statsobj_t **ppThis);
rsRetVal (*SetName)(statsobj_t *pThis, uchar *name);
rsRetVal (*SetOrigin)(statsobj_t *pThis, uchar *name); /* added v12, 2014-09-08 */
rsRetVal (*SetReadNotifier)(statsobj_t *pThis, statsobj_read_notifier_t notifier, void *ctx);
rsRetVal (*SetReportingNamespace)(statsobj_t *pThis, uchar *ns);
void (*SetStatsObjFlags)(statsobj_t *pThis, int flags);
rsRetVal (*GetAllStatsLines)(rsRetVal (*cb)(void *, const char *), void *usrptr, statsFmtType_t fmt,
int8_t bResetCtr);
rsRetVal (*AddCounter)(statsobj_t *pThis, const uchar *ctrName, statsCtrType_t ctrType, int8_t flags, void *pCtr);
rsRetVal (*AddManagedCounter)(statsobj_t *pThis, const uchar *ctrName, statsCtrType_t ctrType, int8_t flags,
void *pCtr, ctr_t **ref, int8_t linked);
void (*AddPreCreatedCtr)(statsobj_t *pThis, ctr_t *ctr);
void (*DestructCounter)(statsobj_t *pThis, ctr_t *ref);
void (*DestructUnlinkedCounter)(ctr_t *ctr);
ctr_t *(*UnlinkAllCounters)(statsobj_t *pThis);
rsRetVal (*EnableStats)(void);
ENDinterface(statsobj)
#define statsobjCURR_IF_VERSION 13 /* increment whenever you change the interface structure! */
/* Changes
* v2-v9 rserved for future use in "older" version branches
* v10, 2012-04-01: GetAllStatsLines got fmt parameter
* v11, 2013-09-07: - add "flags" to AddCounter API
* - GetAllStatsLines got parameter telling if ctrs shall be reset
* v13, 2016-05-19: GetAllStatsLines cb data type changed (char* instead of cstr)
*/
/* prototypes */
PROTOTYPEObj(statsobj);
rsRetVal statsRecordSender(const uchar *sender, unsigned nMsgs, time_t lastSeen);
/* checkGoneAwaySenders() is part of this module because all it needs is
* done by this module, so even though it's own processing is not directly
* related to stats, it makes sense to do it here... -- rgerhards, 2016-02-01
*/
void checkGoneAwaySenders(time_t);
/* macros to handle stats counters
* These are to be used by "counter providers". Note that we MUST
* specify the mutex name, even though at first it looks like it
* could be automatically be generated via e.g. "mut##ctr".
* Unfortunately, this does not work if counter is e.g. "pThis->ctr".
* So we decided, for clarity, to always insist on specifying the mutex
* name (after all, it's just a few more keystrokes...).
* --------------------------------------------------------------------
* NOTE WELL
* --------------------------------------------------------------------
* There are actually two types of stats counters: "regular" counters,
* which are only used for stats purposes and "dual" counters, which
* are primarily used for other purposes but can be included in stats
* as well. ALL regular counters MUST be initialized with
* STATSCOUNTER_INIT and only be modified by STATSCOUNTER_* functions.
* They MUST NOT be used for any other purpose (if this seems to make
* sense, consider changing it to a dual counter).
* Dual counters are somewhat dangerous in that a single variable is
* used for two purposes: the actual application need and stats
* counting. However, this is supported for performance reasons, as it
* provides insight into the inner engine workings without need for
* additional counters (and their maintenance code). Dual counters
* MUST NOT be modified by STATSCOUNTER_* functions. Most importantly,
* it is expected that the actua application code provides proper
* (enough) synchronized access to these counters. Most importantly,
* this means they have NO stats-system mutex associated to them.
*
* The interface function AddCounter() is a read-only function. It
* only provides the stats subsystem with a reference to a counter.
* It is irrelevant if the counter is a regular or dual one. For that
* reason, AddCounter() must not modify the counter contents, as in
* the case of a dual counter application code may be broken.
*/
#define STATSCOUNTER_DEF(ctr, mut) \
intctr_t ctr; \
DEF_ATOMIC_HELPER_MUT64(mut);
#define STATSCOUNTER_INIT(ctr, mut) \
INIT_ATOMIC_HELPER_MUT64(mut); \
ctr = 0;
#define STATSCOUNTER_INC(ctr, mut) \
if (GatherStats) ATOMIC_INC_uint64(&ctr, &mut);
#define STATSCOUNTER_ADD(ctr, mut, delta) \
if (GatherStats) ATOMIC_ADD_uint64(&ctr, &mut, delta);
#define STATSCOUNTER_DEC(ctr, mut) \
if (GatherStats) ATOMIC_DEC_uint64(&ctr, &mut);
/* the next macro works only if the variable is already guarded
* by mutex (or the users risks a wrong result). It is assumed
* that there are not concurrent operations that modify the counter.
*/
#define STATSCOUNTER_SETMAX_NOMUT(ctr, newmax) \
if (GatherStats && ((newmax) > (ctr))) ctr = newmax;
#endif /* #ifndef INCLUDED_STATSOBJ_H */