Flow 1.0.2
Flow project: Public API.
Classes | Namespaces | Macros
log.hpp File Reference

Classes

class  flow::log::Component
 A light-weight class, each object storing a component payload encoding an enum value from enum type of user's choice, and a light-weight ID of that enum type itself. More...
 
struct  flow::log::Msg_metadata
 Simple data store containing all of the information generated at every logging call site by flow::log, except the message itself, which is passed to Logger::do_log() assuming Logger::should_log() had returned true. More...
 
class  flow::log::Logger
 Interface that the user should implement, passing the implementing Logger into logging classes (Flow's own classes like net_flow::Node; and user's own logging classes) at construction (plus free/static logging functions). More...
 
class  flow::log::Log_context
 Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns this Logger and Component via get_logger() and get_log_component() public accessors. More...
 

Namespaces

namespace  flow
 Catch-all namespace for the Flow project: A collection of various production-quality modules written in modern C++17, originally by ygoldfel.
 
namespace  flow::log
 Flow module providing logging functionality.
 

Macros

#define FLOW_LOG_WARNING(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_WARNING, ARG_stream_fragment)
 Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by that Logger. More...
 
#define FLOW_LOG_FATAL(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_FATAL, ARG_stream_fragment)
 Logs a FATAL message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_ERROR(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_ERROR, ARG_stream_fragment)
 Logs an ERROR message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_INFO(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_INFO, ARG_stream_fragment)
 Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_DEBUG(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_DEBUG, ARG_stream_fragment)
 Logs a DEBUG message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_TRACE(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_TRACE, ARG_stream_fragment)
 Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_DATA(ARG_stream_fragment)    FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_DATA, ARG_stream_fragment)
 Logs a DATA message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_WARNING_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_WARNING, ARG_stream_fragment)
 Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_FATAL_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_FATAL, ARG_stream_fragment)
 Logs a FATAL message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_ERROR_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_ERROR, ARG_stream_fragment)
 Logs an ERROR message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_INFO_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_INFO, ARG_stream_fragment)
 Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_DEBUG_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_DEBUG, ARG_stream_fragment)
 Logs a DEBUG message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_TRACE_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_TRACE, ARG_stream_fragment)
 Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_DATA_WITHOUT_CHECKING(ARG_stream_fragment)    FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_DATA, ARG_stream_fragment)
 Logs a DATA message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger. More...
 
#define FLOW_LOG_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload)
 For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_...() invocations to log to ARG_logger_ptr with component flow::log::Component(ARG_component_payload), instead of the normal get_logger() and get_log_component(), if there even such things are available in the block. More...
 
#define FLOW_LOG_SET_LOGGER(ARG_logger_ptr)
 Equivalent to FLOW_LOG_SET_CONTEXT() but sets the get_logger only. More...
 
#define FLOW_LOG_SET_COMPONENT(ARG_component_payload)
 Equivalent to FLOW_LOG_SET_CONTEXT() but sets the get_log_component only. More...
 
#define FLOW_LOG_WITH_CHECKING(ARG_sev, ARG_stream_fragment)
 Logs a message of the specified severity into flow::log::Logger *get_logger() with flow::log::Component get_log_component() if such logging is enabled by said flow::log::Logger. More...
 
#define FLOW_LOG_WITHOUT_CHECKING(ARG_sev, ARG_stream_fragment)
 Identical to FLOW_LOG_WITH_CHECKING() but foregoes the filter (Logger::should_log()) check. More...
 
#define FLOW_LOG_DO_LOG(ARG_logger_ptr, ARG_component, ARG_sev, ARG_file_view, ARG_line, ARG_func_view, ARG_time_stamp, ARG_call_thread_nickname_str_moved, ARG_call_thread_id, ARG_stream_fragment)
 Lowest-level logging API accessible to the user, this is identical to FLOW_LOG_WITHOUT_CHECKING() but expects all pieces of metadata in addition to the message and log::Sev, plus the flow::log::Logger, to be supplied as macro arguments. More...
 

