155#define FLOW_LOG_WARNING(ARG_stream_fragment) \
156 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_WARNING, ARG_stream_fragment)
170#define FLOW_LOG_FATAL(ARG_stream_fragment) \
171 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_FATAL, ARG_stream_fragment)
185#define FLOW_LOG_ERROR(ARG_stream_fragment) \
186 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_ERROR, ARG_stream_fragment)
200#define FLOW_LOG_INFO(ARG_stream_fragment) \
201 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_INFO, ARG_stream_fragment)
215#define FLOW_LOG_DEBUG(ARG_stream_fragment) \
216 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_DEBUG, ARG_stream_fragment)
230#define FLOW_LOG_TRACE(ARG_stream_fragment) \
231 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_TRACE, ARG_stream_fragment)
245#define FLOW_LOG_DATA(ARG_stream_fragment) \
246 FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_DATA, ARG_stream_fragment)
262#define FLOW_LOG_WARNING_LOCKED(ARG_stream_fragment) \
263 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_WARNING(ARG_stream_fragment); })
270#define FLOW_LOG_FATAL_LOCKED(ARG_stream_fragment) \
271 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_FATAL(ARG_stream_fragment); })
278#define FLOW_LOG_ERROR_LOCKED(ARG_stream_fragment) \
279 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_ERROR(ARG_stream_fragment); })
286#define FLOW_LOG_INFO_LOCKED(ARG_stream_fragment) \
287 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_INFO(ARG_stream_fragment); })
294#define FLOW_LOG_DEBUG_LOCKED(ARG_stream_fragment) \
295 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_DEBUG(ARG_stream_fragment); })
302#define FLOW_LOG_TRACE_LOCKED(ARG_stream_fragment) \
303 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_TRACE(ARG_stream_fragment); })
310#define FLOW_LOG_DATA_LOCKED(ARG_stream_fragment) \
311 log_while_locked([&](auto&& get_logger, auto&& get_log_component) { FLOW_LOG_DATA(ARG_stream_fragment); })
332#define FLOW_LOG_WARNING_WITHOUT_CHECKING(ARG_stream_fragment) \
333 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_WARNING, ARG_stream_fragment)
350#define FLOW_LOG_FATAL_WITHOUT_CHECKING(ARG_stream_fragment) \
351 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_FATAL, ARG_stream_fragment)
368#define FLOW_LOG_ERROR_WITHOUT_CHECKING(ARG_stream_fragment) \
369 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_ERROR, ARG_stream_fragment)
386#define FLOW_LOG_INFO_WITHOUT_CHECKING(ARG_stream_fragment) \
387 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_INFO, ARG_stream_fragment)
404#define FLOW_LOG_DEBUG_WITHOUT_CHECKING(ARG_stream_fragment) \
405 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_DEBUG, ARG_stream_fragment)
422#define FLOW_LOG_TRACE_WITHOUT_CHECKING(ARG_stream_fragment) \
423 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_TRACE, ARG_stream_fragment)
440#define FLOW_LOG_DATA_WITHOUT_CHECKING(ARG_stream_fragment) \
441 FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_DATA, ARG_stream_fragment)
473#define FLOW_LOG_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload) \
474 FLOW_LOG_SET_LOGGER(ARG_logger_ptr); \
475 FLOW_LOG_SET_COMPONENT(ARG_component_payload);
483#define FLOW_LOG_SET_LOGGER(ARG_logger_ptr) \
485 const auto get_logger \
486 = [logger_ptr_copy = static_cast<::flow::log::Logger*>(ARG_logger_ptr)] \
487 () -> ::flow::log::Logger* { return logger_ptr_copy; }
519#define FLOW_LOG_SET_COMPONENT(ARG_component_payload) \
521 const auto get_log_component = [component = ::flow::log::Component{ARG_component_payload}] \
522 () -> const ::flow::log::Component & \
537#define FLOW_LOG_SET_LOCKED_CONTEXT(ARG_log_ctx_mt_ptr) \
539 const auto log_while_locked \
540 = [log_ctx_mt_ptr_copy = static_cast<const ::flow::log::Log_context_mt*>(ARG_log_ctx_mt_ptr)] \
541 (auto&& logging_task) \
542 { log_ctx_mt_ptr_copy->log_while_locked(logging_task); }
574#define FLOW_LOG_WITH_CHECKING(ARG_sev, ARG_stream_fragment) \
575 FLOW_UTIL_SEMICOLON_SAFE \
577 ::flow::log::Logger const * const FLOW_LOG_W_CHK_logger = get_logger(); \
578 if (FLOW_LOG_W_CHK_logger && FLOW_LOG_W_CHK_logger->should_log(ARG_sev, get_log_component())) \
580 FLOW_LOG_WITHOUT_CHECKING(ARG_sev, ARG_stream_fragment); \
617#define FLOW_LOG_WITHOUT_CHECKING(ARG_sev, ARG_stream_fragment) \
618 FLOW_UTIL_SEMICOLON_SAFE \
620 using ::flow::util::Thread_id; \
621 using ::flow::log::Logger; \
622 using ::flow::log::Component; \
623 using ::flow::util::String_view; \
624 using ::flow::util::get_last_path_segment; \
625 using ::std::chrono::system_clock; \
626 Logger* const FLOW_LOG_WO_CHK_logger = get_logger(); \
627 if (!FLOW_LOG_WO_CHK_logger) \
634 auto const& FLOW_LOG_WO_CHK_time_stamp = system_clock::now(); \
642 constexpr char const * FLOW_LOG_WO_CHK_file_ptr = __FILE__; \
643 constexpr size_t FLOW_LOG_WO_CHK_file_sz = sizeof(__FILE__) - 1; \
644 constexpr char const * FLOW_LOG_WO_CHK_func_ptr = __FUNCTION__; \
645 constexpr size_t FLOW_LOG_WO_CHK_func_sz = sizeof(__FUNCTION__) - 1; \
647 constexpr String_view FLOW_LOG_WO_CHK_full_file_str(FLOW_LOG_WO_CHK_file_ptr, FLOW_LOG_WO_CHK_file_sz); \
649 constexpr String_view FLOW_LOG_WO_CHK_file_str = get_last_path_segment(FLOW_LOG_WO_CHK_full_file_str); \
651 constexpr String_view FLOW_LOG_WO_CHK_func_str(FLOW_LOG_WO_CHK_func_ptr, FLOW_LOG_WO_CHK_func_sz); \
652 const Component& FLOW_LOG_WO_CHK_component = get_log_component(); \
653 String_view FLOW_LOG_WO_CHK_call_thread_nickname; \
654 Thread_id FLOW_LOG_WO_CHK_call_thread_id; \
655 Logger::set_thread_info(&FLOW_LOG_WO_CHK_call_thread_nickname, &FLOW_LOG_WO_CHK_call_thread_id); \
656 FLOW_LOG_DO_LOG(FLOW_LOG_WO_CHK_logger, FLOW_LOG_WO_CHK_component, ARG_sev, FLOW_LOG_WO_CHK_file_str, __LINE__, \
657 FLOW_LOG_WO_CHK_func_str, FLOW_LOG_WO_CHK_time_stamp, FLOW_LOG_WO_CHK_call_thread_nickname, \
658 FLOW_LOG_WO_CHK_call_thread_id, ARG_stream_fragment); \
771#define FLOW_LOG_DO_LOG(ARG_logger_ptr, \
772 ARG_component, ARG_sev, ARG_file_view, ARG_line, ARG_func_view, \
773 ARG_time_stamp, ARG_call_thread_nickname_str_view, \
774 ARG_call_thread_id, ARG_stream_fragment) \
775 FLOW_UTIL_SEMICOLON_SAFE \
777 using ::flow::log::Thread_local_string_appender; \
778 using ::flow::log::this_thread_sync_msg_metadata; \
779 using ::flow::log::Logger; \
780 using ::flow::log::Msg_metadata; \
781 using ::flow::log::Fixed_string; \
782 using ::flow::util::String_view; \
783 using ::std::flush; \
784 using ::std::optional; \
785 Logger* const FLOW_LOG_DO_LOG_logger = ARG_logger_ptr; \
799 auto FLOW_LOG_DO_LOG_appender \
800 = Thread_local_string_appender::this_thread_string_appender(*FLOW_LOG_DO_LOG_logger); \
801 optional<Thread_local_string_appender> FLOW_LOG_DO_LOG_local_appender_or_none; \
802 if (!FLOW_LOG_DO_LOG_appender) \
804 FLOW_LOG_DO_LOG_local_appender_or_none.emplace(); \
805 FLOW_LOG_DO_LOG_appender = &*FLOW_LOG_DO_LOG_local_appender_or_none; \
807 auto& FLOW_LOG_DO_LOG_os = *(FLOW_LOG_DO_LOG_appender->fresh_appender_ostream()); \
808 FLOW_LOG_DO_LOG_os << ARG_stream_fragment << flush; \
810 const auto FLOW_LOG_DO_LOG_msg_metadata_ptr \
811 = FLOW_LOG_DO_LOG_logger->logs_asynchronously() \
813 ? (new Msg_metadata{ ARG_component, ARG_sev, ARG_file_view, ARG_line, ARG_func_view, \
815 {ARG_call_thread_nickname_str_view.data(), \
817 ::std::min(Fixed_string::static_capacity, ARG_call_thread_nickname_str_view.size())}, \
818 ARG_call_thread_id }) \
820 : &(this_thread_sync_msg_metadata = \
821 { ARG_component, ARG_sev, ARG_file_view, ARG_line, ARG_func_view, \
823 {ARG_call_thread_nickname_str_view.data(), \
825 ::std::min(Fixed_string::static_capacity, ARG_call_thread_nickname_str_view.size())}, \
826 ARG_call_thread_id }); \
839 FLOW_LOG_DO_LOG_logger->do_log(FLOW_LOG_DO_LOG_msg_metadata_ptr, \
840 String_view{FLOW_LOG_DO_LOG_appender->target_contents()}); \
963 template<
typename Payload>
1000 template<
typename Payload>
1026 template<
typename Payload>
1245static_assert(std::is_trivially_destructible_v<Msg_metadata>,
1246 "Using all-simple members, including array-backed string(s), so Msg_metadata is maximally TL-friendly.");
1391 private boost::noncopyable
1562 Logger* logger_ptr =
nullptr,
1563 bool also_set_os_name =
true);
1811 template<
typename Component_payload>
1974 template<
typename Component_payload>
2118 template<
typename Logging_task>
2132template<
typename Payload>
2139template<
typename Payload>
2146template<
typename Payload>
2149 static_assert(std::is_enum_v<Payload>,
"Payload type must be an enum.");
2150 static_assert(std::is_same_v<typename std::underlying_type_t<Payload>,
enum_raw_t>,
2151 "Payload enum underlying type must equal enum_raw_t.");
2161template<
typename Component_payload>
2164 m_component(component_payload)
2169template<
typename Component_payload>
2176template<
typename Logging_task>
2181 () ->
Logger* {
return logger_ptr; },
2183 () ->
const Component& {
return component_ref; });
A light-weight class, each object storing a component payload encoding an enum value from enum type o...
Component & operator=(const Component &src)
Overwrites *this with a copy of src.
unsigned int enum_raw_t
The type Payload must be enum class Payload : enum_raw_t: an enum type encoded via this integer type.
Component(Component &&src_moved)
Constructs *this equal to src_moved.
std::type_info const * m_payload_type_or_null
The typeid() of the Payload passed to the 1-arg constructor; if 0-arg ctor was used (empty() is true)...
const std::type_info & payload_type() const
Returns typeid(Payload), where Payload was the template param used when calling the originating one-a...
bool empty() const
Returns true if *this is as if default-constructed (a null Component); false if as if constructed via...
enum_raw_t m_payload_enum_raw_value
The internally stored integer representation of the enum value passed to the 1-arg constructor; meani...
Component(const Component &src)
Copies the source Component into *this.
Payload payload() const
Returns reference to immutable payload stored in *this; undefined behavior if empty() == true.
Component & operator=(Component &&src_moved)
Makes *this equal to src_moved.
enum_raw_t payload_enum_raw_value() const
Returns the numeric value of the enum payload stored by this Component, originating in the one-arg co...
Component()
Constructs a Component that stores no payload; meaning an unspecified-component Component that return...
Similar mission to Log_context but enables one to safely log under the possibility of a concurrent se...
void swap(Log_context_mt &other)
Identical to Log_context API; but safe against concurrent operations on a *this.
Log_context_mt & operator=(const Log_context_mt &src)
Identical to Log_context API; but safe against concurrent operations on a *this.
void log_while_locked(Logging_task &&logging_task) const
Locks *this to be immutable, and under this lock executes user's logging_task(), providing it get_log...
util::Mutex_non_recursive m_mutex
Protects access to data in static_cast<Log_context&>(*this) (especially Log_context::m_logger).
Log_context_mt(Logger *logger=nullptr)
Identical to Log_context API.
Logger * set_logger(Logger *logger)
Identical to Log_context API; but safe against concurrent operations on a *this.
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Log_context(const Log_context &src)
Copy constructor that stores equal Logger* and Component values as the source.
Log_context & operator=(const Log_context &src)
Assignment operator that behaves similarly to the copy constructor.
const Component & get_log_component() const
Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect.
Log_context(Logger *logger=nullptr)
Constructs Log_context by storing the given pointer to a Logger and a null Component.
Logger * set_logger(Logger *logger)
Sets the value to be returned by the next get_logger() call; returns get_logger() from before the cha...
void swap(Log_context &other)
Swaps Logger pointers and Component objects held by *this and other.
Component m_component
The held Component object. Making the object non-const to allow operator=() to work.
Logger * m_logger
The held Logger pointer. Making the pointer itself non-const to allow operator=() to work.
Logger * get_logger() const
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect.
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
static void set_thread_info_in_msg_metadata(Msg_metadata *msg_metadata)
Sets msg_metadata->m_call_thread_nickname (if set) or else msg_metadata->m_call_thread_id,...
virtual void do_log(Msg_metadata *metadata, util::String_view msg)=0
Given a message and its severity, logs that message and possibly severity WITHOUT checking whether it...
static std::ostream & this_thread_logged_name_os_manip(std::ostream &os)
ostream manipulator function that, if output via operator<< to an ostream, will cause the current thr...
static void this_thread_set_logged_nickname(util::String_view thread_nickname={}, Logger *logger_ptr=nullptr, bool also_set_os_name=true)
Sets or unsets the current thread's logging-worthy string name; optionally sets the OS thread name (s...
static thread_local Fixed_string s_this_thread_nickname
Thread-local storage for each thread's logged name (empty, which is default, means no nickname stored...
virtual bool should_log(Sev sev, const Component &component) const =0
Given attributes of a hypothetical message that would be logged, return true if that message should b...
std::ostream * this_thread_ostream() const
Returns the stream dedicated to the executing thread and this Logger, so that the caller can apply st...
static void set_thread_info(Fixed_string *call_thread_nickname, util::Thread_id *call_thread_id)
Same as set_thread_info_in_msg_metadata() but targets the given two variables as opposed to a Msg_met...
virtual bool logs_asynchronously() const =0
Must return true if do_log() at least sometimes logs the given message and metadata (e....
An empty interface, consisting of nothing but a default virtual destructor, intended as a boiler-plat...
Each object of this class stores (at construction) and returns (on demand) a numeric ID unique from a...
Flow module providing logging functionality.
Sev
Enumeration containing one of several message severity levels, ordered from highest to lowest.
boost::static_string< 128 > Fixed_string
Alias for a heap-free, array-backed, trivial-destructor-having string used for certain simple strings...
Thread::id Thread_id
Short-hand for an OS-provided ID of a util::Thread.
boost::unique_lock< Mutex > Lock_guard
Short-hand for advanced-capability RAII lock guard for any mutex, ensuring exclusive ownership of tha...
boost::mutex Mutex_non_recursive
Short-hand for non-reentrant, exclusive mutex. ("Reentrant" = one can lock an already-locked-in-that-...
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.