wip: (builds, dont run correctly)

- fixed logging api to match spdlog meaning
- spdlog handler impl
- more applied logging api usage
- source location
This commit is contained in:
Klaim (Joël Lamotte) 2025-07-16 14:36:35 +02:00 committed by Joël Lamotte (Klaim)
parent 716257ac2d
commit 20ba69a17f
18 changed files with 339 additions and 150 deletions

View File

@ -273,6 +273,8 @@ namespace mamba
void dump_backtrace_no_guards(); void dump_backtrace_no_guards();
void set_verbosity(int lvl); void set_verbosity(int lvl);
[[deprecated("Use `mamba::logging::set_log_level` instead")]]
void set_log_level(log_level level); void set_log_level(log_level level);
/// Setups the required core subsystems for `libmamba`'s high-level operations to work, /// Setups the required core subsystems for `libmamba`'s high-level operations to work,
@ -283,9 +285,9 @@ namespace mamba
/// @param log_handler /// @param log_handler
/// Log handler implementation to use once the logging system starts. /// Log handler implementation to use once the logging system starts.
/// Ignored if `options.enable_logging == false`. /// Ignored if `options.enable_logging == false`.
/// If `options.enable_logging == true and log_handler.has_value() == false`,\ /// If `options.enable_logging == true and log_handler.has_value() == false`,
/// which is the default if this parameter is not specified, /// which is the default if this parameter is not specified,
/// then a default implementation-defined log handler implementation will be installed. /// then a default implementation-defined log handler implementation will be used.
Context(const ContextOptions& options = {}, logging::AnyLogHandler log_handler = {}); Context(const ContextOptions& options = {}, logging::AnyLogHandler log_handler = {});
~Context(); ~Context();

View File