Macro Definition Documentation

◆ FLOW_LOG_DATA

#define FLOW_LOG_DATA (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_DATA, ARG_stream_fragment)

Logs a DATA message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but for the flow::log::Sev::S_DATA severity.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_DATA_WITHOUT_CHECKING

#define FLOW_LOG_DATA_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_DATA, ARG_stream_fragment)

Logs a DATA message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING_WITHOUT_CHECKING() but for the flow::log::Sev::S_DATA severity.

Note
Same warnings and notes as for FLOW_LOG_WARNING_WITHOUT_CHECKING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_DEBUG

#define FLOW_LOG_DEBUG (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_DEBUG, ARG_stream_fragment)

Logs a DEBUG message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but for the flow::log::Sev::S_DEBUG severity.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_DEBUG_WITHOUT_CHECKING

#define FLOW_LOG_DEBUG_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_DEBUG, ARG_stream_fragment)

Logs a DEBUG message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING_WITHOUT_CHECKING() but for the flow::log::Sev::S_DEBUG severity.

Note
Same warnings and notes as for FLOW_LOG_WARNING_WITHOUT_CHECKING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_DO_LOG

#define FLOW_LOG_DO_LOG (   ARG_logger_ptr,
  ARG_component,
  ARG_sev,
  ARG_file_view,
  ARG_line,
  ARG_func_view,
  ARG_time_stamp,
  ARG_call_thread_nickname_str_moved,
  ARG_call_thread_id,
  ARG_stream_fragment 
)

Lowest-level logging API accessible to the user, this is identical to FLOW_LOG_WITHOUT_CHECKING() but expects all pieces of metadata in addition to the message and log::Sev, plus the flow::log::Logger, to be supplied as macro arguments.

Internally, all other log-call-site macros ultimately build on top of this one.

Note
From public user's point of view: It's flow::log::Logger::should_log() that allows the message argument to be built using ostream<< semantics instead of having to instantiate an intermediate flow::util::String_ostream (which has performance overhead and is more verbose). Why not just use a higher-level macro – at least as high-level as FLOW_LOG_WITHOUT_CHECKING() – instead? Answer: In some cases there is a source of metadata, like file and line number, that comes from a different source than (e.g.) __FILE__ and __LINE__ at the log call site; e.g., when logging from another log API through flow::log.
Warning
If invoking this directly, API user must manually ensure the severity/component is enabled in the Logger. Not doing so breaks (unenforced but nevertheless mandatory) rules of logging system.
If invoking this directly, API user must manually ensure ARG_logger_ptr is not null. Otherwise behavior is undefined.
Parameters
ARG_logger_ptrA Logger* through which to log; not null.
ARG_componentSee Msg_metadata (reference copied into it).
ARG_sevSee Msg_metadata (enum value copied into it).
ARG_file_viewSee Msg_metadata (String_view copied into it). Reminder: Underlying memory may need to remain valid asynchronously (read: indefinitely); usually it's a literal in static storage.
ARG_lineSee Msg_metadata (integer copied into it).
ARG_func_viewSee Msg_metadata (String_view copied into it). Reminder: Same as for ARG_file_view.
ARG_time_stampSee Msg_metadata (scalar copied into it).
ARG_call_thread_nickname_str_movedSee Msg_metadata (this std::string is moved into it and thus made empty).
ARG_call_thread_idSee Msg_metadata (scalar copied into it).
ARG_stream_fragmentSee FLOW_LOG_WITHOUT_CHECKING().

◆ FLOW_LOG_ERROR

#define FLOW_LOG_ERROR (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_ERROR, ARG_stream_fragment)

Logs an ERROR message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but for the flow::log::Sev::S_ERROR severity.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_ERROR_WITHOUT_CHECKING

#define FLOW_LOG_ERROR_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_ERROR, ARG_stream_fragment)

Logs an ERROR message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING_WITHOUT_CHECKING() but for the flow::log::Sev::S_ERROR severity.

Note
Same warnings and notes as for FLOW_LOG_WARNING_WITHOUT_CHECKING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_FATAL

#define FLOW_LOG_FATAL (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_FATAL, ARG_stream_fragment)

Logs a FATAL message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but for the flow::log::Sev::S_FATAL severity.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_FATAL_WITHOUT_CHECKING

#define FLOW_LOG_FATAL_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_FATAL, ARG_stream_fragment)

Logs a FATAL message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING_WITHOUT_CHECKING() but for the flow::log::Sev::S_FATAL severity.

Note
Same warnings and notes as for FLOW_LOG_WARNING_WITHOUT_CHECKING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_INFO

#define FLOW_LOG_INFO (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_INFO, ARG_stream_fragment)

Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but for the flow::log::Sev::S_INFO severity.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_INFO_WITHOUT_CHECKING

#define FLOW_LOG_INFO_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_INFO, ARG_stream_fragment)

Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING_WITHOUT_CHECKING() but for the flow::log::Sev::S_INFO severity.

Note
Same warnings and notes as for FLOW_LOG_WARNING_WITHOUT_CHECKING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_SET_COMPONENT

#define FLOW_LOG_SET_COMPONENT (   ARG_component_payload)
Value:
[[maybe_unused]] \
const auto get_log_component = [component = ::flow::log::Component(ARG_component_payload)] \
() -> const ::flow::log::Component & \
{ \
return component; \
}
A light-weight class, each object storing a component payload encoding an enum value from enum type o...
Definition: log.hpp:840

Equivalent to FLOW_LOG_SET_CONTEXT() but sets the get_log_component only.

Parameters
ARG_component_payloadSee FLOW_LOG_SET_CONTEXT().

◆ FLOW_LOG_SET_CONTEXT

#define FLOW_LOG_SET_CONTEXT (   ARG_logger_ptr,
  ARG_component_payload 
)
Value:
FLOW_LOG_SET_LOGGER(ARG_logger_ptr); \
FLOW_LOG_SET_COMPONENT(ARG_component_payload);
#define FLOW_LOG_SET_LOGGER(ARG_logger_ptr)
Equivalent to FLOW_LOG_SET_CONTEXT() but sets the get_logger only.
Definition: log.hpp:415

For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_...() invocations to log to ARG_logger_ptr with component flow::log::Component(ARG_component_payload), instead of the normal get_logger() and get_log_component(), if there even such things are available in the block.

This is useful, for example, in static methods, where there is no get_logger() or get_log_component() function defined, but a flow::log::Logger and component payload are available (for example) via parameters. It's also useful if one wants to log to a different Logger* for some reason and/or (perhaps more likely) a different component. Note that this creates or changes the meaning of the identifiers get_logger and get_log_component for the rest of the block; in fact you may call get_logger() or get_log_component() directly for whatever nefarious purposes you require, though it is suspected to be rare compared to just using FLOW_LOG_...() normally.

Example:

// Suppose flow_node is a flow::Node object, which derives from Log_context.
FLOW_LOG_SET_CONTEXT(flow_node.get_logger(), My_project_components::S_COOL_MODULE);
// Logs with component S_COOL_MODULE to logger set above.
FLOW_LOG_WARNING("Something horrible happened: [" << error_str << "].");
#define FLOW_LOG_WARNING(ARG_stream_fragment)
Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_compone...
Definition: log.hpp:152
#define FLOW_LOG_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload)
For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_....
Definition: log.hpp:405
Note
It will not compile if used 2+ times in the same block at the same nesting level. (The same applies to mixing with FLOW_LOG_SET_COMPONENT() or FLOW_LOG_SET_LOGGER().) However, one can create sub-blocks to work around this (likely very infrequent) situation.
Parameters
ARG_logger_ptrARG_logger_ptr will be used as the Logger* in subsequent FLOW_LOG_...() invocations in this block.
ARG_component_payloadComponent(ARG_component_payload), a light-weight holder of a copy of ARG_component_payload, will be used as the const Component& in subsequent FLOW_LOG_...() invocations in this block.

