Flow 2.0.0
Flow project: Public API.
Public Member Functions | List of all members
flow::log::Log_context Class Reference

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...

#include <log.hpp>

Inheritance diagram for flow::log::Log_context:
[legend]

Public Member Functions

 Log_context (Logger *logger=nullptr)
 Constructs Log_context by storing the given pointer to a Logger and a null Component. More...
 
template<typename Component_payload >
 Log_context (Logger *logger, Component_payload component_payload)
 Constructs Log_context by storing the given pointer to a Logger and a new Component storing the specified generically typed payload (an enum value). More...
 
 Log_context (const Log_context &src)
 Copy constructor that stores equal Logger* and Component values as the source. More...
 
 Log_context (Log_context &&src)
 Move constructor that makes this equal to src, while the latter becomes as-if default-constructed. More...
 
Log_contextoperator= (const Log_context &src)
 Assignment operator that behaves similarly to the copy constructor. More...
 
Log_contextoperator= (Log_context &&src)
 Move assignment operator that behaves similarly to the move constructor. More...
 
void swap (Log_context &other)
 Swaps Logger pointers and Component objects held by *this and other. More...
 
Loggerget_logger () const
 Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect. More...
 
Loggerset_logger (Logger *logger)
 Sets the value to be returned by the next get_logger() call; returns get_logger() from before the change. More...
 
const Componentget_log_component () const
 Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect. More...
 

Detailed Description

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.

It's extremely useful (almost mandatory in conventional practice) for classes that want to log, as they can simply derive from it (passing in the desired Logger* and Component payload (an enum value) into the Log_context super-class constructor), at which point the get_logger() and get_log_component() functions the FLOW_LOG_...() macros expect automatically become available without any additional code having to be written in the logging class. Here is how:

class I_like_to_have_fun_and_log_about_it :
{
public:
I_like_to_have_fun_and_log_about_it() :
// Glue FLOW_LOG_*() macros to the following simple logger and component FUN_HAVER.
Log_context(&m_logger, My_cool_components::S_FUN_HAVER),
// Initialize stdout logger that logs INFO-or-higher-severity messages.
m_logger(true, std::cout, std::cout, flow::log::Sev::S_INFO),
// ... other initializers and super-class constructors, if any ...
{
FLOW_LOG_INFO("I can log right from the constructor and throughout *this lifetime!");
// ... other code ...
}
private:
void do_fun_stuff()
{
// This macro works, because Log_context super-class defines get_logger() which returns m_logger,
// and component() returns My_cool_components::S_FUN_HAVER.
// But we need not ever worry about such details.
FLOW_LOG_INFO("I am about to do something cool and fun: " << 42 << "!");
// ... more code ...
}
// I will use a simple stdout/stderr logger for my logging. It's passed to Log_context in constructor.
}; // class I_like_to_have_fun_and_log_about_it
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Definition: log.hpp:1638
An implementation of Logger that logs messages to the given ostreams (e.g., cout or an ofstream for a...
Definition: simple_ostream_logger.hpp:85
#define FLOW_LOG_INFO(ARG_stream_fragment)
Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:197
Sev
Enumeration containing one of several message severity levels, ordered from highest to lowest.
Definition: log_fwd.hpp:225
@ S_INFO
Message indicates a not-"bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
Catch-all namespace for the Flow project: A collection of various production-quality modules written ...
Definition: async_fwd.hpp:75

Note that the operator=() allows one to change the underlying Logger anytime after construction (e.g., existing_log_context = Log_context{&some_logger, Some_enum::S_SOME_COMPONENT};). That said it is more convenient to use set_logger(); but see the next section, as this may involve more subtleties than one might think.

Setting the logger / thready safety

set_logger() allows one, including an external user, to change the Logger. However beware two points w/r/t thread safety.

  1. It is not safe to use set_logger() or *this = Log_context{...} concurrently with any call that would log via get_logger(): so anything that, e.g., does FLOW_LOG_...(). It only replaces a pointer in memory, but there is no mutex or atomic protection; so it is not safe.
  2. Assuming one avoids any issues with the get_logger() pointer safety, please be sure that the Logger itself is actually valid/alive.

Informally: Generally it is best to avoid changing the active Logger, after an object is constructed. 99% of code in practice does not do so; it is usually far better to affect the Logger via its Config which takes massive pains to be both thread-safe and performant at that.

However in practice there is at least one exception to this: when the sub-class's instance is static or even global and/or a singleton. Then it might operate before and even after main(), and even during main() there may not be a good Logger to use yet. One might then make use of set_logger(), e.g., early in main() to change it from null to a Logger and then back late in main() (or if not null then a default Simple_ostream_logger to cout + cerr... you get the idea).

That however does not protect against thread-safety problems (point 1 above) necessarily. It depends when one does it. If it is necessary to be changing get_logger() return-value while get_logger() is potentially used by another thread, then consider using Log_context_mt. There is a bit of a perf trade-off there (see its doc header).

Implementation notes

The code could be shorter by getting rid of non-copy constuctor in favor of direct member initialization by user; and by simply omitting the API for the auto-generated copy constructor and assignment. However, in this case, I wanted to clearly document the API; and since there are more than 1 constructors, it seemed better to explicitly declare them all instead of replacing some with implicitly required direct initialization (again to make API more clearly documented).

Thread safety

The only operation of interest w/r/t threads is the aforementioned implicit assignment operator. Thread safety is the same as for any struct with no locking done therein.

Constructor & Destructor Documentation

◆ Log_context() [1/4]

flow::log::Log_context::Log_context ( Logger logger = nullptr)
explicit

Constructs Log_context by storing the given pointer to a Logger and a null Component.

Parameters
loggerPointer to store. Rationale for providing the null default: To facilitate sub-class = default no-arg ctors.

◆ Log_context() [2/4]

template<typename Component_payload >
flow::log::Log_context::Log_context ( Logger logger,
Component_payload  component_payload 
)
explicit

Constructs Log_context by storing the given pointer to a Logger and a new Component storing the specified generically typed payload (an enum value).

For more background on Component see its doc header.

Template Parameters
Component_payloadSee Component constructor doc header: Payload template arg specifically.
Parameters
loggerPointer to store.
component_payloadSee Component constructor doc header: payload arg specifically.

◆ Log_context() [3/4]

flow::log::Log_context::Log_context ( const Log_context src)
explicitdefault

Copy constructor that stores equal Logger* and Component values as the source.

This is explicit, even though an unintentional copy (e.g., in a bind sans cref or ref) would just internally involve the copying a pointer (as of this writing). The reason is that it's unlikely one wants to blithely copy these objects or objects of a sub-type; most likely (at least in scenarios seen so far, as of this writing) a cref or ref is in order instead. (I am open to counter-examples and thus removing this explicit keyword if convinced by one.)

Parameters
srcSource object.

◆ Log_context() [4/4]

flow::log::Log_context::Log_context ( Log_context &&  src)

Move constructor that makes this equal to src, while the latter becomes as-if default-constructed.

Parameters
srcSource object.

Member Function Documentation

◆ get_log_component()

const Component & flow::log::Log_context::get_log_component ( ) const

Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect.

Note
It's public at least so that FLOW_LOG_SET_CONTEXT() works in all reasonable contexts.
Returns
See above.

◆ get_logger()

Logger * flow::log::Log_context::get_logger ( ) const

Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect.

Note
It's public at least so that FLOW_LOG_SET_CONTEXT() works in all reasonable contexts.
Returns
See above.

◆ operator=() [1/2]

Log_context & flow::log::Log_context::operator= ( const Log_context src)
default

Assignment operator that behaves similarly to the copy constructor.

Parameters
srcSource object.
Returns
*this.

◆ operator=() [2/2]

Log_context & flow::log::Log_context::operator= ( Log_context &&  src)

Move assignment operator that behaves similarly to the move constructor.

Parameters
srcSource object.
Returns
*this.

◆ set_logger()

Logger * flow::log::Log_context::set_logger ( Logger logger)

Sets the value to be returned by the next get_logger() call; returns get_logger() from before the change.

Behavior is undefined if invoked concurrently with itself or get_logger() on the same *this. If that is unacceptable: see our class doc header for brief discussion / suggestion on alternative to Log_context.

Parameters
loggerAs in ctor.
Returns
get_logger() pre-change.

◆ swap()

void flow::log::Log_context::swap ( Log_context other)

Swaps Logger pointers and Component objects held by *this and other.

No-op if this == &other.

Parameters
otherOther object.

The documentation for this class was generated from the following files: