diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index 7aef6e20456..b87347ad0a1 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -47,6 +48,12 @@ namespace xamarin::android { // A slightly faster alternative to other log functions as it doesn't parse the message // for format placeholders nor it uses variable arguments void log_write (LogCategories category, LogLevel level, const char *message) noexcept; + void log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept; + void log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); + void log_debugf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_infof (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_warnf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_errorf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); [[gnu::always_inline]] static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept diff --git a/src/native/clr/shared/helpers.cc b/src/native/clr/shared/helpers.cc index 7850592af5a..5c95342b1af 100644 --- a/src/native/clr/shared/helpers.cc +++ b/src/native/clr/shared/helpers.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,11 +8,24 @@ using namespace xamarin::android; +[[noreturn]] void +Helpers::abort_applicationf (LogCategories category, std::source_location sloc, const char *format, ...) noexcept +{ + char *message = nullptr; + const char *safe_format = format == nullptr ? "" : format; + va_list args; + va_start (args, format); + int ret = vasprintf (&message, safe_format, args); + va_end (args); + + abort_application (category, ret < 0 ? safe_format : message, true, sloc); +} + [[noreturn]] void Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, "{}", message); + log_write (category, LogLevel::Fatal, message); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -33,9 +47,10 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo } } - log_fatal ( + log_writef ( category, - "Abort at {}:{}:{} ('{}')", + LogLevel::Fatal, + "Abort at %s:%u:%u ('%s')", file_name, sloc.line (), sloc.column (), diff --git a/src/native/clr/shared/log_functions.cc b/src/native/clr/shared/log_functions.cc index acd5e705c06..2f3db78abe7 100644 --- a/src/native/clr/shared/log_functions.cc +++ b/src/native/clr/shared/log_functions.cc @@ -55,6 +55,17 @@ namespace { }; constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1; + + [[gnu::always_inline]] + auto priority_for_level (LogLevel level) noexcept -> android_LogPriority + { + size_t map_index = static_cast(level); + if (map_index > loglevel_map_max_index) { + return DEFAULT_PRIORITY; + } + + return loglevel_map[map_index]; + } } unsigned int log_categories = LOG_NONE; @@ -117,15 +128,67 @@ namespace xamarin::android { void log_write (LogCategories category, LogLevel level, const char *message) noexcept { - size_t map_index = static_cast(level); - android_LogPriority priority; + __android_log_write (priority_for_level (level), category_name (category), message); + } - if (map_index > loglevel_map_max_index) { - priority = DEFAULT_PRIORITY; - } else { - priority = loglevel_map[map_index]; + void + log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept + { + const char *safe_format = format == nullptr ? "" : format; + __android_log_vprint (priority_for_level (level), category_name (category), safe_format, args); + } + + void + log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, level, format, args); + va_end (args); + } + + void + log_debugf (LogCategories category, const char *format, ...) noexcept + { + if ((log_categories & category) == 0) { + return; + } + + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Debug, format, args); + va_end (args); + } + + void + log_infof (LogCategories category, const char *format, ...) noexcept + { + if ((log_categories & category) == 0) { + return; } - __android_log_write (priority, category_name (category), message); + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Info, format, args); + va_end (args); } + + void + log_warnf (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Warn, format, args); + va_end (args); + } + + void + log_errorf (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Error, format, args); + va_end (args); + } + } diff --git a/src/native/common/include/shared/helpers.hh b/src/native/common/include/shared/helpers.hh index 22e29b40f25..f1ec1fb6ab4 100644 --- a/src/native/common/include/shared/helpers.hh +++ b/src/native/common/include/shared/helpers.hh @@ -56,6 +56,9 @@ namespace xamarin::android [[noreturn]] static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; + [[noreturn]] + static void abort_applicationf (LogCategories category, std::source_location sloc, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); + [[noreturn]] static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept { diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index 394ba2a1927..16e8eda7525 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -102,19 +103,81 @@ static constexpr android_LogPriority loglevel_map[] = { static constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1; +static auto +priority_for_level (xamarin::android::LogLevel level) noexcept -> android_LogPriority +{ + size_t map_index = static_cast(level); + if (map_index > loglevel_map_max_index) { + return DEFAULT_PRIORITY; + } + + return loglevel_map[map_index]; +} + namespace xamarin::android { void log_write (LogCategories category, LogLevel level, const char *message) noexcept { - size_t map_index = static_cast(level); - android_LogPriority priority; + __android_log_write (priority_for_level (level), CATEGORY_NAME (category), message); + } + + void + log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept + { + const char *safe_format = format == nullptr ? "" : format; + __android_log_vprint (priority_for_level (level), CATEGORY_NAME (category), safe_format, args); + } + + void + log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, level, format, args); + va_end (args); + } + + void + log_debugf (LogCategories category, const char *format, ...) noexcept + { + if ((log_categories & category) == 0) { + return; + } + + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Debug, format, args); + va_end (args); + } - if (map_index > loglevel_map_max_index) { - priority = DEFAULT_PRIORITY; - } else { - priority = loglevel_map[map_index]; + void + log_infof (LogCategories category, const char *format, ...) noexcept + { + if ((log_categories & category) == 0) { + return; } - __android_log_write (priority, CATEGORY_NAME (category), message); + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Info, format, args); + va_end (args); + } + + void + log_warnf (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Warn, format, args); + va_end (args); + } + + void + log_errorf (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Error, format, args); + va_end (args); } } diff --git a/src/native/mono/shared/log_types.hh b/src/native/mono/shared/log_types.hh index 0821ef59077..e476b82b1cd 100644 --- a/src/native/mono/shared/log_types.hh +++ b/src/native/mono/shared/log_types.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -47,6 +48,12 @@ namespace xamarin::android { // A slightly faster alternative to other log functions as it doesn't parse the message // for format placeholders nor it uses variable arguments void log_write (LogCategories category, LogLevel level, const char *message) noexcept; + void log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept; + void log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); + void log_debugf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_infof (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_warnf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_errorf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); [[gnu::always_inline]] static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept diff --git a/src/native/nativeaot/host/bridge-processing.cc b/src/native/nativeaot/host/bridge-processing.cc index b87a49b431b..eb636515d6f 100644 --- a/src/native/nativeaot/host/bridge-processing.cc +++ b/src/native/nativeaot/host/bridge-processing.cc @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -21,16 +19,12 @@ void BridgeProcessing::naot_initialize_on_runtime_init (JNIEnv *env) noexcept GCUserPeerable_jiClearManagedReferences = env->GetMethodID (GCUserPeerable_class, "jiClearManagedReferences", "()V"); if (GCUserPeerable_jiAddManagedReference == nullptr || GCUserPeerable_jiClearManagedReferences == nullptr) [[unlikely]] { - constexpr auto ABSENT = "absent"sv; - constexpr auto PRESENT = "present"sv; - - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_DEFAULT, - std::format ( - "Failed to find GCUserPeerable method(s): jiAddManagedReference ({}); jiClearManagedReferences ({})"sv, - GCUserPeerable_jiAddManagedReference == nullptr ? ABSENT : PRESENT, - GCUserPeerable_jiClearManagedReferences == nullptr ? ABSENT : PRESENT - ) + std::source_location::current (), + "Failed to find GCUserPeerable method(s): jiAddManagedReference (%s); jiClearManagedReferences (%s)", + GCUserPeerable_jiAddManagedReference == nullptr ? "absent" : "present", + GCUserPeerable_jiClearManagedReferences == nullptr ? "absent" : "present" ); } } diff --git a/src/native/nativeaot/host/host.cc b/src/native/nativeaot/host/host.cc index b6d87483c78..7258f963785 100644 --- a/src/native/nativeaot/host/host.cc +++ b/src/native/nativeaot/host/host.cc @@ -33,9 +33,9 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint if (__jni_on_load_handler_count > 0) { for (uint32_t i = 0; i < __jni_on_load_handler_count; i++) { - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Calling JNI on-load init func '{}' ({:p})", + "Calling JNI on-load init func '%s' (%p)", optional_string (__jni_on_load_handler_names[i]), reinterpret_cast(__jni_on_load_handlers[i]) );