// src/common/dout.h 文件中定义的 dout_impl 和 dendl_impl 宏 #ifdef WITH_CRIMSON #define dout_impl(cct, sub, v) \ do { \ if (crimson::common::local_conf()->subsys.should_gather(sub, v)) { \ seastar::logger &_logger = crimson::get_logger(sub); \ const auto _lv = v; \ std::ostringstream _out; \ std::ostream *_dout = &_out; #define dendl_impl \ ""; \ _logger.log(crimson::to_log_level(_lv), "{}", _out.str().c_str()); \ } \ } \ while (0) #else #define dout_impl(cct, sub, v) \ do { \ const bool should_gather = [&](const auto cctX, auto sub_, auto v_) { \ /* The check is performed on `sub_` and `v_` to leverage the C++'s \ * guarantee on _discarding_ one of blocks of `if constexpr`, which \ * includes also the checks for ill-formed code (`should_gather<>` \ * must not be feed with non-const expresions), BUT ONLY within \ * a template (thus the generic lambda) and under the restriction \ * it's dependant on a parameter of this template). \ * GCC prior to v14 was not enforcing these restrictions. */ \ if constexpr (ceph::dout::is_dynamic<decltype(sub_)>::value || \ ceph::dout::is_dynamic<decltype(v_)>::value) { \ return cctX->_conf->subsys.should_gather(sub, v); \ } else { \ constexpr auto sub_helper = static_cast<decltype(sub_)>(sub); \ constexpr auto v_helper = static_cast<decltype(v_)>(v); \ /* The parentheses are **essential** because commas in angle \ * brackets are NOT ignored on macro expansion! A language's \ * limitation, sorry. */ \ return (cctX->_conf->subsys \ .template should_gather<sub_helper, v_helper>()); \ } \ }(cct, sub, v); \ \ if (should_gather) { \ ceph::logging::MutableEntry _dout_e(v, sub); \ static_assert( \ std::is_convertible<decltype(&*cct), CephContext *>::value, \ "provided cct must be compatible with CephContext*"); \ auto _dout_cct = cct; \ std::ostream *_dout = &_dout_e.get_ostream();
// 展开 dout_prefix 宏内容,比如: // *_dout << "auth: "
// 继续输出对应的日志内容,比如: // << " ignoring boot message without a port" << dendl;
graph LR
A[global_init] --> B[global_pre_init]
B --> C[common_preinit <br/>初始化context]
C --> C1[CephContext::CephContext <br/>初始化 log 对象]
B --> D[global_init_set_globals<br/>设置 g_ceph_context]
B --> E[Log::start<br/>创建名为 log 的线程]
E --> F[Thread::create]
F --> G[Thread::try_create]
G --> H[Thread::_entry_func]
H --> I[Thread::entry_wrapper]
I --> J[Log::entry]
style E fill:#e8f5e8,stroke:#333,stroke-width:1px
style J fill:#e8f5e8,stroke:#333,stroke-width:1px
if (should_gather) { ceph::logging::MutableEntry _dout_e(1, dout_subsys); static_assert( std::is_convertible<decltype(&*dout_context), CephContext *>::value, "provided cct must be compatible with CephContext*"); auto _dout_cct = dout_context; std::ostream *_dout = &_dout_e.get_ostream();