@ -17,6 +17,7 @@
#include <typeindex> #include <typeindex>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <source_location>
namespace mamba namespace mamba
{ {
@ -29,7 +30,10 @@ namespace mamba
warn, warn,
err, err,
critical, critical,
off
// Special values:
off,
all
}; };
struct LoggingParams struct LoggingParams
@ -42,17 +46,35 @@ namespace mamba
enum class log_source // "source" isnt the best way to put it, maybe channel? component? sink? enum class log_source // "source" isnt the best way to put it, maybe channel? component? sink?
{ {
libmamba, libmamba, // default
libcurl, libcurl,
libsolv libsolv
}; };
/// @returns The name of the specified log source as an UTF-8 null-terminated string. /// @returns The name of the specified log source as an UTF-8 null-terminated string.
constexpr auto name_of(log_source source) -> const char*; inline constexpr auto name_of(log_source source) -> const char*
{
switch (source)
{
case log_source::libmamba:
return "libmamba";
case log_source::libcurl:
return "libcurl";
case log_source::libsolv:
return "libsolv";
}
// TODO(c++23): std::unreachable();
assert(false);
return "unknown";
}
/// @returns All `log_source` values as a range. /// @returns All `log_source` values as a range.
constexpr auto all_log_sources() -> std::initializer_list<log_source>; inline constexpr auto all_log_sources() -> std::initializer_list<log_source>
{
return { log_source::libmamba, log_source::libcurl, log_source::libsolv };
}
namespace logging namespace logging
{ {
@ -62,13 +84,14 @@ namespace mamba
struct LogRecord struct LogRecord
{ {
std::string message; // THINK: cool be made lazy if it was a function instead std::string message; // THINK: could be made lazy if it was a function instead
log_level level; log_level level;
log_source source; log_source source;
std::source_location location;
}; };
// NOTE: it might make more sense to talka bout sinks than sources when it comes to the // NOTE: it might make more sense to talk about sinks than sources when it comes to the
// implementation // implementation
template <typename T> template <typename T>
@ -84,6 +107,8 @@ namespace mamba
{ {
// REQUIREMENT: all the following operations must be thread-safe // REQUIREMENT: all the following operations must be thread-safe
// TODO: how to make sure calls are noexcepts?
// //
handler.start_log_handling(params, sources); handler.start_log_handling(params, sources);
@ -99,23 +124,26 @@ namespace mamba
// //
handler.log(log_record); handler.log(log_record);
// log stacktrace in all sources // enable buffering a provided number of log records, dont log until `log_backtrace()` is called
handler.log_stacktrace(); handler.enable_backtrace(size_t(42));
// log stacktrace only in specific source // disable log buffering
handler.log_stacktrace(source); handler.disable_backtrace();
// log stacktrace in all sources // log buffered records
handler.log_stacktrace_no_guards(); handler.log_backtrace();
// log stacktrace only in specific source // log buffered records without filtering
handler.log_stacktrace_no_guards(source); handler.log_backtrace_no_guards();
// flush all sources // flush all sources
handler.flush(); handler.flush();
// flush only a specific source // flush only a specific source
handler.flush(std::optional<log_source>{}); handler.flush(std::optional<log_source>{});
// when a log's record is equal or higher than the specified level, flush
handler.set_flush_threshold(log_level::all);
}; };
template <typename T> template <typename T>
@ -173,16 +201,28 @@ namespace mamba
/// ///
/// Pre-condition: `has_value() == true` /// Pre-condition: `has_value() == true`
auto log_stacktrace(std::optional<log_source> source = {}) noexcept -> void; auto enable_backtrace(size_t record_buffer_size) -> void;
/// ///
/// Pre-condition: `has_value() == true` /// Pre-condition: `has_value() == true`
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) noexcept -> void; auto disable_backtrace() -> void;
///
/// Pre-condition: `has_value() == true`
auto log_backtrace() noexcept -> void;
///
/// Pre-condition: `has_value() == true`
auto log_backtrace_no_guards() noexcept -> void;
/// ///
/// Pre-condition: `has_value() == true` /// Pre-condition: `has_value() == true`
auto flush(std::optional<log_source> source = {}) noexcept -> void; auto flush(std::optional<log_source> source = {}) noexcept -> void;
///
/// Pre-condition: `has_value() == true`
auto set_flush_threshold(log_level threshold_level) noexcept -> void;
/// @returns `true` if there is an handler object stored in `this`, `false` otherwise. /// @returns `true` if there is an handler object stored in `this`, `false` otherwise.
auto has_value() const noexcept -> bool; auto has_value() const noexcept -> bool;
@ -212,6 +252,8 @@ namespace mamba
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Logging System API // Logging System API
// not thread-safe
auto stop_logging() -> AnyLogHandler;
// not thread-safe // not thread-safe
auto auto
@ -237,13 +279,24 @@ namespace mamba
auto log(LogRecord record) noexcept -> void; auto log(LogRecord record) noexcept -> void;
// as thread-safe as handler's implementation if set // as thread-safe as handler's implementation if set
auto log_stacktrace(std::optional<log_source> source = {}) noexcept -> void; auto enable_backtrace(size_t records_buffer_size) -> void;
// as thread-safe as handler's implementation if set
auto disable_backtrace() -> void;
// as thread-safe as handler's implementation if set
auto log_backtrace() noexcept -> void;
// as thread-safe as handler's implementation if set
auto log_backtrace_no_guards() noexcept -> void;
// as thread-safe as handler's implementation if set // as thread-safe as handler's implementation if set
auto flush_logs(std::optional<log_source> source = {}) noexcept -> void; auto flush_logs(std::optional<log_source> source = {}) noexcept -> void;
// as thread-safe as handler's implementation if set // as thread-safe as handler's implementation if set
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) noexcept -> void; auto set_flush_threshold(log_level threshold_level) noexcept -> void;
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// MIGT DISAPPEAR SOON // MIGT DISAPPEAR SOON
@ -251,7 +304,7 @@ namespace mamba
{ {
public: public:
MessageLogger(log_level level); MessageLogger(log_level level, std::source_location location = std::source_location::current());
~MessageLogger(); ~MessageLogger();
std::stringstream& stream() std::stringstream& stream()
@ -268,8 +321,9 @@ namespace mamba
log_level m_level; log_level m_level;
std::stringstream m_stream; std::stringstream m_stream;
std::source_location m_location;
static void emit(const std::string& msg, const log_level& level); static void emit(LogRecord log_record);
}; };
} }
} }
@ -298,31 +352,19 @@ namespace mamba::logging
{ {
// NOTE: the following definitions are inline for performance reasons. // NOTE: the following definitions are inline for performance reasons.
inline constexpr auto name_of(log_source source) -> const char* // not thread-safe
inline auto stop_logging() -> AnyLogHandler
{ {
switch (source) return set_log_handler({});
{
case log_source::libmamba:
return "libmamba";
case log_source::libcurl:
return "libcurl";
case log_source::libsolv:
return "libsolv";
}
// TODO(c++23): std::unreachable();
return "unknown";
} }
inline constexpr auto all_log_sources() -> std::initializer_list<log_source>
{
return { log_source::libmamba, log_source::libcurl, log_source::libsolv };
}
// TODO: find a better name? // TODO: find a better name?
template <typename Func, typename... Args> template <typename Func, typename... Args>
requires std::invocable<Func, AnyLogHandler&, Args...> requires std::invocable<Func, AnyLogHandler&, Args...>
auto call_log_handler_if_existing(Func&& func, Args&&... args) -> void auto call_log_handler_if_existing(Func&& func, Args&&... args)
noexcept(noexcept(std::invoke(std::forward<Func>(func), get_log_handler(), std::forward<Args>(args)...)))
-> void
{ {
// TODO: consider enabling for user to specify that no check is needed (one less branch) // TODO: consider enabling for user to specify that no check is needed (one less branch)
if (auto& log_handler = get_log_handler()) if (auto& log_handler = get_log_handler())
@ -337,10 +379,27 @@ namespace mamba::logging
call_log_handler_if_existing(&AnyLogHandler::log, std::move(record)); call_log_handler_if_existing(&AnyLogHandler::log, std::move(record));
} }
// as thread-safe as handler's implementation inline auto enable_backtrace(size_t records_buffer_size) -> void
inline auto log_stacktrace(std::optional<log_source> source) noexcept -> void
{ {
call_log_handler_if_existing(&AnyLogHandler::log_stacktrace, std::move(source)); call_log_handler_if_existing(&AnyLogHandler::enable_backtrace, records_buffer_size);
}
// as thread-safe as handler's implementation if set
inline auto disable_backtrace() -> void
{
call_log_handler_if_existing(&AnyLogHandler::disable_backtrace);
}
// as thread-safe as handler's implementation if set
inline auto log_backtrace() noexcept -> void
{
call_log_handler_if_existing(&AnyLogHandler::log_backtrace);
}
// as thread-safe as handler's implementation if set
inline auto log_backtrace_no_guards() noexcept -> void
{
call_log_handler_if_existing(&AnyLogHandler::log_backtrace_no_guards);
} }
// as thread-safe as handler's implementation // as thread-safe as handler's implementation
@ -349,12 +408,12 @@ namespace mamba::logging
call_log_handler_if_existing(&AnyLogHandler::flush, std::move(source)); call_log_handler_if_existing(&AnyLogHandler::flush, std::move(source));
} }
// as thread-safe as handler's implementation inline auto set_flush_threshold(log_level threshold_level) noexcept -> void
inline auto log_stacktrace_no_guards(std::optional<log_source> source) noexcept -> void
{ {
call_log_handler_if_existing(&AnyLogHandler::log_stacktrace_no_guards, std::move(source)); call_log_handler_if_existing(&AnyLogHandler::set_flush_threshold, threshold_level);
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -368,9 +427,12 @@ namespace mamba::logging
virtual void set_log_level(log_level new_level) = 0; virtual void set_log_level(log_level new_level) = 0;
virtual void set_params(LoggingParams new_params) = 0; virtual void set_params(LoggingParams new_params) = 0;
virtual void log(LogRecord record) noexcept = 0; virtual void log(LogRecord record) noexcept = 0;
virtual void log_stacktrace(std::optional<log_source> source) noexcept = 0; virtual void enable_backtrace(size_t record_buffer_size) = 0;
virtual void log_stacktrace_no_guards(std::optional<log_source> source) noexcept = 0; virtual void disable_backtrace() = 0;
virtual void log_backtrace() noexcept = 0;
virtual void log_backtrace_no_guards() noexcept = 0;
virtual void flush(std::optional<log_source> source) noexcept = 0; virtual void flush(std::optional<log_source> source) noexcept = 0;
virtual void set_flush_threshold(log_level threshold_level) noexcept = 0;
virtual std::type_index type_id() const = 0; virtual std::type_index type_id() const = 0;
}; };
@ -422,14 +484,24 @@ namespace mamba::logging
as_ref(object).log(std::move(record)); as_ref(object).log(std::move(record));
} }
void log_stacktrace(std::optional<log_source> source) noexcept override void enable_backtrace(size_t records_buffer_size) override
{ {
as_ref(object).log_stacktrace(std::move(source)); as_ref(object).enable_backtrace(records_buffer_size);
} }
void log_stacktrace_no_guards(std::optional<log_source> source) noexcept override void disable_backtrace() override
{ {
as_ref(object).log_stacktrace_no_guards(std::move(source)); as_ref(object).disable_backtrace();
}
void log_backtrace() noexcept override
{
as_ref(object).log_backtrace();
}
void log_backtrace_no_guards() noexcept override
{
as_ref(object).log_backtrace_no_guards();
} }
void flush(std::optional<log_source> source) noexcept override void flush(std::optional<log_source> source) noexcept override
@ -437,6 +509,12 @@ namespace mamba::logging
as_ref(object).flush(std::move(source)); as_ref(object).flush(std::move(source));
} }
void set_flush_threshold(log_level threshold_level) noexcept override
{
as_ref(object).set_flush_threshold(threshold_level);
}
std::type_index type_id() const override std::type_index type_id() const override
{ {
return typeid(object); return typeid(object);
@ -520,18 +598,28 @@ namespace mamba::logging
m_storage->log(std::move(record)); m_storage->log(std::move(record));
} }
inline auto AnyLogHandler::log_stacktrace(std::optional<log_source> source) noexcept -> void inline auto AnyLogHandler::enable_backtrace(size_t record_buffer_size) -> void
{ {
assert(m_storage); assert(m_storage);
m_storage->log_stacktrace_no_guards(std::move(source)); m_storage->enable_backtrace(record_buffer_size);
} }
inline auto inline auto AnyLogHandler::disable_backtrace() -> void
AnyLogHandler::log_stacktrace_no_guards(std::optional<log_source> source) noexcept
-> void
{ {
assert(m_storage); assert(m_storage);
m_storage->log_stacktrace_no_guards(std::move(source)); m_storage->disable_backtrace();
}
inline auto AnyLogHandler::log_backtrace() noexcept -> void
{
assert(m_storage);
m_storage->log_backtrace();
}
inline auto AnyLogHandler::log_backtrace_no_guards() noexcept -> void
{
assert(m_storage);
m_storage->log_backtrace_no_guards();
} }
inline auto AnyLogHandler::flush(std::optional<log_source> source) noexcept -> void inline auto AnyLogHandler::flush(std::optional<log_source> source) noexcept -> void
@ -540,6 +628,12 @@ namespace mamba::logging
m_storage->flush(std::move(source)); m_storage->flush(std::move(source));
} }
inline auto AnyLogHandler::set_flush_threshold(log_level threshold_level) noexcept -> void
{
assert(m_storage);
m_storage->set_flush_threshold(threshold_level);
}
inline auto AnyLogHandler::has_value() const noexcept -> bool inline auto AnyLogHandler::has_value() const noexcept -> bool
{ {
return m_storage ? true : false; return m_storage ? true : false;

View File

@ -8,18 +8,22 @@
#define MAMBA_CORE_LOGGING_SPDLOG_HPP #define MAMBA_CORE_LOGGING_SPDLOG_HPP
#include <memory> #include <memory>
#include <vector>
#include <mamba/core/tasksync.hpp>
#include <mamba/core/logging.hpp>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <mamba/core/logging.hpp>
namespace mamba namespace mamba
{ {
class TaskSynchronizer;
// THINK: add namespace? // THINK: add namespace?
inline auto convert_log_level(log_level l) -> spdlog::level::level_enum inline constexpr auto to_spdlog(log_level level) -> spdlog::level::level_enum
{ {
return static_cast<spdlog::level::level_enum>(l); static_assert(sizeof(log_level) == sizeof(spdlog::level::level_enum));
static_assert(static_cast<int>(log_level::all) == static_cast<int>(spdlog::level::level_enum::n_levels));
return static_cast<spdlog::level::level_enum>(level);
} }
class LogHandler_spdlog class LogHandler_spdlog
@ -40,15 +44,23 @@ namespace mamba
auto log(logging::LogRecord record) -> void; auto log(logging::LogRecord record) -> void;
auto log_stacktrace(std::optional<log_source> source = {}) -> void; auto enable_backtrace(size_t record_buffer_size) -> void;
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) -> void; auto disable_backtrace() -> void;
auto log_backtrace() noexcept -> void;
auto log_backtrace_no_guards() noexcept -> void;
auto flush(std::optional<log_source> source = {}) -> void; auto flush(std::optional<log_source> source = {}) -> void;
auto set_flush_threshold(log_level threshold_level) noexcept -> void;
private: private:
struct Impl; class ScopedLogger;
std::unique_ptr<Impl> pimpl; std::vector<ScopedLogger> loggers;
std::unique_ptr<TaskSynchronizer> tasksync = std::make_unique<TaskSynchronizer>();
// THINK: consider only using spdlog to get the loggers
auto default_logger() -> ScopedLogger&;
auto get_logger(log_source source) -> ScopedLogger&;
}; };
static_assert(logging::LogHandler<LogHandler_spdlog>); static_assert(logging::LogHandler<LogHandler_spdlog>);

View File

@ -17,7 +17,7 @@ namespace mamba
class ProgressBar; class ProgressBar;
struct ProgressBarOptions; struct ProgressBarOptions;
// TODO: find a way to define it here without // TODO: find a way to define it here without
// impoorting spdlog and modst of the STL. // importing spdlog and most of the STL.
class ProgressBarRepr; class ProgressBarRepr;
enum ProgressBarMode enum ProgressBarMode

View File

@ -11,11 +11,11 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#include <spdlog/spdlog.h>
#include "mamba/api/configuration.hpp" #include "mamba/api/configuration.hpp"
#include "mamba/api/install.hpp" #include "mamba/api/install.hpp"
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
#include "mamba/core/logging.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/package_fetcher.hpp" #include "mamba/core/package_fetcher.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
@ -2194,12 +2194,12 @@ namespace mamba
void Configuration::load() void Configuration::load()
{ {
spdlog::set_level(spdlog::level::n_levels); logging::set_log_level(log_level::all);
spdlog::flush_on(spdlog::level::n_levels); logging::set_flush_threshold(log_level::all);
// Hard-coded value assuming it's enough to store the logs emitted // Hard-coded value assuming it's enough to store the logs emitted
// before setting the log level, flushing the backtrace and setting // before setting the log level, flushing the backtrace and setting
// its new capacity // its new capacity
spdlog::enable_backtrace(500); logging::enable_backtrace(500);
LOG_DEBUG << "Loading configuration"; LOG_DEBUG << "Loading configuration";
@ -2229,19 +2229,19 @@ namespace mamba
exit(0); exit(0);
} }
m_context.set_log_level(m_context.output_params.logging_level); m_context.set_log_level(m_context.output_params.logging_level); // TODO remove that function from Context
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); }); logging::flush_logs();
spdlog::flush_on(spdlog::level::off); logging::set_flush_threshold(log_level::off);
m_context.dump_backtrace_no_guards(); m_context.dump_backtrace_no_guards();
if (m_context.output_params.log_backtrace > 0) if (m_context.output_params.log_backtrace > 0)
{ {
spdlog::enable_backtrace(m_context.output_params.log_backtrace); logging::enable_backtrace(m_context.output_params.log_backtrace);
} }
else else
{ {
spdlog::disable_backtrace(); logging::disable_backtrace();
} }
} }

