Enable defining custom namespace for spdlog#3611
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a configurable namespace mechanism for spdlog (via SPDLOG_NAMESPACE, SPDLOG_NAMESPACE_BEGIN, SPDLOG_NAMESPACE_END) to help consumers avoid ODR/linker collisions when multiple spdlog copies are present in the same process, and updates many headers to use these namespace macros.
Changes:
- Adds namespace customization macros in
include/spdlog/common.h. - Replaces
namespace spdlog { ... }blocks across many public headers withSPDLOG_NAMESPACE_BEGIN/END. - Adjusts one C++17 nested-namespace usage (
namespace spdlog::details) to a C++11-compatible form using the new macros.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
| include/spdlog/common.h | Defines namespace customization macros and wraps common declarations in SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/spdlog.h | Wraps API functions in SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/source_loc.h | Switches source_loc namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/stopwatch.h | Switches stopwatch namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/bin_to_hex.h | Switches hex-dump utilities namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/pattern_formatter.h | Switches pattern_formatter namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/logger.h | Switches logger namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/fwd.h | Switches forward declarations namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/formatter.h | Switches formatter namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/filename_t.h | Switches filename_t namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/file_event_handlers.h | Switches file event handlers namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/async_log_msg.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/circular_q.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/err_helper.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/file_helper.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/fmt_helper.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/log_msg.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/mpmc_blocking_q.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/null_mutex.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/os.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/tcp_client_unix.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/tcp_client_windows.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/udp_client_unix.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/details/udp_client_windows.h | Switches details namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/ansicolor_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/android_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/async_sink.h | Switches sinks/details forward-decl namespaces to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/base_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/basic_file_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/callback_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/daily_file_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/dist_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/dup_filter_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/hourly_file_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/kafka_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/mongo_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/msvc_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/null_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/ostream_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/qt_sinks.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/ringbuffer_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/rotating_file_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/stdout_color_sinks.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/stdout_sinks.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/syslog_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/systemd_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/tcp_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/udp_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/win_eventlog_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
| include/spdlog/sinks/wincolor_sink.h | Switches sinks namespace to SPDLOG_NAMESPACE_BEGIN/END. |
Comments suppressed due to low confidence (4)
include/spdlog/common.h:60
- Inside
SPDLOG_NAMESPACE_BEGINthis header still hard-codesspdlog::in declarations (e.g.to_string_view(spdlog::level),level_from_str), which will fail to compile whenSPDLOG_NAMESPACEis set to a non-spdlognamespace. Prefer unqualifiedlevel(since you’re already inside the namespace) or qualify via the configurable namespace macro consistently.
SPDLOG_NAMESPACE_BEGIN
class formatter;
namespace sinks {
class sink;
}
include/spdlog/bin_to_hex.h:93
- After switching to
SPDLOG_NAMESPACE_BEGIN/END, this header’sfmt::formatterspecialization and helper functions still hard-codespdlog::details::dump_infoandspdlog::fmt_lib::format_to. WhenSPDLOG_NAMESPACEis customized, those names won’t resolve. Use the active namespace macro (or another consistent qualifier) for these references.
SPDLOG_NAMESPACE_END
template <typename T>
struct fmt::formatter<spdlog::details::dump_info<T>, char> {
char delimiter = ' ';
include/spdlog/details/fmt_helper.h:18
- Within
SPDLOG_NAMESPACE_BEGIN,append_string_viewstill takes aspdlog::string_view_t. With a custom namespace,spdlog::string_view_twon’t exist. Usestring_view_t(unqualified) or qualify via the configurable namespace.
SPDLOG_NAMESPACE_BEGIN
namespace details {
namespace fmt_helper {
inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) {
const auto *buf_ptr = view.data();
dest.append(buf_ptr, buf_ptr + view.size());
include/spdlog/details/os.h:18
details/os.his insideSPDLOG_NAMESPACE_BEGIN, butnow()is declared as returningspdlog::log_clock::time_point. That hard-codes the original namespace and will fail withSPDLOG_NAMESPACEcustomization. Uselog_clock::time_point(unqualified) or qualify via the configurable namespace consistently.
SPDLOG_NAMESPACE_BEGIN
namespace details {
namespace os {
SPDLOG_API spdlog::log_clock::time_point now() noexcept;
SPDLOG_API std::tm localtime(const std::time_t &time_tt) noexcept;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| SPDLOG_NAMESPACE_BEGIN // source location | ||
| struct source_loc { | ||
| constexpr source_loc() = default; |
| #pragma once | ||
|
|
||
| namespace spdlog { | ||
| SPDLOG_NAMESPACE_BEGIN | ||
| class logger; |
| #endif | ||
|
|
||
| namespace spdlog { | ||
| SPDLOG_NAMESPACE_BEGIN | ||
| using filename_t = std::filesystem::path; | ||
| } // namespace spdlog | ||
| SPDLOG_NAMESPACE_END |
| #include "./filename_t.h" | ||
|
|
||
| namespace spdlog { | ||
| SPDLOG_NAMESPACE_BEGIN | ||
| struct file_event_handlers { | ||
| file_event_handlers() |
| inline void critical(std::string_view msg) { log(level::critical, msg); } | ||
|
|
||
| } // namespace spdlog | ||
| SPDLOG_NAMESPACE_END |
| } // namespace sinks | ||
| } // namespace spdlog | ||
| SPDLOG_NAMESPACE_END |
| } // namespace sinks | ||
| } // namespace spdlog | ||
| SPDLOG_NAMESPACE_END |
| } // namespace sinks | ||
| } // namespace spdlog | ||
| SPDLOG_NAMESPACE_END |
| // clang-format on | ||
|
|
||
| namespace spdlog { | ||
| SPDLOG_NAMESPACE_BEGIN |
| // qt_sink class | ||
| // | ||
| namespace spdlog { | ||
| SPDLOG_NAMESPACE_BEGIN |
|
SPDLOG_NAMESPACE_BEGIN is enough. no need for the SPDLOG_NAMESPACE. |
Move namespace macros to a dedicated namespace.h header and include it in headers that don't pull in common.h, making each self-contained.
Inside SPDLOG_NAMESPACE_BEGIN blocks, names are already in scope unqualified. The explicit spdlog:: prefix was harmless with the default namespace but would silently break with any customization.
Fix logging macros in spdlog.h to use SPDLOG_NS__ instead of hardcoded spdlog::, so they resolve correctly when SPDLOG_NAMESPACE_BEGIN is customized.
|
Thank you for the review!
See here for a suggestion to handle SPDLOG_NAMESPACE more like an implementation detail.
I'm sorry for the oversight! ca6be4e fixes the namespaces which fell besides the customization. I'm afraid you would have to make it a rule not to introduce new redundant namespace qualifiers in headers. 😬 With the |
Enable defining custom namespace for spdlog
When spdlog is used by multiple components in the same process,
each bundling their own copy, the linker or dynamic loader may resolve
all spdlog:: symbols to whichever definition it finds first. This is an ODR
(One Definition Rule) violation and can cause subtle misbehavior:
loggers silently share state across components, or the program crashes
when internal data structures disagree on their layout.
The SPDLOG_NAMESPACE macro lets a consumer place their copy of
spdlog in a dedicated namespace, making its symbols distinct from any
other copy in the process and avoiding ODR conflicts entirely.
For more sophisticated use cases, SPDLOG_NAMESPACE_BEGIN and
SPDLOG_NAMESPACE_END can be overridden directly. One example is
defining the namespace as inline, which keeps existing source code that
refers to
spdlog::loggerorspdlog::info(…)compiling withoutchanges, while the mangled symbol names still include the namespace
and remain ABI-distinct from other copies.