◆ FLOW_LOG_SET_LOGGER

#define FLOW_LOG_SET_LOGGER (   ARG_logger_ptr)
Value:
[[maybe_unused]] \
const auto get_logger \
= [logger_ptr_copy = static_cast<::flow::log::Logger*>(ARG_logger_ptr)] \
() -> ::flow::log::Logger* { return logger_ptr_copy; }
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1291

Equivalent to FLOW_LOG_SET_CONTEXT() but sets the get_logger only.

Parameters
ARG_logger_ptrSee FLOW_LOG_SET_CONTEXT().

◆ FLOW_LOG_TRACE

#define FLOW_LOG_TRACE (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_TRACE, ARG_stream_fragment)

Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but for the flow::log::Sev::S_TRACE severity.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_TRACE_WITHOUT_CHECKING

#define FLOW_LOG_TRACE_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_TRACE, ARG_stream_fragment)

Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING_WITHOUT_CHECKING() but for the flow::log::Sev::S_TRACE severity.

Note
Same warnings and notes as for FLOW_LOG_WARNING_WITHOUT_CHECKING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_WARNING

#define FLOW_LOG_WARNING (   ARG_stream_fragment)     FLOW_LOG_WITH_CHECKING(::flow::log::Sev::S_WARNING, ARG_stream_fragment)

Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_component(), if such logging is enabled by that Logger.

Supplies context information to be potentially logged with message, like current time, source file/line/function, and thread ID/nickname info, in addition to the message, component, and severity. The severity checked against (and potentially logged in its own right) is flow::log::Sev:S_WARNING.

More precisely, checks whether logging warnings is currently enabled in the Logger* returned by get_logger() in the macro invocation's context; if not does nothing; if so constructs and logs the message as a warning via FLOW_LOG_WITHOUT_CHECKING(). Also, if get_logger() is null, then the effect is the same as a get_logger()->should_log() returning false (meaning it is a no-op).

get_logger() must exist, and if not null then get_logger() (returning Logger*) and get_log_component() (returning const Component&) must return a valid pointer and reference to Logger and Component, respectively. Most of the time these are available due to most logging code being in classes deriving from flow::log::Log_context which supplies those methods and takes (at construction) the values to return subsequently. In situations where this is impossible (such as static members methods or in free functions) or insufficient (such as when one wants to use a different component vs. the one returned by flow::log::Log_context::get_log_component()), use FLOW_LOG_SET_CONTEXT().

Final log output subleties

We assume for this discussion that the notion of order of final output (to device/file/network/whatever) exists, and that the get_logger() indeed safely outputs message M1 entirely before M2, or vice versa, for every pair of messages (in this context by message we mean message+metadata pair) ever passed to do_log(). With that assumption in effect (IF indeed it is):

  • In a given thread T, and assuming the same get_logger(), if FLOW_LOG_*(M1); is called before FLOW_LOG_*(M2);, and both are successfully output by logger, then the final output order must have M1 precede M2, not vice versa.
    • In addition, assuming monotonically increasing time stamps, as time flows (which is the case most of the time with exceptions due to computer-clock adjustments and similar), M1's time stamp will be earlier (ignoring rounding) than M2's.
  • If, instead, M1 is logged in thread T1, while M2 is logged in thread T2:
    • If the 2 FLOW_LOG_*() calls are chronologically disjoint, then again the final output must also have M1 precede M2 if M1 went first; and vice versa.
      • Time stamps (under a well behaved clock again), again, will match this order.
    • If the 2 FLOW_LOG_*() calls chronologically overlap, then either final output order is possible.
      • Moreover if M1 precedes M2 in the output, formally time stamps might be in the opposite order (even assuming, again, a well behaved clock). (Informally, given how this is implemented internally, this is unlikely to be observed in practice, barring a wide absolute discrepancy between how long it takes to evaluate ARG_stream_fragment in M1 vs. M2.)