View File

@ -54,7 +54,7 @@ namespace mamba
void Context::enable_logging(logging::AnyLogHandler log_handler) // THINK: change name? start_logging? void Context::enable_logging(logging::AnyLogHandler log_handler) // THINK: change name? start_logging?
{ {
if (not logging::get_log_handler()) if (not logging::get_log_handler()) // don't allow replacing one already set; THINK: OR DO WE ALLOW THAT????
{ {
if (log_handler) if (log_handler)
{ {
@ -111,7 +111,10 @@ namespace mamba
} }
} }
Context::~Context() = default; Context::~Context()
{
logging::stop_logging();
}
void Context::set_verbosity(int lvl) void Context::set_verbosity(int lvl)
{ {
@ -314,7 +317,7 @@ namespace mamba
void Context::dump_backtrace_no_guards() void Context::dump_backtrace_no_guards()
{ {
logging::log_stacktrace_no_guards(log_source::libmamba); logging::log_backtrace_no_guards();
} }
} // namespace mamba } // namespace mamba

View File

@ -4,7 +4,6 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include <spdlog/spdlog.h>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include "mamba/core/env_lockfile.hpp" #include "mamba/core/env_lockfile.hpp"

View File

@ -10,7 +10,7 @@ namespace mamba
{ {
if (ec == mamba_error_code::internal_failure) if (ec == mamba_error_code::internal_failure)
{ {
logging::log_stacktrace(); logging::log_backtrace();
} }
} }

View File

@ -17,9 +17,9 @@
namespace mamba::logging namespace mamba::logging
{ {
namespace // TODO: STATIC INIT FIASCO!!! namespace
{ {
constinit util::synchronized_value<LoggingParams> logging_params; constinit util::synchronized_value<LoggingParams, std::shared_mutex> logging_params;
// IMPRTANT NOTE: // IMPRTANT NOTE:
// The handler MUST NOT be protected from concurrent calls at this level // The handler MUST NOT be protected from concurrent calls at this level
@ -112,50 +112,61 @@ namespace mamba::logging
} }
} }
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
// MessageLogger // MessageLogger
namespace namespace
{ {
constinit std::atomic<bool> message_logger_use_buffer; constinit std::atomic<bool> message_logger_use_buffer;
using MessageLoggerBuffer = std::vector<std::pair<std::string, log_level>>; using MessageLoggerBuffer = std::vector<LogRecord>;
constinit util::synchronized_value<MessageLoggerBuffer> message_logger_buffer; constinit util::synchronized_value<MessageLoggerBuffer> message_logger_buffer;
auto make_safe_log_record(std::string_view message, log_level level, std::source_location location)
{
// THINK: maybe remove as much locals as possible to enable optimizations with
// temporaries
// TODO: use fmt or std::format to do the space prepend
const auto secured_message = Console::hide_secrets(message);
auto formatted_message = prepend(secured_message, "", std::string(4, ' ').c_str());
return LogRecord{
.message = std::move(formatted_message), //
.level = level, //
.source = log_source::libmamba, // default logging source, other sources will log
// through other mechanisms
.location = std::move(location) //
};
}
} }
MessageLogger::MessageLogger(log_level level) MessageLogger::MessageLogger(log_level level, std::source_location location)
: m_level(level) : m_level(level)
, m_location(std::move(location))
{ {
} }
MessageLogger::~MessageLogger() MessageLogger::~MessageLogger()
{ {
auto log_record = make_safe_log_record(m_stream.str(), m_level, std::move(m_location));
if (!message_logger_use_buffer && Console::is_available()) if (!message_logger_use_buffer && Console::is_available())
{ {
emit(m_stream.str(), m_level); emit(std::move(log_record));
} }
else else
{ {
message_logger_buffer->push_back({ m_stream.str(), m_level }); message_logger_buffer->push_back(log_record);
} }
} }
void MessageLogger::emit(const std::string& msg, const log_level& level) void MessageLogger::emit(LogRecord log_record)
{ {
// THINK: maybe remove as much locals as possible to enable optimizations with temporaries logging::log(std::move(log_record));
// TODO: use fmt or std::format to do the space prepend
const auto secured_message = Console::hide_secrets(msg);
const auto formatted_message = prepend(secured_message, "", std::string(4, ' ').c_str());
logging::log(LogRecord{
.message = formatted_message, //
.level = level, //
.source = log_source::libmamba //
});
if (level == log_level::critical and get_log_level() != log_level::off) if (log_record.level == log_level::critical and get_log_level() != log_level::off) // WARNING:
// THERE
// IS A LOCK HERE!
{ {
log_stacktrace(); log_backtrace();
} }
} }
@ -174,13 +185,11 @@ namespace mamba::logging
MessageLoggerBuffer tmp; MessageLoggerBuffer tmp;
message_logger_buffer->swap(tmp); message_logger_buffer->swap(tmp);
for (const auto& [msg, level] : tmp) for (auto& log_record : tmp)
{ {
emit(msg, level); emit(std::move(log_record));
} }
// TODO impl commented
/*spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); });*/
flush_logs(); flush_logs();
} }

View File

@ -67,7 +67,7 @@ namespace mamba
// Associate the registration of a logger to the lifetime of this object. // Associate the registration of a logger to the lifetime of this object.
// This is used to help with making sure loggers are unregistered once // This is used to help with making sure loggers are unregistered once
// their logical owner is destroyed. // their logical owner is destroyed.
class ScopedLogger class LogHandler_spdlog::ScopedLogger
{ {
std::shared_ptr<Logger> m_logger; std::shared_ptr<Logger> m_logger;
@ -108,41 +108,119 @@ namespace mamba
ScopedLogger& operator=(const ScopedLogger&) = delete; ScopedLogger& operator=(const ScopedLogger&) = delete;
}; };
struct LogHandler_spdlog::Impl
{
std::vector<ScopedLogger> loggers;
TaskSynchronizer tasksync;
};
LogHandler_spdlog::LogHandler_spdlog() = default; LogHandler_spdlog::LogHandler_spdlog() = default;
LogHandler_spdlog::~LogHandler_spdlog() = default; LogHandler_spdlog::~LogHandler_spdlog() = default;
LogHandler_spdlog::LogHandler_spdlog(LogHandler_spdlog&& other) = default;
LogHandler_spdlog& LogHandler_spdlog::operator=(LogHandler_spdlog&& other) = default;
auto LogHandler_spdlog::get_logger(log_source source) -> ScopedLogger&
{
// THINK: consider only using spdlog to get the loggers
const auto logger_idx = static_cast<size_t>(source);
assert(logger_idx > 0 && logger_idx < loggers.size());
auto& logger = loggers[logger_idx];
assert(logger.logger());
return logger;
}
auto LogHandler_spdlog::default_logger() -> ScopedLogger&
{
return get_logger(log_source::libmamba);
}
auto auto
LogHandler_spdlog::start_log_handling(const LoggingParams params, std::vector<log_source> sources) LogHandler_spdlog::start_log_handling(const LoggingParams params, std::vector<log_source> sources)
-> void -> void
{ {
pimpl = std::make_unique<Impl>(); assert(tasksync);
const auto main_source = sources.front(); const auto main_source = sources.front();
sources.pop_back(); sources.pop_back();
pimpl->loggers.emplace_back( loggers.emplace_back(
std::make_shared<Logger>(name_of(main_source), params.log_pattern, "\n"), std::make_shared<Logger>(name_of(main_source), params.log_pattern, "\n"),
logger_kind::default_logger logger_kind::default_logger
); );
MainExecutor::instance().on_close( MainExecutor::instance().on_close(
pimpl->tasksync.synchronized([this] { pimpl->loggers.front().logger()->flush(); }) tasksync->synchronized([this] { loggers.front().logger()->flush(); })
); );
for (const auto source : sources) for (const auto source : sources)
{ {
pimpl->loggers.emplace_back( loggers.emplace_back(std::make_shared<Logger>(name_of(source), params.log_pattern, ""));
std::make_shared<Logger>(name_of(source), params.log_pattern, "")
);
} }
spdlog::set_level(convert_log_level(params.logging_level)); spdlog::set_level(to_spdlog(params.logging_level));
} }
auto LogHandler_spdlog::stop_log_handling() -> void
{
loggers.clear();
spdlog::shutdown(); // ? or drop_all?
}
auto LogHandler_spdlog::set_log_level(log_level new_level) -> void
{
spdlog::set_level(to_spdlog(new_level));
}
auto LogHandler_spdlog::set_params(LoggingParams new_params) -> void
{
// TODO: add missing parameters
spdlog::set_level(to_spdlog(new_params.logging_level));
}
auto LogHandler_spdlog::log(const logging::LogRecord record) -> void
{
// THINK: consider only using spdlog to get the loggers
auto logger = get_logger(record.source).logger();
logger->log(
spdlog::source_loc{
record.location.file_name(),
static_cast<int>(record.location.line()), // CRINGE
record.location.function_name(),
},
to_spdlog(record.level),
record.message
);
}
auto LogHandler_spdlog::enable_backtrace(size_t record_buffer_size) -> void
{
spdlog::enable_backtrace(record_buffer_size);
}
auto LogHandler_spdlog::disable_backtrace() -> void
{
spdlog::disable_backtrace();
}
auto LogHandler_spdlog::log_backtrace() noexcept -> void
{
spdlog::dump_backtrace();
}
auto LogHandler_spdlog::log_backtrace_no_guards() noexcept -> void
{
default_logger().logger()->dump_backtrace_no_guards();
}
auto LogHandler_spdlog::set_flush_threshold(log_level threshold_level) noexcept -> void
{
spdlog::flush_on(to_spdlog(threshold_level));
}
auto LogHandler_spdlog::flush(std::optional<log_source> source) -> void
{
if (source)
{
get_logger(source.value()).logger()->flush(); // THINK: consider only using spdlog to get the loggers
}
else
{
spdlog::apply_all([](std::shared_ptr<spdlog::logger> l) { l->flush(); });
}
}
} }

View File

@ -29,7 +29,6 @@ extern "C"
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#include <spdlog/spdlog.h>
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/error_handling.hpp" #include "mamba/core/error_handling.hpp"

View File

@ -6,8 +6,7 @@
#include <functional> #include <functional>
#include <spdlog/spdlog.h> #include "mamba/core/logging.hpp"
#include "mamba/core/util.hpp" // for hide_secrets #include "mamba/core/util.hpp" // for hide_secrets
#include "mamba/fs/filesystem.hpp" // for fs::exists #include "mamba/fs/filesystem.hpp" // for fs::exists
#include "mamba/util/environment.hpp" #include "mamba/util/environment.hpp"
@ -69,9 +68,7 @@ namespace mamba::download
if (proxy) if (proxy)
{ {
curl_easy_setopt(handle, CURLOPT_PROXY, proxy->c_str()); curl_easy_setopt(handle, CURLOPT_PROXY, proxy->c_str());
// TODO LOG_INFO was used here instead; to be modified later following the new log LOG_INFO << fmt::format("Using Proxy {}", hide_secrets(*proxy));
// procedure (TBD)
spdlog::info("Using Proxy {}", hide_secrets(*proxy));
} }
if (ssl_verify.size()) if (ssl_verify.size())

View File

@ -4,8 +4,7 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include <spdlog/spdlog.h> #include "mamba/core/logging.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/util/string.hpp" #include "mamba/util/string.hpp"
#include "mamba/util/url.hpp" #include "mamba/util/url.hpp"
@ -124,8 +123,8 @@ namespace mamba::download
} }
catch (const nlohmann::detail::parse_error& e) catch (const nlohmann::detail::parse_error& e)
{ {
spdlog::error("Could not parse JSON\n{}", value); LOG_ERROR << fmt::format("Could not parse JSON\n{}", value);
spdlog::error("Error message: {}", e.what()); LOG_ERROR << fmt::format("Error message: {}", e.what());
return nl::json::object(); return nl::json::object();
} }
} }

