-
Notifications
You must be signed in to change notification settings - Fork 375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add rpmlogOnce() and rpmlogReset() #3417
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
#include <mutex> | ||
#include <shared_mutex> | ||
#include <vector> | ||
#include <unordered_map> | ||
#include <string> | ||
|
||
#include <stdarg.h> | ||
|
@@ -17,11 +18,22 @@ | |
#include <rpm/rpmstring.h> | ||
#include "debug.h" | ||
|
||
struct pair_hash { | ||
template <class T1, class T2> | ||
std::size_t operator () (const std::pair<T1,T2> &p) const { | ||
auto h1 = std::hash<T1>{}(p.first); | ||
auto h2 = std::hash<T2>{}(p.second); | ||
/* based on boost::hash_combine */ | ||
return h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2); | ||
} | ||
}; | ||
|
||
typedef struct rpmlogCtx_s * rpmlogCtx; | ||
struct rpmlogCtx_s { | ||
unsigned mask; | ||
int nrecsPri[RPMLOG_NPRIS]; | ||
std::vector<rpmlogRec_s> recs; | ||
std::unordered_map<uint64_t, std::unordered_map<std::pair<int, std::string>, int, pair_hash>> seen; | ||
rpmlogCallback cbfunc; | ||
rpmlogCallbackData cbdata; | ||
FILE *stdlog; | ||
|
@@ -41,7 +53,7 @@ using rdlock = std::shared_lock<std::shared_mutex>; | |
static rpmlogCtx rpmlogCtxAcquire() | ||
{ | ||
static struct rpmlogCtx_s _globalCtx = { RPMLOG_UPTO(RPMLOG_NOTICE), | ||
{0}, {}, NULL, NULL, NULL }; | ||
{0}, {}, {}, NULL, NULL, NULL }; | ||
return &_globalCtx; | ||
} | ||
|
||
|
@@ -127,6 +139,7 @@ void rpmlogClose (void) | |
wrlock lock(ctx->mutex); | ||
|
||
ctx->recs.clear(); | ||
ctx->seen.clear(); | ||
memset(ctx->nrecsPri, 0, sizeof(ctx->nrecsPri)); | ||
} | ||
|
||
|
@@ -412,3 +425,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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thing that occurred to me last evening is that technically this should use a mutex of its own - there's no reason to prevent other logging events from proceeding while we filter out other messages. Not that it matters here so just a random remark, not a requirement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically yes. For now I don't want to over complicate things for what is very little gains in practice. |
||
/* 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); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this check necessary? We don't seem to be doing it elsewhere in this file (the global
ctx
is always returned).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not. It is there to limit the scope of the lock. If you want to use rpmlock below to print the numbers for the repeated messages we can't hold a lock there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add a bogus check just to create a scope, if you need a scope then just use a plain { } block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But a cleaner version is actually to wrap the seen-check and the lock into a small seenLog() style helper function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, that didn't occur to me, thanks for clarifying.