The time stamp is obtained as soon as practically possible within the body of this macro. Hence it reflects the time at the moment just after the pre-logging statement finished, just before the log call site executes. After this is when ARG_stream_fragment is evaluated – assuming the filter check passes – and only after that might the final output get queued (or possibly synchronously output, depending on nature of get_logger()). This is why it's technically possible that (even in the absence of system time going backwards) 2 messages from 2 different threads might appear in the final output with slightly out-of-order time stamps. Informally, this is unlikely, because the ARG_stream_fragment evaluation would be on the order of a bunch of instructions that would complete in less time than the microsecond resolution of time stamp output, in most cases, or maybe a handful of microseconds. Anecdotally, I (ygoldfel) don't recall one instance of seeing this (out-of-order time stamps due to the concurrency race implied by the above mechanism). Nevertheless I mention it here for completeness, as well as to explain how it works.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WITHOUT_CHECKING().
Todo:
We can avoid using macros for this and similar APIs by requiring the user to use commas instead of the usual << and by implementing this as a variadic function template (C++11 feature).

Thus, while it'd be no longer possible to write

FLOW_LOG_WARNING("Result: [" << std::setfill('0') << num << "].");

one would instead write

flow::log::warning("Result: [", std::setfill('0'), num, "].");

which is fairly close and still reasonably readable. However, one would need to be mindful of performance; hopefully the optimizer would still inline everything instead of adding a number of function calls compared to this macro implementation whose side benefit is guaranteed inlining. Generally, though, macros are bad and should be eliminated where possible; just don't mess up speed in something as common as logging. In addition, if it's NOT inlined, the number of functions generated by the template's many instantiations would be rather large, though I suppose that's not necessarily worse than full-on inlining thereof – just different. (Still, consider how many different configurations would pop up as a result of all the different log messages!) Also keep in mind that fully inlining all of this would require the build engine to be capable of link-time optimization (FLTO), and the build script to enable FLTO. Unfortunately it would be impossible for the non-macro to refer to a get_logger() in the call's context, so it would be necessary for this to be passed in as an argument, significantly lowering the ease of use of the API. That said, flow::log::Logger itself could simply implement all these APIs as class methods instead of their being free functions. Then one could even (when desired) write such things as

Logger some_logger(...); // Some Logger that is not available through get_logger() as would be more typical.
some_logger.warning("Error detected: [", err_num, "].");

and therefore FLOW_LOG_SET_CONTEXT() (another "tricky" macro) could be eliminated due to lack of necessity. Finally, flow::log::Log_context (in the current design, to be derived from by all logging classes) would be used like this:

get_logger()->warning("Error detected: [", err_num, "].");

It might also be advisable, for code brevity in such commonly referenced APIs, to add trivial forwarding methods to flow::log::Log_context. This is slightly questionable, as it's quite a bit of boiler-plate (needed every time one might change this overall API) just to remove a few characters from each log call. The above call would become:

log_warning("Error detected: [", err_num, "]."); // Invoke superclass Log_context's Logger::warning() method.

which is a little more compact. That can also be accomplished by having flow::log::Log_context implement flow::log::Logger itself. As a last note, __LINE__ (etc.) can only be made useful via a macro, so one would still be required to wrap around any API suggested above in a simple macro – but this would be far superior (in this particular dimension of avoiding macro insanity) to the level of macro-ness required at the moment. All in all, while I do hate macros, the present design seems reasonably strong, so the above rejiggering ideas don't feel like no-brainers.

◆ FLOW_LOG_WARNING_WITHOUT_CHECKING

#define FLOW_LOG_WARNING_WITHOUT_CHECKING (   ARG_stream_fragment)     FLOW_LOG_WITHOUT_CHECKING(::flow::log::Sev::S_WARNING, ARG_stream_fragment)

Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_component() regardless of whether such logging is enabled by the flow::log::Logger.