View File

@ -12,7 +12,6 @@
#include <solv/evr.h> #include <solv/evr.h>
#include <solv/selection.h> #include <solv/selection.h>
#include <solv/solver.h> #include <solv/solver.h>
#include <spdlog/spdlog.h>
#include "mamba/fs/filesystem.hpp" #include "mamba/fs/filesystem.hpp"
#include "mamba/solver/libsolv/database.hpp" #include "mamba/solver/libsolv/database.hpp"

View File

@ -10,13 +10,12 @@
#include <catch2/catch_all.hpp> #include <catch2/catch_all.hpp>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#include "mamba/core/logging.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/util_scope.hpp" #include "mamba/core/util_scope.hpp"
#include "mamba/fs/filesystem.hpp" #include "mamba/fs/filesystem.hpp"
#include "spdlog/spdlog.h"
#ifdef _WIN32 #ifdef _WIN32
#include <io.h> #include <io.h>
@ -47,13 +46,13 @@ namespace mamba
p_tempdir = std::make_unique<TemporaryDirectory>(); p_tempdir = std::make_unique<TemporaryDirectory>();
tempdir_path = p_tempdir->path(); tempdir_path = p_tempdir->path();
spdlog::set_level(spdlog::level::trace); logging::set_log_level(log_level::trace);
} }
~LockDirTest() ~LockDirTest()
{ {
mamba::allow_file_locking(true); mamba::allow_file_locking(true);
spdlog::set_level(spdlog::level::info); logging::set_log_level(log_level::info);
} }
}; };
@ -206,12 +205,12 @@ namespace mamba
p_tempfile = std::make_unique<TemporaryFile>(); p_tempfile = std::make_unique<TemporaryFile>();
tempfile_path = p_tempfile->path(); tempfile_path = p_tempfile->path();
spdlog::set_level(spdlog::level::trace); logging::set_log_level(log_level::trace);
} }
~LockFileTest() ~LockFileTest()
{ {
spdlog::set_level(spdlog::level::info); logging::set_log_level(log_level::info);
} }
}; };

