diff --git a/rpmio/rpmlog.cc b/rpmio/rpmlog.cc index 6253e45d51..ad6e8c7ed7 100644 --- a/rpmio/rpmlog.cc +++ b/rpmio/rpmlog.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -22,6 +23,7 @@ struct rpmlogCtx_s { unsigned mask; int nrecsPri[RPMLOG_NPRIS]; std::vector recs; + std::map, int>> seen; rpmlogCallback cbfunc; rpmlogCallbackData cbdata; FILE *stdlog; @@ -41,7 +43,7 @@ using rdlock = std::shared_lock; static rpmlogCtx rpmlogCtxAcquire() { static struct rpmlogCtx_s _globalCtx = { RPMLOG_UPTO(RPMLOG_NOTICE), - {0}, {}, NULL, NULL, NULL }; + {0}, {}, {}, NULL, NULL, NULL }; return &_globalCtx; } @@ -127,6 +129,7 @@ void rpmlogClose (void) wrlock lock(ctx->mutex); ctx->recs.clear(); + ctx->seen.clear(); memset(ctx->nrecsPri, 0, sizeof(ctx->nrecsPri)); } @@ -412,3 +415,36 @@ void rpmlog (int code, const char *fmt, ...) exit: errno = saved_errno; } + +int rpmlogOnce (uint64_t domain, const char * key, int code, const char *fmt, ...) +{ + int saved_errno = errno; + rpmlogCtx ctx = rpmlogCtxAcquire(); + int newkey = 0; + + if (ctx) { + wrlock lock(ctx->mutex); + /* members get initialized automatically on first access */ + newkey = !(ctx->seen[domain][{code, key}]++); + } + + if (newkey) { + va_list ap; + char *msg = NULL; + va_start(ap, fmt); + if (rvasprintf(&msg, fmt, ap) >= 0) { + rpmlog(code, msg); + free(msg); + } + va_end(ap); + } + errno = saved_errno; + return newkey; +} + +void rpmlogReset(uint64_t domain, int mode=0) +{ + rpmlogCtx ctx = rpmlogCtxAcquire(); + wrlock lock(ctx->mutex); + ctx->seen.erase(domain); +} diff --git a/rpmio/rpmlog_internal.hh b/rpmio/rpmlog_internal.hh new file mode 100644 index 0000000000..8024eddc0c --- /dev/null +++ b/rpmio/rpmlog_internal.hh @@ -0,0 +1,23 @@ +#ifndef H_RPMLOG_INTERNAL +#define H_RPMLOG_INTERNAL 1 + + +/** \ingroup rpmlog + * Generate a log message using FMT string and option arguments. + * Only actually log on the first time passing the key value + * @param domain group of messages to be reset together + * @param key key to match log messages together + * @param code rpmlogLvl + * @param fmt format string and parameter to render + * @return 1 if actually logging 0 otherwise + */ +int rpmlogOnce (uint64_t domain, const char * key, int code, const char *fmt, ...) RPM_GNUC_PRINTF(4, 5); + +/** \ingroup rpmlog + * Clear memory of logmessages for a given domain + * @param domain group of messages to be reset together + * @param mode curretnly only 0 supported whihc drops everything + */ +void rpmlogReset(uint64_t domain, int mode=0); + +#endif