aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sokol_log.h184
1 files changed, 176 insertions, 8 deletions
diff --git a/sokol_log.h b/sokol_log.h
index 50f5bdc0..3ea1dbba 100644
--- a/sokol_log.h
+++ b/sokol_log.h
@@ -27,7 +27,40 @@
SOKOL_DEBUG - by default this is defined if _DEBUG is defined
- FIXME: documentation
+
+ OVERVIEW
+ ========
+ sokol_log.h provides a default logging callback for other sokol headers.
+
+ To use the default log callback, just include sokol_log.h and provide
+ a function pointer to the 'slog_func' function when setting up the
+ sokol library:
+
+ For instance with sokol_audio.h:
+
+ #include "sokol_log.h"
+ ...
+ saudio_setup(&(saudio_desc){ .logger.func = slog_func });
+
+ Logging output goes to stderr and/or a platform specific logging subsystem:
+
+ - Windows: stderr + OutputDebugStringA()
+ - macOS/iOS/Linux: stderr + syslog()
+ - Emscripten: browser console
+ - Android: __android_log_write()
+
+ In debug mode, a log message might look like this:
+
+ [saudio] [error] /Users/floh/projects/sokol/sokol_audio.h:2422:0: COREAUDIO_NEW_OUTPUT_FAILED (id:32)
+
+ The source path and line number is formatted in like compiler errors, in some IDEs (like VSCode)
+ such error messages are clickable.
+
+ In release mode, logging is less verbose as to not bloat the executable with string data, but you still get
+ enough information to identify an error:
+
+ [saudio] [error] line:2422 id:32
+
LICENSE
=======
@@ -84,7 +117,7 @@ extern "C" {
}
});
*/
-void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, int line_nr, const char* filename, void* user_data);
+SOKOL_LOG_API_DECL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data);
#ifdef __cplusplus
} // extern "C"
@@ -130,7 +163,7 @@ void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const cha
// platform detection
#if defined(__APPLE__)
#define _SLOG_APPLE (1)
-#if defined(__EMSCRIPTEN__)
+#elif defined(__EMSCRIPTEN__)
#define _SLOG_EMSCRIPTEN (1)
#elif defined(_WIN32)
#define _SLOG_WINDOWS (1)
@@ -142,11 +175,10 @@ void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const cha
#error "sokol_log.h: unknown platform"
#endif
-#include <stdio.h>
+#include <stdio.h> // fputs
+#include <stddef.h> // size_t
-#if defined(_SLOG_APPLE)
-#include <os/log.h>
-#elif defined(_SLOG_WINDOWS)
+#if defined(_SLOG_WINDOWS)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
@@ -154,7 +186,143 @@ void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const cha
#define NOMINMAX
#endif
#include <windows.h>
+#elif defined(_SLOG_ANDROID)
+#include <android/log.h>
+#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
+#include <syslog.h>
+#endif
+_SOKOL_PRIVATE char* _slog_append(const char* str, char* dst, const char* end) {
+ if (str) {
+ char c;
+ while (((c = *str++) != 0) && (dst < (end - 1))) {
+ *dst++ = c;
+ }
+ }
+ *dst = 0;
+ return dst;
+}
+_SOKOL_PRIVATE char* _slog_itoa(uint32_t x, char* buf, size_t buf_size) {
+ const size_t max_digits_and_null = 11;
+ if (buf_size < max_digits_and_null) {
+ return 0;
+ }
+ char* p = buf + max_digits_and_null;
+ *--p = 0;
+ do {
+ *--p = '0' + (x % 10);
+ x /= 10;
+ } while (x != 0);
+ return p;
+}
-#endif // SOKOL_LOG_IMPL \ No newline at end of file
+#if defined(_SLOG_EMSCRIPTEN)
+EM_JS(void, slog_js_log, (uint32_t level, const char* c_str), {
+ const str = UTF8ToString(c_str);
+ switch (level) {
+ case 0: console.error(str); break;
+ case 1: console.error(str); break;
+ case 2: console.warn(str); break;
+ default: console.info(str); break;
+ }
+});
+#endif
+
+SOKOL_API_IMPL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data) {
+ _SOKOL_UNUSED(user_data);
+
+ const char* log_level_str;
+ switch (log_level) {
+ case 0: log_level_str = "panic"; break;
+ case 1: log_level_str = "error"; break;
+ case 2: log_level_str = "warning"; break;
+ default: log_level_str = "info"; break;
+ }
+
+ // build log output line
+ char line_buf[256];
+ char* str = &line_buf[0];
+ const char* end = str + sizeof(line_buf);
+ char num_buf[32];
+ if (tag) {
+ str = _slog_append("[", str, end);
+ str = _slog_append(tag, str, end);
+ str = _slog_append("] ", str, end);
+ }
+ str = _slog_append("[", str, end);
+ str = _slog_append(log_level_str, str, end);
+ str = _slog_append("] ", str, end);
+ // if a filename is provided, build a clickable log message that's compatible with compiler error messages
+ if (filename) {
+ #if defined(_MSC_VER)
+ // MSVC compiler error format
+ str = _slog_append(filename, str, end);
+ str = _slog_append("(", str, end);
+ str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
+ str = _slog_append("): ");
+ #else
+ // gcc/clang compiler error format
+ str = _slog_append(filename, str, end);
+ str = _slog_append(":", str, end);
+ str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
+ str = _slog_append(":0: ", str, end);
+ #endif
+ if (message) {
+ str = _slog_append(message, str, end);
+ str = _slog_append(" ", str, end);
+ }
+ else {
+ str = _slog_append("??? ", str, end);
+ }
+ str = _slog_append("(id:", str, end);
+ str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end);
+ str = _slog_append(")", str, end);
+ }
+ else {
+ // no filename provided, print what we can
+ str = _slog_append("line:", str, end);
+ str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
+ str = _slog_append(" id:", str, end);
+ str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end);
+ if (message) {
+ str = _slog_append(" msg: ", str, end);
+ str = _slog_append(message, str, end);
+ }
+ }
+ str = _slog_append("\n", str, end);
+
+ // print to stderr?
+ #if defined(_SLOG_LINUX) || defined(_SLOG_WINDOWS) || defined(_SLOG_APPLE)
+ fputs(line_buf, stderr);
+ #endif
+
+ // platform specific logging calls
+ #if defined(_SLOG_WINDOWS)
+ OutputDebugStringA(line_buf);
+ #elif defined(_SLOG_ANDROID)
+ int prio;
+ switch (log_level) {
+ case 0: prio = ANDROID_LOG_FATAL; break;
+ case 1: prio = ANDROID_LOG_ERROR; break;
+ case 2: prio = ANDROID_LOG_WARN; break;
+ default: prio = ANDROID_LOG_INFO; break;
+ }
+ __android_log_write(prio, "SOKOL", line_buf);
+ #elif defined(_SLOG_EMSCRIPTEN)
+ slog_js_log(log_level, line_buf);
+ #elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
+ int prio;
+ switch (log_level) {
+ case 0: prio = LOG_CRIT; break;
+ case 1: prio = LOG_ERR; break;
+ case 2: prio = LOG_WARNING; break;
+ default: prio = LOG_INFO; break;
+ }
+ syslog(prio, "%s", line_buf);
+ #endif
+ if (0 == log_level) {
+ abort();
+ }
+}
+#endif // SOKOL_LOG_IMPL