View File

@ -6,9 +6,9 @@
#include <catch2/catch_all.hpp> #include <catch2/catch_all.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/logging.hpp"
#include "mamba/util/encoding.hpp" #include "mamba/util/encoding.hpp"
#include "mamba/validation/tools.hpp" #include "mamba/validation/tools.hpp"
@ -49,7 +49,7 @@ namespace
REQUIRE(error == 0); REQUIRE(error == 0);
REQUIRE(pk_hex == hex_str(pk_bytes)); REQUIRE(pk_hex == hex_str(pk_bytes));
spdlog::set_level(spdlog::level::debug); logging::set_log_level(log_level::debug);
std::array<std::byte, 5> not_even_key; std::array<std::byte, 5> not_even_key;
pk_hex = hex_str(not_even_key); pk_hex = hex_str(not_even_key);
@ -63,7 +63,7 @@ namespace
REQUIRE(error == 0); REQUIRE(error == 0);
REQUIRE_FALSE(pk_hex == hex_str(pk_bytes)); REQUIRE_FALSE(pk_hex == hex_str(pk_bytes));
spdlog::set_level(spdlog::level::info); logging::set_log_level(log_level::info);
} }
TEST_CASE("ed25519_sig_hex_to_bytes") TEST_CASE("ed25519_sig_hex_to_bytes")
@ -80,7 +80,7 @@ namespace
REQUIRE(error == 0); REQUIRE(error == 0);
REQUIRE(sig_hex == hex_str(sig_bytes)); REQUIRE(sig_hex == hex_str(sig_bytes));
spdlog::set_level(spdlog::level::debug); logging::set_log_level(log_level::debug);
std::array<std::byte, 5> not_even_sig; std::array<std::byte, 5> not_even_sig;
sig_hex = hex_str(not_even_sig); sig_hex = hex_str(not_even_sig);
@ -94,7 +94,7 @@ namespace
REQUIRE(error == 0); REQUIRE(error == 0);
REQUIRE_FALSE(sig_hex == hex_str(sig_bytes)); REQUIRE_FALSE(sig_hex == hex_str(sig_bytes));
spdlog::set_level(spdlog::level::info); logging::set_log_level(log_level::info);
} }
} }
@ -132,20 +132,20 @@ namespace
TEST_CASE_METHOD(VerifyMsg, "wrong_signature") TEST_CASE_METHOD(VerifyMsg, "wrong_signature")
{ {
spdlog::set_level(spdlog::level::debug); logging::set_log_level(log_level::debug);
auto pk_hex = hex_str(pk); auto pk_hex = hex_str(pk);
REQUIRE(verify("Some text.", pk_hex, "signature_hex") == 0); REQUIRE(verify("Some text.", pk_hex, "signature_hex") == 0);
spdlog::set_level(spdlog::level::info); logging::set_log_level(log_level::info);
} }
TEST_CASE_METHOD(VerifyMsg, "wrong_public_key") TEST_CASE_METHOD(VerifyMsg, "wrong_public_key")
{ {
spdlog::set_level(spdlog::level::debug); logging::set_log_level(log_level::debug);
auto signature_hex = hex_str(signature); auto signature_hex = hex_str(signature);
REQUIRE(verify("Some text.", "pk_hex", signature_hex) == 0); REQUIRE(verify("Some text.", "pk_hex", signature_hex) == 0);
spdlog::set_level(spdlog::level::info); logging::set_log_level(log_level::info);
} }
} }

View File

@ -8,8 +8,8 @@
#include <catch2/catch_all.hpp> #include <catch2/catch_all.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include "mamba/core/logging.hpp"
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/util/encoding.hpp" #include "mamba/util/encoding.hpp"
@ -1188,12 +1188,12 @@ public:
write_role(key_mgr_json, channel_dir->path() / "key_mgr.json"); write_role(key_mgr_json, channel_dir->path() / "key_mgr.json");
write_role(pkg_mgr_json, channel_dir->path() / "pkg_mgr.json"); write_role(pkg_mgr_json, channel_dir->path() / "pkg_mgr.json");
spdlog::set_level(spdlog::level::debug); logging::set_log_level(log_level::debug);
} }
~RepoCheckerT() ~RepoCheckerT()
{ {
spdlog::set_level(spdlog::level::warn); logging::set_log_level(log_level::warn);
} }
protected: protected:

View File

@ -8,7 +8,6 @@
#include <catch2/catch_all.hpp> #include <catch2/catch_all.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"