Logging: Add argument to list all available categories

New `--log-list-categories` command line argument to list all available
logging categories. This improves documentation of logging, allowing
users to understand what logging categories are available for use. It is
also useful for developers to understand what logging categories already
exist before making a change.

Implemented using static initializers to register all logrefs on startup.

Ref  #141754

Pull Request: https://projects.blender.org/blender/blender/pulls/146456
This commit is contained in:
Nick Alberelli
2025-09-26 17:33:26 +02:00
committed by Brecht Van Lommel
parent 8e9ccb33d0
commit f7e7a5d09e
3 changed files with 71 additions and 10 deletions

View File

@@ -76,6 +76,8 @@ struct CLG_LogType {
};
struct CLG_LogRef {
CLG_LogRef(const char *identifier);
const char *identifier;
CLG_LogType *type;
struct CLG_LogRef *next;
@@ -114,6 +116,10 @@ void CLG_level_set(CLG_Level level);
void CLG_logref_init(CLG_LogRef *clg_ref);
void CLG_logref_register(CLG_LogRef *clg_ref);
void CLG_logref_list_all(void (*callback)(const char *identifier, void *user_data),
void *user_data);
int CLG_color_support_get(CLG_LogRef *clg_ref);
/* When true, quiet any NOCHECK logs that would otherwise be printed regardless of log filters
@@ -123,6 +129,12 @@ int CLG_color_support_get(CLG_LogRef *clg_ref);
void CLG_quiet_set(bool quiet);
bool CLG_quiet_get();
inline CLG_LogRef::CLG_LogRef(const char *identifier)
: identifier(identifier), type(nullptr), next(nullptr)
{
CLG_logref_register(this);
}
/** Declare outside function, declare as extern in header. */
#define CLG_LOGREF_DECLARE_GLOBAL(var, id) \
static CLG_LogRef _static_##var = {id}; \

View File

@@ -14,6 +14,7 @@
#include <cstring>
#include <mutex>
#include <set>
/* Disable for small single threaded programs
* to avoid having to link with pthreads. */
@@ -78,8 +79,6 @@ struct CLG_IDFilter {
struct CLogContext {
/** Single linked list of types. */
CLG_LogType *types;
/** Single linked list of references. */
CLG_LogRef *refs;
#ifdef WITH_CLOG_PTHREADS
pthread_mutex_t types_lock;
#endif
@@ -113,6 +112,20 @@ struct CLogContext {
/** \} */
/* -------------------------------------------------------------------- */
/** \name Global LogRef Single Linked List
* \{ */
static CLG_LogRef **clg_all_refs_p()
{
/* Inside a function for correct static initialization order, otherwise
* all_refs might get null initialized only after logrefs are registered.*/
static CLG_LogRef *all_refs = nullptr;
return &all_refs;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mini Buffer Functionality
*
@@ -827,10 +840,8 @@ static void CLG_ctx_free(CLogContext *ctx)
MEM_freeN(item);
}
while (ctx->refs != nullptr) {
CLG_LogRef *item = ctx->refs;
ctx->refs = item->next;
item->type = nullptr;
for (CLG_LogRef *ref = *clg_all_refs_p(); ref; ref = ref->next) {
ref->type = nullptr;
}
for (uint i = 0; i < 2; i++) {
@@ -944,6 +955,32 @@ bool CLG_quiet_get()
* Use to avoid look-ups each time.
* \{ */
void CLG_logref_register(CLG_LogRef *clg_ref)
{
/* Add to global list of refs, both for setting the type to null on CLG_exit()
* and so CLG_logref_list_all can be used to print all categories. */
static std::mutex mutex;
std::scoped_lock lock(mutex);
CLG_LogRef **all_refs = clg_all_refs_p();
clg_ref->next = *all_refs;
*all_refs = clg_ref;
}
void CLG_logref_list_all(void (*callback)(const char *identifier, void *user_data),
void *user_data)
{
/* Generate sorted list of unique identifiers. */
auto cmp = [](const char *a, const char *b) { return std::strcmp(a, b) < 0; };
std::set<const char *, decltype(cmp)> identifiers(cmp);
for (CLG_LogRef *ref = *clg_all_refs_p(); ref; ref = ref->next) {
identifiers.insert(ref->identifier);
}
for (const char *identifier : identifiers) {
callback(identifier, user_data);
}
}
void CLG_logref_init(CLG_LogRef *clg_ref)
{
#ifdef WITH_CLOG_PTHREADS
@@ -951,10 +988,6 @@ void CLG_logref_init(CLG_LogRef *clg_ref)
pthread_mutex_lock(&g_ctx->types_lock);
#endif
if (clg_ref->type == nullptr) {
/* Add to the refs list so we can nullptr the pointers to 'type' when CLG_exit() is called. */
clg_ref->next = g_ctx->refs;
g_ctx->refs = clg_ref;
CLG_LogType *clg_ty = clg_ctx_type_find_by_name(g_ctx, clg_ref->identifier);
if (clg_ty == nullptr) {
clg_ty = clg_ctx_type_register(g_ctx, clg_ref->identifier);