mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-10 21:28:32 +09:00
[Fix, Feat, Test] (MG_Util, MG_Backend, MG_Impl, MG_State): correct the log severity ordering and unwind the diagnostics it silenced
This commit is contained in:
@@ -115,7 +115,13 @@ namespace MobileGL {
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_LOG_ENABLE_ANDROID && defined(__ANDROID__)
|
||||
__android_log_print(androidLogLevel, "MobileGL", "%s", out.c_str());
|
||||
// Without the trailing newline that the file sink needs: logcat terminates
|
||||
// records itself, so handing it an already-newline-terminated string made
|
||||
// every MobileGL log occupy TWO logcat records, the second one empty. That
|
||||
// halved the useful depth of every `adb logcat -t N` window the CI
|
||||
// diagnostics read (android-plugin/trace-replay-ci.sh).
|
||||
__android_log_print(androidLogLevel, "MobileGL", "%.*s", static_cast<int>(out.size() - 1),
|
||||
out.c_str());
|
||||
#endif
|
||||
|
||||
WriteToFile(out.c_str());
|
||||
|
||||
@@ -9,10 +9,24 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
// Severity order, ascending. MOBILEGL_LOG_ACTIVE_LEVEL names the LOWEST severity that is
|
||||
// compiled in, so every level at or above it survives and everything below it becomes a
|
||||
// no-op: the production default INFO admits I/W/E/F and drops only D.
|
||||
//
|
||||
// This ordering was inverted until 2026-08-13 (DEBUG < WARN < ERROR < INFO < FATAL), which
|
||||
// silently compiled MGLOG_W and MGLOG_E out of every production and CI build and cost
|
||||
// several real diagnostic blackouts. Do not reorder without re-reading every
|
||||
// `#if MOBILEGL_LOG_ACTIVE_LEVEL <= ...` in the tree.
|
||||
//
|
||||
// These five constants are duplicated verbatim in Defines.h, which needs them for the
|
||||
// MOBILEGL_ASSERT gate in translation units that do not include Log.h. Keep both copies
|
||||
// in sync; the values are load-bearing, not cosmetic.
|
||||
#define MOBILEGL_LOG_LEVEL_DEBUG 0
|
||||
#define MOBILEGL_LOG_LEVEL_WARN 1
|
||||
#define MOBILEGL_LOG_LEVEL_ERROR 2
|
||||
#define MOBILEGL_LOG_LEVEL_INFO 3
|
||||
#define MOBILEGL_LOG_LEVEL_INFO 1
|
||||
#define MOBILEGL_LOG_LEVEL_WARN 2
|
||||
#define MOBILEGL_LOG_LEVEL_ERROR 3
|
||||
#define MOBILEGL_LOG_LEVEL_FATAL 4
|
||||
|
||||
#define MOBILEGL_LOG_INTERNAL(levelTag, androidLogLevel, fmt, ...) \
|
||||
@@ -20,6 +34,28 @@
|
||||
MobileGL::MG_Util::Debug::Log(levelTag, androidLogLevel, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
// Emit `inner` at most once per call site, for the life of the process.
|
||||
//
|
||||
// Production logging is not allowed to repeat: a diagnostic on a per-draw or per-frame
|
||||
// path costs frame time on every occurrence and buries the rest of the log. Anything at
|
||||
// W or E that sits on such a path must either be latched with one of the _ONCE forms
|
||||
// below or be demoted to MGLOG_D, which production compiles out entirely.
|
||||
//
|
||||
// The latch is a function-local atomic - zero-initialised before any dynamic
|
||||
// initialisation runs, so it is safe from any thread at any time, needs no guard
|
||||
// variable, and costs one relaxed test-and-set on the already-cold failure path. Note
|
||||
// that the latch is per CALL SITE, not per subject: a site that reports "texture %u is
|
||||
// unsupported" reports only the first such texture. That is the intended trade - the
|
||||
// first occurrence is what a user shares for troubleshooting, and MGLOG_D still shows
|
||||
// every occurrence in a dev build.
|
||||
#define MOBILEGL_LOG_ONCE_INTERNAL(inner, fmt, ...) \
|
||||
do { \
|
||||
static ::std::atomic_flag mobileglLogOnceLatch; \
|
||||
if (!mobileglLogOnceLatch.test_and_set(::std::memory_order_relaxed)) { \
|
||||
inner(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
#define MGLOG_D(fmt, ...) MOBILEGL_LOG_INTERNAL("DEBUG", ANDROID_LOG_DEBUG, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
@@ -55,6 +91,37 @@
|
||||
{}
|
||||
#endif
|
||||
|
||||
// One-shot forms. Each is gated on its own level so that a suppressed level leaves no
|
||||
// latch behind - MGLOG_D_ONCE in a production build is nothing at all, not a byte of
|
||||
// state plus a test-and-set.
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
#define MGLOG_D_ONCE(fmt, ...) MOBILEGL_LOG_ONCE_INTERNAL(MGLOG_D, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define MGLOG_D_ONCE(fmt, ...) \
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_INFO
|
||||
#define MGLOG_I_ONCE(fmt, ...) MOBILEGL_LOG_ONCE_INTERNAL(MGLOG_I, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define MGLOG_I_ONCE(fmt, ...) \
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_WARN
|
||||
#define MGLOG_W_ONCE(fmt, ...) MOBILEGL_LOG_ONCE_INTERNAL(MGLOG_W, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define MGLOG_W_ONCE(fmt, ...) \
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_ERROR
|
||||
#define MGLOG_E_ONCE(fmt, ...) MOBILEGL_LOG_ONCE_INTERNAL(MGLOG_E, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define MGLOG_E_ONCE(fmt, ...) \
|
||||
{}
|
||||
#endif
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
namespace Debug {
|
||||
|
||||
Reference in New Issue
Block a user