Analogous to FLOW_LOG_WARNING() but without checking for whether it is enabled (you should do so yourself; see the following note on this topic).

Note
If get_logger() is null, this is a no-op. In practice, though, this case should have been eliminated as part of heeding the following warning:
Warning
If invoking this directly, API user must manually ensure the severity is enabled in the logger. Not doing so breaks (unenforced but nevertheless mandatory) rules of logging system.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

◆ FLOW_LOG_WITH_CHECKING

#define FLOW_LOG_WITH_CHECKING (   ARG_sev,
  ARG_stream_fragment 
)
Value:
( \
::flow::log::Logger const * const FLOW_LOG_W_CHK_logger = get_logger(); \
if (FLOW_LOG_W_CHK_logger && FLOW_LOG_W_CHK_logger->should_log(ARG_sev, get_log_component())) \
{ \
FLOW_LOG_WITHOUT_CHECKING(ARG_sev, ARG_stream_fragment); \
} \
)
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...
#define FLOW_UTIL_SEMICOLON_SAFE(ARG_func_macro_definition)
Use this to create a semicolon-safe version of a "void" functional macro definition consisting of at ...
Definition: util_fwd.hpp:1079

Logs a message of the specified severity into flow::log::Logger *get_logger() with flow::log::Component get_log_component() if such logging is enabled by said flow::log::Logger.

The behavior is identical to that by FLOW_LOG_WARNING() and similar, but one specifies the severity as an argument instead of it being hard-coded into the macro name itself.

Note
It is important that ARG_stream_fragment is actually evaluated only if Logger::should_log() is true. Otherwise resources are wasted on constructing a message string that never gets logged. That's a (the?) reason Logger:should_log() and Logger::do_log() are mutually decoupled in that interface.
Parameters
ARG_sevSeverity (type log::Sev).
ARG_stream_fragmentSame as in FLOW_LOG_WARNING().

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

◆ FLOW_LOG_WITHOUT_CHECKING

#define FLOW_LOG_WITHOUT_CHECKING (   ARG_sev,
  ARG_stream_fragment 
)

Identical to FLOW_LOG_WITH_CHECKING() but foregoes the filter (Logger::should_log()) check.

No-op if get_logger() returns null. Internally, all other log-call-site macros ultimately build on top of this one except FLOW_LOG_DO_LOG().

Context information obtained and possibly logged is file/function/line, thread nickname/ID, time stamp, etc. The message is given as the <<-using ostream fragment in ARG_stream_fragment argument. Example (note the 2nd argument containing a stream output fragment):

"Failed [" << n_times << "] times; bailing out!");
#define FLOW_LOG_WITHOUT_CHECKING(ARG_sev, ARG_stream_fragment)
Identical to FLOW_LOG_WITH_CHECKING() but foregoes the filter (Logger::should_log()) check.
Definition: log.hpp:532
@ S_WARNING
Message indicates a "bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
Note
This macro is the lowest-level API that user should invoke to actually log, except FLOW_LOG_DO_LOG(). Usually she'd invoke something higher-level like FLOW_LOG_WARNING(), etc.; but at times more control is desirable for performance or other reasons – but even then one should not call anything below this level without an extremely excellent reason. See FLOW_LOG_DO_LOG() for discussion of the latter.
Warning
If invoking this directly, API user must manually ensure the severity is enabled in the Logger. Not doing so breaks (unenforced but nevertheless mandatory) rules of logging system.

Severity selection

Before selecting a severity for your log call site, please consider the discussion in the flow::log::Sev doc header.

Parameters
ARG_sevSeverity (type flow::log::Sev).
ARG_stream_fragmentFragment of code as if writing to a standard ostream. A terminating newline will be auto-appended to this eventually and therefore should generally not be included by the invoker. (Such a terminating newline would manifest as a blank line, likely.)