mirror of https://github.com/mamba-org/mamba.git
Customizable `libmamba` logging implementation
- new logging system for users to plug-in a log handler which will receive log records from `libmamba` and do whatever appropriate logging impl they want with it (this is separate from the "console" output, only concerns logging); - provides a `spdlog`-based log handler, which should do what previous `libmamba` versions did; - `Context` can be initialized with a provided log handler; - By default, if no provided log handler and logging is enabled, `Context` will setup a `spdlog`-based log handler; (more to come: stdlib log handler, noop log handler, test log handler) Note that this is a stepping stone towards removing `spdlog` as dependency of `libmamba` (see also #3945)
This commit is contained in:
parent
d5c2a83932
commit
11641d374e
|
@ -229,6 +229,8 @@ set(
|
|||
${LIBMAMBA_SOURCE_DIR}/core/history.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/link.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/link.hpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/logging.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/logging_spdlog.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/menuinst.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/output.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/package_cache.cpp
|
||||
|
@ -377,6 +379,8 @@ set(
|
|||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/fsutil.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/history.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/invoke.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/logging.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/logging_spdlog.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/menuinst.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/output.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/package_cache.hpp
|
||||
|
|
|
@ -9,16 +9,7 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
enum class log_level
|
||||
{
|
||||
trace,
|
||||
debug,
|
||||
info,
|
||||
warn,
|
||||
err,
|
||||
critical,
|
||||
off
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
#include "mamba/core/common_types.hpp"
|
||||
#include "mamba/core/context_params.hpp"
|
||||
#include "mamba/core/logging.hpp"
|
||||
#include "mamba/core/palette.hpp"
|
||||
#include "mamba/core/subdir_parameters.hpp"
|
||||
#include "mamba/core/tasksync.hpp"
|
||||
#include "mamba/download/mirror_map.hpp"
|
||||
#include "mamba/download/parameters.hpp"
|
||||
#include "mamba/fs/filesystem.hpp"
|
||||
|
@ -68,6 +68,7 @@ namespace mamba
|
|||
{
|
||||
bool enable_logging = false;
|
||||
bool enable_signal_handling = false;
|
||||
logging::AnyLogHandler log_handler;
|
||||
};
|
||||
|
||||
// Context singleton class
|
||||
|
@ -77,16 +78,12 @@ namespace mamba
|
|||
|
||||
static void use_default_signal_handler(bool val);
|
||||
|
||||
struct OutputParams
|
||||
{
|
||||
int verbosity{ 0 };
|
||||
log_level logging_level{ log_level::warn };
|
||||
|
||||
|
||||
struct OutputParams : LoggingParams
|
||||
{
|
||||
bool json{ false };
|
||||
bool quiet{ false };
|
||||
|
||||
std::string log_pattern{ "%^%-9!l%-8n%$ %v" };
|
||||
std::size_t log_backtrace{ 0 };
|
||||
};
|
||||
|
||||
struct GraphicsParams
|
||||
|
@ -293,14 +290,6 @@ namespace mamba
|
|||
specs::AuthenticationDataBase m_authentication_info;
|
||||
bool m_authentication_infos_loaded = false;
|
||||
|
||||
class ScopedLogger;
|
||||
std::vector<ScopedLogger> loggers;
|
||||
|
||||
std::shared_ptr<Logger> main_logger();
|
||||
void add_logger(std::shared_ptr<Logger>);
|
||||
|
||||
TaskSynchronizer tasksync;
|
||||
|
||||
|
||||
// Enables the provided context setup signal handling.
|
||||
// This function must be called only for one Context in the lifetime of the program.
|
||||
|
@ -308,7 +297,7 @@ namespace mamba
|
|||
|
||||
// Enables the provided context to drive the logging system.
|
||||
// This function must be called only for one Context in the lifetime of the program.
|
||||
void enable_logging();
|
||||
void enable_logging(logging::AnyLogHandler log_handler);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/progress_bar.hpp"
|
||||
#include "mamba/core/package_fetcher.hpp"
|
||||
#include "mamba/download/downloader.hpp"
|
||||
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
// Copyright (c) 2025, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#ifndef MAMBA_CORE_LOGGING_HPP
|
||||
#define MAMBA_CORE_LOGGING_HPP
|
||||
|
||||
#include <concepts>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
enum class log_level
|
||||
{
|
||||
trace,
|
||||
debug,
|
||||
info,
|
||||
warn,
|
||||
err,
|
||||
critical,
|
||||
off
|
||||
};
|
||||
|
||||
struct LoggingParams
|
||||
{
|
||||
int verbosity{ 0 };
|
||||
log_level logging_level{ log_level::warn };
|
||||
std::string log_pattern{ "%^%-9!l%-8n%$ %v" }; // IS THIS SPECIFIC TO spdlog???
|
||||
std::size_t log_backtrace{ 0 };
|
||||
};
|
||||
|
||||
enum class log_source // "source" isnt the best way to put it, maybe channel? component? sink?
|
||||
{
|
||||
libmamba,
|
||||
libcurl,
|
||||
libsolv
|
||||
};
|
||||
|
||||
inline auto name_of(log_source source)
|
||||
{
|
||||
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();
|
||||
return "";
|
||||
}
|
||||
|
||||
inline auto all_log_sources() -> std::vector<log_source> // TODO: do better :|
|
||||
{
|
||||
return { log_source::libmamba, log_source::libcurl, log_source::libsolv };
|
||||
}
|
||||
|
||||
namespace logging
|
||||
{
|
||||
struct LogRecord
|
||||
{
|
||||
std::string message;
|
||||
log_level level;
|
||||
log_source source;
|
||||
};
|
||||
|
||||
|
||||
// NOTE: it might make more sense to talka bout sinks than sources when it comes to the
|
||||
// implementation
|
||||
|
||||
template <class T>
|
||||
concept LogHandler = std::equality_comparable<T> //
|
||||
&& requires(
|
||||
T& handler,
|
||||
const T& const_handler //
|
||||
,
|
||||
LoggingParams params,
|
||||
std::vector<log_source> sources,
|
||||
LogRecord log_record //
|
||||
,
|
||||
std::optional<log_source> source // no value means all sources
|
||||
) {
|
||||
handler.start_log_handling(params, sources); //
|
||||
handler.stop_log_handling(); //
|
||||
handler.set_log_level(params.logging_level); //
|
||||
handler.set_params(std::as_const(params)); //
|
||||
handler.log(log_record); //
|
||||
handler.log_stacktrace(); // log stacktrace in all sources
|
||||
handler.log_stacktrace(source); // log stacktrace only in
|
||||
// specific source
|
||||
handler.log_stacktrace_no_guards(); // log stacktrace in all
|
||||
// sources
|
||||
handler.log_stacktrace_no_guards(source); // log stacktrace
|
||||
// only in specific
|
||||
// source
|
||||
handler.flush(); // flush all
|
||||
handler.flush(std::optional<log_source>{}); // flush only a
|
||||
// specific source
|
||||
};
|
||||
|
||||
class AnyLogHandler
|
||||
{
|
||||
public:
|
||||
|
||||
AnyLogHandler();
|
||||
~AnyLogHandler();
|
||||
|
||||
template <class T>
|
||||
requires(not std::is_same_v<std::remove_cvref_t<T>, AnyLogHandler>) and LogHandler<T>
|
||||
AnyLogHandler(T&& handler);
|
||||
|
||||
template <class T>
|
||||
requires(not std::is_same_v<std::remove_cvref_t<T>, AnyLogHandler>) and LogHandler<T>
|
||||
AnyLogHandler(T* handler_ptr);
|
||||
|
||||
template <class T>
|
||||
requires(not std::is_same_v<std::remove_cvref_t<T>, AnyLogHandler>) and LogHandler<T>
|
||||
AnyLogHandler& operator=(T&& new_handler);
|
||||
|
||||
template <class T>
|
||||
requires(not std::is_same_v<std::remove_cvref_t<T>, AnyLogHandler>) and LogHandler<T>
|
||||
AnyLogHandler& operator=(T* new_handler_ptr);
|
||||
|
||||
auto start_log_handling(LoggingParams params, std::vector<log_source> sources) -> void;
|
||||
auto stop_log_handling() -> void;
|
||||
|
||||
auto set_log_level(log_level new_level) -> void;
|
||||
auto set_params(LoggingParams new_params) -> void;
|
||||
|
||||
auto log(LogRecord record) noexcept -> void;
|
||||
|
||||
auto log_stacktrace(std::optional<log_source> source = {}) noexcept -> void;
|
||||
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) noexcept -> void;
|
||||
auto flush(std::optional<log_source> source = {}) noexcept -> void;
|
||||
|
||||
auto operator==(const AnyLogHandler& other) const noexcept -> bool;
|
||||
|
||||
template <class T>
|
||||
requires(not std::is_same_v<std::remove_cvref_t<T>, AnyLogHandler>) and LogHandler<T>
|
||||
auto operator==(const T& other) const noexcept -> bool;
|
||||
|
||||
auto has_value() const noexcept -> bool;
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return has_value();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Interface
|
||||
{
|
||||
virtual ~Interface() = 0;
|
||||
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(LogHandler<AnyLogHandler>); // NEEDED? AnyLogHandler must not recursively
|
||||
// host itself
|
||||
|
||||
// not thread-safe
|
||||
auto set_log_handler(AnyLogHandler handler, std::optional<LoggingParams> maybe_params = {})
|
||||
-> AnyLogHandler;
|
||||
|
||||
// not thread-safe
|
||||
auto get_log_handler() -> const AnyLogHandler&;
|
||||
|
||||
// thread-safe
|
||||
auto set_log_level(log_level new_level) -> log_level;
|
||||
|
||||
// thread-safe, value immediately obsolete
|
||||
auto get_log_level() noexcept -> log_level;
|
||||
|
||||
// thread-safe, value immediately obsolete
|
||||
auto get_logging_params() noexcept -> LoggingParams;
|
||||
|
||||
// thread-safe
|
||||
auto set_logging_params(LoggingParams new_params);
|
||||
|
||||
// as thread-safe as handler's implementation
|
||||
auto log(LogRecord record) noexcept -> void;
|
||||
|
||||
// as thread-safe as handler's implementation
|
||||
auto log_stacktrace(std::optional<log_source> source = {}) noexcept -> void;
|
||||
|
||||
// as thread-safe as handler's implementation
|
||||
auto flush_logs(std::optional<log_source> source = {}) noexcept -> void;
|
||||
|
||||
// as thread-safe as handler's implementation
|
||||
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) noexcept -> void;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// MIGT DISAPPEAR SOON
|
||||
class MessageLogger
|
||||
{
|
||||
public:
|
||||
|
||||
MessageLogger(log_level level);
|
||||
~MessageLogger();
|
||||
|
||||
std::stringstream& stream()
|
||||
{
|
||||
// Keep this implementation inline for performance reasons.
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
static void activate_buffer();
|
||||
static void deactivate_buffer();
|
||||
static void print_buffer(std::ostream& ostream);
|
||||
|
||||
private:
|
||||
|
||||
log_level m_level;
|
||||
std::stringstream m_stream;
|
||||
|
||||
static void emit(const std::string& msg, const log_level& level);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG
|
||||
#undef LOG_TRACE
|
||||
#undef LOG_DEBUG
|
||||
#undef LOG_INFO
|
||||
#undef LOG_WARNING
|
||||
#undef LOG_ERROR
|
||||
#undef LOG_CRITICAL
|
||||
|
||||
#define LOG(severity) mamba::logging::MessageLogger(severity).stream()
|
||||
#define LOG_TRACE LOG(mamba::log_level::trace)
|
||||
#define LOG_DEBUG LOG(mamba::log_level::debug)
|
||||
#define LOG_INFO LOG(mamba::log_level::info)
|
||||
#define LOG_WARNING LOG(mamba::log_level::warn)
|
||||
#define LOG_ERROR LOG(mamba::log_level::err)
|
||||
#define LOG_CRITICAL LOG(mamba::log_level::critical)
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2025, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#ifndef MAMBA_CORE_LOGGING_SPDLOG_HPP
|
||||
#define MAMBA_CORE_LOGGING_SPDLOG_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <mamba/core/tasksync.hpp>
|
||||
#include <mamba/core/logging.hpp>
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
// THINK: add namespace?
|
||||
inline auto convert_log_level(log_level l) -> spdlog::level::level_enum
|
||||
{
|
||||
return static_cast<spdlog::level::level_enum>(l);
|
||||
}
|
||||
|
||||
class LogHandler_spdlog
|
||||
{
|
||||
public:
|
||||
|
||||
LogHandler_spdlog();
|
||||
~LogHandler_spdlog();
|
||||
|
||||
auto start_log_handling(LoggingParams params, std::vector<log_source> sources) -> void;
|
||||
auto stop_log_handling() -> void;
|
||||
|
||||
auto set_log_level(log_level new_level) -> void;
|
||||
auto set_params(LoggingParams new_params) -> void;
|
||||
|
||||
auto log(logging::LogRecord record) -> void;
|
||||
|
||||
auto log_stacktrace(std::optional<log_source> source = {}) -> void;
|
||||
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) -> void;
|
||||
auto flush(std::optional<log_source> source = {}) -> void;
|
||||
|
||||
auto operator==(const LogHandler_spdlog& other) const noexcept -> bool;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
};
|
||||
static_assert(logging::LogHandler<LogHandler_spdlog>);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -16,7 +16,7 @@
|
|||
#include <fmt/color.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "mamba/core/common_types.hpp"
|
||||
#include "mamba/core/logging.hpp"
|
||||
#include "mamba/core/progress_bar.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -166,43 +166,6 @@ namespace mamba
|
|||
static void clear_singleton();
|
||||
};
|
||||
|
||||
class MessageLogger
|
||||
{
|
||||
public:
|
||||
|
||||
MessageLogger(log_level level);
|
||||
~MessageLogger();
|
||||
|
||||
std::stringstream& stream();
|
||||
|
||||
static void activate_buffer();
|
||||
static void deactivate_buffer();
|
||||
static void print_buffer(std::ostream& ostream);
|
||||
|
||||
private:
|
||||
|
||||
log_level m_level;
|
||||
std::stringstream m_stream;
|
||||
|
||||
static void emit(const std::string& msg, const log_level& level);
|
||||
};
|
||||
|
||||
} // namespace mamba
|
||||
|
||||
#undef LOG
|
||||
#undef LOG_TRACE
|
||||
#undef LOG_DEBUG
|
||||
#undef LOG_INFO
|
||||
#undef LOG_WARNING
|
||||
#undef LOG_ERROR
|
||||
#undef LOG_CRITICAL
|
||||
|
||||
#define LOG(severity) mamba::MessageLogger(severity).stream()
|
||||
#define LOG_TRACE LOG(mamba::log_level::trace)
|
||||
#define LOG_DEBUG LOG(mamba::log_level::debug)
|
||||
#define LOG_INFO LOG(mamba::log_level::info)
|
||||
#define LOG_WARNING LOG(mamba::log_level::warn)
|
||||
#define LOG_ERROR LOG(mamba::log_level::err)
|
||||
#define LOG_CRITICAL LOG(mamba::log_level::critical)
|
||||
|
||||
#endif // MAMBA_CORE_OUTPUT_HPP
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "mamba/core/output.hpp"
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "mamba/core/logging.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mamba/core/activation.hpp"
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/shell_init.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/fs/filesystem.hpp"
|
||||
#include "mamba/util/path_manip.hpp"
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
// TODO includes to be removed after moving some functions/structs around
|
||||
#include "mamba/api/install.hpp" // other_pkg_mgr_spec
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/fs/filesystem.hpp"
|
||||
#include "mamba/util/environment.hpp"
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
|
||||
#include <fmt/ostream.h>
|
||||
#include <fmt/ranges.h>
|
||||
#include <spdlog/pattern_formatter.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/execution.hpp"
|
||||
#include "mamba/core/logging_spdlog.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/thread_utils.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
|
@ -28,99 +26,6 @@
|
|||
namespace mamba
|
||||
{
|
||||
|
||||
class Logger : public spdlog::logger
|
||||
{
|
||||
public:
|
||||
|
||||
Logger(const std::string& name, const std::string& pattern, const std::string& eol);
|
||||
|
||||
void dump_backtrace_no_guards();
|
||||
};
|
||||
|
||||
Logger::Logger(const std::string& name, const std::string& pattern, const std::string& eol)
|
||||
: spdlog::logger(name, std::make_shared<spdlog::sinks::stderr_color_sink_mt>())
|
||||
{
|
||||
auto f = std::make_unique<spdlog::pattern_formatter>(
|
||||
pattern,
|
||||
spdlog::pattern_time_type::local,
|
||||
eol
|
||||
);
|
||||
set_formatter(std::move(f));
|
||||
}
|
||||
|
||||
void Logger::dump_backtrace_no_guards()
|
||||
{
|
||||
using spdlog::details::log_msg;
|
||||
if (tracer_.enabled())
|
||||
{
|
||||
tracer_.foreach_pop(
|
||||
[this](const log_msg& msg)
|
||||
{
|
||||
if (this->should_log(msg.level))
|
||||
{
|
||||
this->sink_it_(msg);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class logger_kind
|
||||
{
|
||||
normal_logger,
|
||||
default_logger,
|
||||
};
|
||||
|
||||
// Associate the registration of a logger to the lifetime of this object.
|
||||
// This is used to help with making sure loggers are unregistered once
|
||||
// their logical owner is destroyed.
|
||||
class Context::ScopedLogger
|
||||
{
|
||||
std::shared_ptr<Logger> m_logger;
|
||||
|
||||
public:
|
||||
|
||||
explicit ScopedLogger(std::shared_ptr<Logger> new_logger, logger_kind kind = logger_kind::normal_logger)
|
||||
: m_logger(std::move(new_logger))
|
||||
{
|
||||
assert(m_logger);
|
||||
if (kind == logger_kind::default_logger)
|
||||
{
|
||||
spdlog::set_default_logger(m_logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::register_logger(m_logger);
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedLogger()
|
||||
{
|
||||
if (m_logger)
|
||||
{
|
||||
spdlog::drop(m_logger->name());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Logger> logger() const
|
||||
{
|
||||
assert(m_logger);
|
||||
return m_logger;
|
||||
}
|
||||
|
||||
ScopedLogger(ScopedLogger&&) = default;
|
||||
ScopedLogger& operator=(ScopedLogger&&) = default;
|
||||
|
||||
ScopedLogger(const ScopedLogger&) = delete;
|
||||
ScopedLogger& operator=(const ScopedLogger&) = delete;
|
||||
};
|
||||
|
||||
spdlog::level::level_enum convert_log_level(log_level l)
|
||||
{
|
||||
return static_cast<spdlog::level::level_enum>(l);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::atomic<bool> use_default_signal_handler_val{ true };
|
||||
|
@ -139,16 +44,6 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Logger> Context::main_logger()
|
||||
{
|
||||
if (loggers.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return loggers.front().logger();
|
||||
}
|
||||
|
||||
void Context::enable_signal_handling()
|
||||
{
|
||||
if (use_default_signal_handler_val)
|
||||
|
@ -157,22 +52,19 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
void Context::enable_logging()
|
||||
void Context::enable_logging(logging::AnyLogHandler log_handler) // THINK: change name? start_logging?
|
||||
{
|
||||
loggers.clear(); // Make sure we work with a known set of loggers, first one is
|
||||
// always the default one.
|
||||
|
||||
loggers.emplace_back(
|
||||
std::make_shared<Logger>("libmamba", output_params.log_pattern, "\n"),
|
||||
logger_kind::default_logger
|
||||
);
|
||||
MainExecutor::instance().on_close(tasksync.synchronized([&] { main_logger()->flush(); }));
|
||||
|
||||
loggers.emplace_back(std::make_shared<Logger>("libcurl", output_params.log_pattern, ""));
|
||||
|
||||
loggers.emplace_back(std::make_shared<Logger>("libsolv", output_params.log_pattern, ""));
|
||||
|
||||
spdlog::set_level(convert_log_level(output_params.logging_level));
|
||||
if (not logging::get_log_handler())
|
||||
{
|
||||
if (log_handler)
|
||||
{
|
||||
logging::set_log_handler(std::move(log_handler), output_params);
|
||||
}
|
||||
else
|
||||
{
|
||||
logging::set_log_handler(LogHandler_spdlog(), output_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context::Context(const ContextOptions& options)
|
||||
|
@ -215,7 +107,7 @@ namespace mamba
|
|||
|
||||
if (options.enable_logging)
|
||||
{
|
||||
enable_logging();
|
||||
enable_logging(options.log_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,13 +144,13 @@ namespace mamba
|
|||
this->output_params.logging_level = log_level::info;
|
||||
break;
|
||||
}
|
||||
spdlog::set_level(convert_log_level(output_params.logging_level));
|
||||
logging::set_log_level(output_params.logging_level);
|
||||
}
|
||||
|
||||
void Context::set_log_level(log_level level)
|
||||
{
|
||||
output_params.logging_level = level;
|
||||
spdlog::set_level(convert_log_level(level));
|
||||
logging::set_log_level(level);
|
||||
}
|
||||
|
||||
std::vector<std::string> Context::platforms() const
|
||||
|
@ -422,10 +314,7 @@ namespace mamba
|
|||
|
||||
void Context::dump_backtrace_no_guards()
|
||||
{
|
||||
if (main_logger()) // REVIEW: is this correct?
|
||||
{
|
||||
main_logger()->dump_backtrace_no_guards();
|
||||
}
|
||||
logging::log_stacktrace_no_guards(log_source::libmamba);
|
||||
}
|
||||
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "mamba/core/download_progress_bar.hpp"
|
||||
|
||||
#include "mamba/core/output.hpp"
|
||||
|
||||
#include "progress_bar_impl.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "mamba/core/error_handling.hpp"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "mamba/core/logging.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ namespace mamba
|
|||
{
|
||||
if (ec == mamba_error_code::internal_failure)
|
||||
{
|
||||
spdlog::dump_backtrace();
|
||||
logging::log_stacktrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright (c) 2025, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <mamba/core/context.hpp>
|
||||
#include <mamba/core/error_handling.hpp>
|
||||
#include <mamba/core/execution.hpp>
|
||||
#include <mamba/core/logging.hpp>
|
||||
#include <mamba/core/output.hpp> // TODO: remove
|
||||
#include <mamba/core/util.hpp>
|
||||
#include <mamba/util/synchronized_value.hpp>
|
||||
|
||||
namespace mamba::logging
|
||||
{
|
||||
namespace // TODO: STATIC INIT FIASCO!!!
|
||||
{
|
||||
util::synchronized_value<LoggingParams> logging_params;
|
||||
|
||||
// IMPRTANT NOTE:
|
||||
// The handler MUST NOT be protected from concurrent calls at this level
|
||||
// as that would add high performance cost to logging from multiple threads.
|
||||
// Instead, we expect the implementation to handle concurrent calls correctly
|
||||
// in a thread-safe manner which is appropriate for this implementation.
|
||||
//
|
||||
// There are many ways to implement such handlers, including with a mutex,
|
||||
// various mutex types, through a concurrent lock-free queue of logging record feeding
|
||||
// a specific thread responsible for the output and file writing, etc.
|
||||
// There are too many ways that we can't predict and each impl will have it's own
|
||||
// best strategy.
|
||||
//
|
||||
// So instead of protecting at this level, we require the implementation of the handler
|
||||
// to be thread-safe, whatever the means. We can't enforce that property and can only
|
||||
// require it with the documentation which should guide the implementers anyway.
|
||||
AnyLogHandler current_log_handler;
|
||||
|
||||
|
||||
// FIXME: maybe generalize and move in synchronized_value.hpp
|
||||
template<std::default_initializable T, typename U, typename... OtherArgs>
|
||||
requires std::assignable_from<T&, U>
|
||||
auto
|
||||
synchronize_with_value(util::synchronized_value<T, OtherArgs...>& sv, const std::optional<U>& new_value)
|
||||
{
|
||||
auto synched_value = sv.synchronize();
|
||||
if (new_value)
|
||||
{
|
||||
*synched_value = *new_value;
|
||||
}
|
||||
return synched_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto set_log_handler(AnyLogHandler new_handler, std::optional<LoggingParams> maybe_params)
|
||||
-> AnyLogHandler
|
||||
{
|
||||
if (current_log_handler)
|
||||
{
|
||||
current_log_handler.stop_log_handling();
|
||||
}
|
||||
|
||||
|
||||
auto previous_handler = std::exchange(current_log_handler, std::move(new_handler));
|
||||
|
||||
auto params = synchronize_with_value(logging_params, maybe_params);
|
||||
|
||||
if (current_log_handler)
|
||||
{
|
||||
current_log_handler.start_log_handling(*params, all_log_sources());
|
||||
}
|
||||
}
|
||||
|
||||
auto get_log_handler() -> const AnyLogHandler&
|
||||
{
|
||||
return current_log_handler;
|
||||
}
|
||||
|
||||
auto set_log_level(log_level new_level) -> log_level
|
||||
{
|
||||
auto synched_params = logging_params.synchronize();
|
||||
const auto previous_level = synched_params->logging_level;
|
||||
synched_params->logging_level = new_level;
|
||||
current_log_handler.set_log_level(synched_params->logging_level);
|
||||
return previous_level;
|
||||
}
|
||||
|
||||
auto get_log_level() noexcept -> log_level
|
||||
{
|
||||
return logging_params->logging_level;
|
||||
}
|
||||
|
||||
auto get_logging_params() noexcept -> LoggingParams
|
||||
{
|
||||
return logging_params.value();
|
||||
}
|
||||
|
||||
auto set_logging_params(LoggingParams new_params)
|
||||
{
|
||||
logging_params = std::move(new_params);
|
||||
}
|
||||
|
||||
auto log(LogRecord record) noexcept -> void
|
||||
{
|
||||
current_log_handler.log(std::move(record));
|
||||
}
|
||||
|
||||
auto log_stacktrace(std::optional<log_source> source) noexcept -> void
|
||||
{
|
||||
current_log_handler.log_stacktrace(std::move(source));
|
||||
}
|
||||
|
||||
auto flush_logs(std::optional<log_source> source) noexcept -> void
|
||||
{
|
||||
current_log_handler.flush(std::move(source));
|
||||
}
|
||||
|
||||
auto log_stacktrace_no_guards(std::optional<log_source> source) noexcept -> void
|
||||
{
|
||||
current_log_handler.log_stacktrace_no_guards(std::move(source));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// AnyLogHandler
|
||||
|
||||
AnyLogHandler::AnyLogHandler() = default;
|
||||
AnyLogHandler::~AnyLogHandler() = default;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// MessageLogger
|
||||
|
||||
struct MessageLoggerData
|
||||
{
|
||||
static std::mutex m_mutex;
|
||||
static bool use_buffer;
|
||||
static std::vector<std::pair<std::string, log_level>> m_buffer;
|
||||
};
|
||||
|
||||
MessageLogger::MessageLogger(log_level level)
|
||||
: m_level(level)
|
||||
{
|
||||
}
|
||||
|
||||
MessageLogger::~MessageLogger()
|
||||
{
|
||||
if (!MessageLoggerData::use_buffer && Console::is_available())
|
||||
{
|
||||
emit(m_stream.str(), m_level);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex);
|
||||
MessageLoggerData::m_buffer.push_back({ m_stream.str(), m_level });
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogger::emit(const std::string& msg, const log_level& level)
|
||||
{
|
||||
// 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(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)
|
||||
{
|
||||
log_stacktrace();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogger::activate_buffer()
|
||||
{
|
||||
MessageLoggerData::use_buffer = true;
|
||||
}
|
||||
|
||||
void MessageLogger::deactivate_buffer()
|
||||
{
|
||||
MessageLoggerData::use_buffer = false;
|
||||
}
|
||||
|
||||
void MessageLogger::print_buffer(std::ostream& /*ostream*/)
|
||||
{
|
||||
decltype(MessageLoggerData::m_buffer) tmp;
|
||||
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex);
|
||||
MessageLoggerData::m_buffer.swap(tmp);
|
||||
}
|
||||
|
||||
for (const auto& [msg, level] : tmp)
|
||||
{
|
||||
emit(msg, level);
|
||||
}
|
||||
|
||||
// TODO impl commented
|
||||
/*spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); });*/
|
||||
flush_logs();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright (c) 2025, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
#include <mamba/core/logging_spdlog.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include <mamba/core/context.hpp>
|
||||
#include <mamba/core/output.hpp> // TODO: remove
|
||||
#include <mamba/core/util.hpp>
|
||||
#include <mamba/core/execution.hpp>
|
||||
#include <mamba/core/tasksync.hpp>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
// FIXME: merge scoped logger with this type, they are the samem, scopepd logger as introduced to patch logger
|
||||
class Logger : public spdlog::logger
|
||||
{
|
||||
public:
|
||||
|
||||
Logger(const std::string& name, const std::string& pattern, const std::string& eol);
|
||||
|
||||
void dump_backtrace_no_guards();
|
||||
};
|
||||
|
||||
Logger::Logger(
|
||||
const std::string& name,
|
||||
const std::string& pattern,
|
||||
const std::string& eol
|
||||
)
|
||||
: spdlog::logger(name, std::make_shared<spdlog::sinks::stderr_color_sink_mt>())
|
||||
{
|
||||
auto f = std::make_unique<spdlog::pattern_formatter>(
|
||||
pattern,
|
||||
spdlog::pattern_time_type::local,
|
||||
eol
|
||||
);
|
||||
set_formatter(std::move(f));
|
||||
}
|
||||
|
||||
void Logger::dump_backtrace_no_guards()
|
||||
{
|
||||
using spdlog::details::log_msg;
|
||||
if (tracer_.enabled())
|
||||
{
|
||||
tracer_.foreach_pop(
|
||||
[this](const log_msg& msg)
|
||||
{
|
||||
if (this->should_log(msg.level))
|
||||
{
|
||||
this->sink_it_(msg);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class logger_kind
|
||||
{
|
||||
normal_logger,
|
||||
default_logger,
|
||||
};
|
||||
|
||||
// Associate the registration of a logger to the lifetime of this object.
|
||||
// This is used to help with making sure loggers are unregistered once
|
||||
// their logical owner is destroyed.
|
||||
class ScopedLogger
|
||||
{
|
||||
std::shared_ptr<Logger> m_logger;
|
||||
|
||||
public:
|
||||
|
||||
explicit ScopedLogger(
|
||||
std::shared_ptr<Logger> new_logger,
|
||||
logger_kind kind = logger_kind::normal_logger
|
||||
)
|
||||
: m_logger(std::move(new_logger))
|
||||
{
|
||||
assert(m_logger);
|
||||
if (kind == logger_kind::default_logger)
|
||||
{
|
||||
spdlog::set_default_logger(m_logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::register_logger(m_logger);
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedLogger()
|
||||
{
|
||||
if (m_logger)
|
||||
{
|
||||
spdlog::drop(m_logger->name());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Logger> logger() const
|
||||
{
|
||||
assert(m_logger);
|
||||
return m_logger;
|
||||
}
|
||||
|
||||
ScopedLogger(ScopedLogger&&) = default;
|
||||
ScopedLogger& operator=(ScopedLogger&&) = default;
|
||||
|
||||
ScopedLogger(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;
|
||||
|
||||
|
||||
auto LogHandler_spdlog::start_log_handling(const LoggingParams params, std::vector<log_source> sources) -> void
|
||||
{
|
||||
pimpl = std::make_unique<Impl>();
|
||||
|
||||
const auto main_source = sources.front();
|
||||
sources.pop_back();
|
||||
|
||||
pimpl->loggers.emplace_back(
|
||||
std::make_shared<Logger>(name_of(main_source), params.log_pattern, "\n"),
|
||||
logger_kind::default_logger
|
||||
);
|
||||
MainExecutor::instance().on_close(
|
||||
pimpl->tasksync.synchronized([this] { pimpl->loggers.front().logger()->flush(); })
|
||||
);
|
||||
|
||||
for (const auto source : sources)
|
||||
{
|
||||
pimpl->loggers.emplace_back(
|
||||
std::make_shared<Logger>(name_of(source), params.log_pattern, "")
|
||||
);
|
||||
}
|
||||
|
||||
spdlog::set_level(convert_log_level(params.logging_level));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2019, QuantStack and Mamba Contributors
|
||||
// Copyright (c) 2019-2025, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
|
@ -466,9 +466,9 @@ namespace mamba
|
|||
{
|
||||
auto new_progress_bar_manager = make_progress_bar_manager(mode);
|
||||
new_progress_bar_manager->register_print_hook(Console::print_buffer);
|
||||
new_progress_bar_manager->register_print_hook(MessageLogger::print_buffer);
|
||||
new_progress_bar_manager->register_pre_start_hook(MessageLogger::activate_buffer);
|
||||
new_progress_bar_manager->register_post_stop_hook(MessageLogger::deactivate_buffer);
|
||||
new_progress_bar_manager->register_print_hook(logging::MessageLogger::print_buffer);
|
||||
new_progress_bar_manager->register_pre_start_hook(logging::MessageLogger::activate_buffer);
|
||||
new_progress_bar_manager->register_post_stop_hook(logging::MessageLogger::deactivate_buffer);
|
||||
|
||||
auto synched_data = p_data->m_synched_data.synchronize();
|
||||
synched_data->progress_bar_manager = std::move(new_progress_bar_manager);
|
||||
|
@ -553,92 +553,4 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
/*****************
|
||||
* MessageLogger *
|
||||
*****************/
|
||||
|
||||
static std::atomic<bool> message_logger_use_buffer;
|
||||
|
||||
using MessageLoggerBuffer = std::vector<std::pair<std::string, log_level>>;
|
||||
static util::synchronized_value<MessageLoggerBuffer> message_logger_buffer;
|
||||
|
||||
MessageLogger::MessageLogger(log_level level)
|
||||
: m_level(level)
|
||||
, m_stream()
|
||||
{
|
||||
}
|
||||
|
||||
MessageLogger::~MessageLogger()
|
||||
{
|
||||
if (!message_logger_use_buffer && Console::is_available())
|
||||
{
|
||||
emit(m_stream.str(), m_level);
|
||||
}
|
||||
else
|
||||
{
|
||||
message_logger_buffer->push_back({ m_stream.str(), m_level });
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogger::emit(const std::string& msg, const log_level& level)
|
||||
{
|
||||
auto str = Console::hide_secrets(msg);
|
||||
switch (level)
|
||||
{
|
||||
case log_level::critical:
|
||||
SPDLOG_CRITICAL(prepend(str, "", std::string(4, ' ').c_str()));
|
||||
if (Console::instance().context().output_params.logging_level != log_level::off)
|
||||
{
|
||||
spdlog::dump_backtrace();
|
||||
}
|
||||
break;
|
||||
case log_level::err:
|
||||
SPDLOG_ERROR(prepend(str, "", std::string(4, ' ').c_str()));
|
||||
break;
|
||||
case log_level::warn:
|
||||
SPDLOG_WARN(prepend(str, "", std::string(4, ' ').c_str()));
|
||||
break;
|
||||
case log_level::info:
|
||||
SPDLOG_INFO(prepend(str, "", std::string(4, ' ').c_str()));
|
||||
break;
|
||||
case log_level::debug:
|
||||
SPDLOG_DEBUG(prepend(str, "", std::string(4, ' ').c_str()));
|
||||
break;
|
||||
case log_level::trace:
|
||||
SPDLOG_TRACE(prepend(str, "", std::string(4, ' ').c_str()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream& MessageLogger::stream()
|
||||
{
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
void MessageLogger::activate_buffer()
|
||||
{
|
||||
message_logger_use_buffer = true;
|
||||
}
|
||||
|
||||
void MessageLogger::deactivate_buffer()
|
||||
{
|
||||
message_logger_use_buffer = false;
|
||||
}
|
||||
|
||||
void MessageLogger::print_buffer(std::ostream& /*ostream*/)
|
||||
{
|
||||
MessageLoggerBuffer tmp;
|
||||
message_logger_buffer->swap(tmp);
|
||||
|
||||
for (const auto& [msg, level] : tmp)
|
||||
{
|
||||
emit(msg, level);
|
||||
}
|
||||
|
||||
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); });
|
||||
}
|
||||
|
||||
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "mamba/core/logging.hpp"
|
||||
#include "mamba/util/string.hpp"
|
||||
|
||||
#include "compression.hpp"
|
||||
|
@ -77,9 +76,7 @@ namespace mamba::download
|
|||
auto ret = ZSTD_decompressStream(p_stream, &output, &input);
|
||||
if (ZSTD_isError(ret))
|
||||
{
|
||||
// This is temporary...
|
||||
// TODO Remove dependency on spdlog after deciding on what to do with logging
|
||||
spdlog::error("ZSTD decompression error: {}", ZSTD_getErrorName(ret));
|
||||
LOG_ERROR << fmt::format("ZSTD decompression error: {}", ZSTD_getErrorName(ret));
|
||||
return size + 1;
|
||||
}
|
||||
if (output.pos > 0)
|
||||
|
@ -151,9 +148,7 @@ namespace mamba::download
|
|||
int ret = BZ2_bzDecompress(&m_stream);
|
||||
if (ret != BZ_OK && ret != BZ_STREAM_END)
|
||||
{
|
||||
// This is temporary...
|
||||
// TODO Remove dependency on spdlog after deciding on what to do with logging
|
||||
spdlog::error("Bzip2 decompression error: {}", ret);
|
||||
LOG_ERROR << fmt::format("Bzip2 decompression error: {}", ret);
|
||||
return size + 1;
|
||||
}
|
||||
|
||||
|
@ -236,9 +231,7 @@ namespace mamba::download
|
|||
auto ret = ZSTD_decompressStream(stream, &output, &input);
|
||||
if (ZSTD_isError(ret))
|
||||
{
|
||||
// This is temporary...
|
||||
// TODO Remove dependency on spdlog after deciding on what to do with logging
|
||||
spdlog::error("ZSTD decompression error: {}", ZSTD_getErrorName(ret));
|
||||
LOG_ERROR << fmt::format("ZSTD decompression error: {}", ZSTD_getErrorName(ret));
|
||||
return size + 1;
|
||||
}
|
||||
if (output.pos > 0)
|
||||
|
@ -268,9 +261,7 @@ namespace mamba::download
|
|||
int ret = BZ2_bzDecompress(stream);
|
||||
if (ret != BZ_OK && ret != BZ_STREAM_END)
|
||||
{
|
||||
// This is temporary...
|
||||
// TODO Remove dependency on spdlog after deciding on what to do with logging
|
||||
spdlog::error("Bzip2 decompression error: {}", ret);
|
||||
LOG_ERROR << fmt::format("Bzip2 decompression error: {}", ret);
|
||||
return size + 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -288,24 +288,36 @@ namespace mamba::download
|
|||
namespace
|
||||
{
|
||||
int
|
||||
curl_debug_callback(CURL* /* handle */, curl_infotype type, char* data, size_t size, void* userptr)
|
||||
curl_debug_callback(CURL* /* handle */, curl_infotype type, char* data, size_t size, void*)
|
||||
{
|
||||
auto* logger = reinterpret_cast<spdlog::logger*>(userptr);
|
||||
std::string log;
|
||||
static constexpr auto symbol_for = [](curl_infotype type) {
|
||||
switch (type)
|
||||
{
|
||||
case CURLINFO_TEXT:
|
||||
return "*";
|
||||
case CURLINFO_HEADER_OUT:
|
||||
return ">";
|
||||
case CURLINFO_HEADER_IN:
|
||||
return "<";
|
||||
default:
|
||||
return "";
|
||||
};
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CURLINFO_TEXT:
|
||||
log = Console::hide_secrets(std::string_view(data, size));
|
||||
logger->info(fmt::format("* {}", log));
|
||||
break;
|
||||
case CURLINFO_HEADER_OUT:
|
||||
log = Console::hide_secrets(std::string_view(data, size));
|
||||
logger->info(fmt::format("> {}", log));
|
||||
break;
|
||||
case CURLINFO_HEADER_IN:
|
||||
log = Console::hide_secrets(std::string_view(data, size));
|
||||
logger->info(fmt::format("< {}", log));
|
||||
{
|
||||
const auto message = fmt::format("{} {}", symbol_for(type), Console::hide_secrets(std::string_view(data, size)));
|
||||
logging::log({
|
||||
.message = message,
|
||||
.level = log_level::info,
|
||||
.source = log_source::libcurl
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// WARNING Using `hide_secrets` here will give a seg fault on linux,
|
||||
// and other errors on other platforms
|
||||
|
@ -377,9 +389,6 @@ namespace mamba::download
|
|||
|
||||
configure_handle_headers(params, auth_info);
|
||||
|
||||
auto logger = spdlog::get("libcurl");
|
||||
p_handle->set_opt(CURLOPT_DEBUGFUNCTION, curl_debug_callback);
|
||||
p_handle->set_opt(CURLOPT_DEBUGDATA, logger.get());
|
||||
}
|
||||
|
||||
void DownloadAttempt::Impl::configure_handle_headers(
|
||||
|
@ -1157,7 +1166,7 @@ namespace mamba::download
|
|||
auto completion_callback = m_completion_map.find(msg.m_handle_id);
|
||||
if (completion_callback == m_completion_map.end())
|
||||
{
|
||||
spdlog::error(
|
||||
LOG_ERROR << std::format(
|
||||
"Received DONE message from unknown target - running transfers left = {}",
|
||||
still_running
|
||||
);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_scope.hpp"
|
||||
#include "mamba/fs/filesystem.hpp"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
|
|
@ -1023,11 +1023,13 @@ bind_submodule_impl(pybind11::module_ m)
|
|||
decltype(Context::OutputParams::json) json,
|
||||
decltype(Context::OutputParams::quiet) quiet) -> Context::OutputParams
|
||||
{
|
||||
return {
|
||||
.verbosity = std::move(verbosity),
|
||||
// TODO: improve this, see https://wg21.link/p2287 for the reason
|
||||
auto params = Context::OutputParams{
|
||||
.json = std::move(json),
|
||||
.quiet = std::move(quiet),
|
||||
};
|
||||
params.verbosity = std::move(verbosity);
|
||||
return params;
|
||||
}
|
||||
),
|
||||
py::arg("verbosity") = default_output_params.verbosity,
|
||||
|
|
Loading…
Reference in New Issue