aboutsummaryrefslogtreecommitdiffstats
path: root/core/logging.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-11-28 12:51:46 +0100
committerSven Gothel <[email protected]>2023-11-28 12:51:46 +0100
commit1aaf4f070011490bcece50394b9b32dfa593fd9e (patch)
tree17d68284e401a35eea3d3a574d986d446a60763a /core/logging.cpp
parent6e7cee4fa9a8af03f28ca26cd89f8357390dfc90 (diff)
parent571b546f35eead77ce109f8d4dd6c3de3199d573 (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'core/logging.cpp')
-rw-r--r--core/logging.cpp106
1 files changed, 93 insertions, 13 deletions
diff --git a/core/logging.cpp b/core/logging.cpp
index 34a95e5a..56ad0a0d 100644
--- a/core/logging.cpp
+++ b/core/logging.cpp
@@ -3,13 +3,17 @@
#include "logging.h"
+#include <cctype>
#include <cstdarg>
#include <cstdio>
+#include <cstring>
+#include <mutex>
+#include <optional>
#include <string>
+#include <vector>
#include "alspan.h"
#include "strutils.h"
-#include "vector.h"
#if defined(_WIN32)
@@ -19,22 +23,74 @@
#include <android/log.h>
#endif
-void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
+
+FILE *gLogFile{stderr};
+#ifdef _DEBUG
+LogLevel gLogLevel{LogLevel::Warning};
+#else
+LogLevel gLogLevel{LogLevel::Error};
+#endif
+
+
+namespace {
+
+enum class LogState : uint8_t {
+ FirstRun,
+ Ready,
+ Disable
+};
+
+std::mutex LogCallbackMutex;
+LogState gLogState{LogState::FirstRun};
+
+LogCallbackFunc gLogCallback{};
+void *gLogCallbackPtr{};
+
+constexpr std::optional<char> GetLevelCode(LogLevel level)
+{
+ switch(level)
+ {
+ case LogLevel::Disable: break;
+ case LogLevel::Error: return 'E';
+ case LogLevel::Warning: return 'W';
+ case LogLevel::Trace: return 'I';
+ }
+ return std::nullopt;
+}
+
+} // namespace
+
+void al_set_log_callback(LogCallbackFunc callback, void *userptr)
+{
+ auto cblock = std::lock_guard{LogCallbackMutex};
+ gLogCallback = callback;
+ gLogCallbackPtr = callback ? userptr : nullptr;
+ if(gLogState == LogState::FirstRun)
+ {
+ auto extlogopt = al::getenv("ALSOFT_DISABLE_LOG_CALLBACK");
+ if(!extlogopt || *extlogopt != "1")
+ gLogState = LogState::Ready;
+ else
+ gLogState = LogState::Disable;
+ }
+}
+
+void al_print(LogLevel level, const char *fmt, ...)
{
/* Kind of ugly since string literals are const char arrays with a size
* that includes the null terminator, which we want to exclude from the
* span.
*/
- auto prefix = al::as_span("[ALSOFT] (--) ").first<14>();
+ auto prefix = al::span{"[ALSOFT] (--) "}.first<14>();
switch(level)
{
case LogLevel::Disable: break;
- case LogLevel::Error: prefix = al::as_span("[ALSOFT] (EE) ").first<14>(); break;
- case LogLevel::Warning: prefix = al::as_span("[ALSOFT] (WW) ").first<14>(); break;
- case LogLevel::Trace: prefix = al::as_span("[ALSOFT] (II) ").first<14>(); break;
+ case LogLevel::Error: prefix = al::span{"[ALSOFT] (EE) "}.first<14>(); break;
+ case LogLevel::Warning: prefix = al::span{"[ALSOFT] (WW) "}.first<14>(); break;
+ case LogLevel::Trace: prefix = al::span{"[ALSOFT] (II) "}.first<14>(); break;
}
- al::vector<char> dynmsg;
+ std::vector<char> dynmsg;
std::array<char,256> stcmsg{};
char *str{stcmsg.data()};
@@ -45,21 +101,28 @@ void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
va_start(args, fmt);
va_copy(args2, args);
const int msglen{std::vsnprintf(msg.data(), msg.size(), fmt, args)};
- if(msglen >= 0 && static_cast<size_t>(msglen) >= msg.size()) UNLIKELY
+ if(msglen >= 0)
{
- dynmsg.resize(static_cast<size_t>(msglen)+prefix.size() + 1u);
+ if(static_cast<size_t>(msglen) >= msg.size()) UNLIKELY
+ {
+ dynmsg.resize(static_cast<size_t>(msglen)+prefix.size() + 1u);
- str = dynmsg.data();
- auto prefend2 = std::copy_n(prefix.begin(), prefix.size(), dynmsg.begin());
- msg = {prefend2, dynmsg.end()};
+ str = dynmsg.data();
+ auto prefend2 = std::copy_n(prefix.begin(), prefix.size(), dynmsg.begin());
+ msg = {prefend2, dynmsg.end()};
- std::vsnprintf(msg.data(), msg.size(), fmt, args2);
+ std::vsnprintf(msg.data(), msg.size(), fmt, args2);
+ }
+ msg = msg.first(static_cast<size_t>(msglen));
}
+ else
+ msg = {msg.data(), std::strlen(msg.data())};
va_end(args2);
va_end(args);
if(gLogLevel >= level)
{
+ auto logfile = gLogFile;
fputs(str, logfile);
fflush(logfile);
}
@@ -86,4 +149,21 @@ void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
};
__android_log_print(android_severity(level), "openal", "%s", str);
#endif
+
+ auto cblock = std::lock_guard{LogCallbackMutex};
+ if(gLogState != LogState::Disable)
+ {
+ while(!msg.empty() && std::isspace(msg.back()))
+ {
+ msg.back() = '\0';
+ msg = msg.first(msg.size()-1);
+ }
+ if(auto logcode = GetLevelCode(level); logcode && !msg.empty())
+ {
+ if(gLogCallback)
+ gLogCallback(gLogCallbackPtr, *logcode, msg.data(), static_cast<int>(msg.size()));
+ else if(gLogState == LogState::FirstRun)
+ gLogState = LogState::Disable;
+ }
+ }
}