Flow 1.0.2
Flow project: Public API.
|
Class used to configure the filtering and logging behavior of Logger
s; its use in your custom Logger
s is optional but encouraged; supports dynamically changing filter settings even while concurrent logging occurs.
More...
#include <config.hpp>
Public Types | |
using | component_union_idx_t = Component::enum_raw_t |
Unsigned index into the flat union of component tables maintained by a Config, combining potentially multiple user component enum tables. More... | |
using | Component_to_union_idx_func = Function< component_union_idx_t(const Component &)> |
Short-hand for a function that takes a Component (storing a payload of some generic component enum member of the logging user's choice) and returns its corresponding flat union component index. | |
Public Member Functions | |
Config (Sev most_verbose_sev_default=S_MOST_VERBOSE_SEV_DEFAULT) | |
Constructs a conceptually blank but functional set of Config. More... | |
Config (const Config &src) | |
Copy-constructs *this to be equal to src config object. More... | |
Config (Config &&)=delete | |
For now at least there's no reason for move-construction. More... | |
void | operator= (const Config &)=delete |
For now at least there's no reason for copy assignment. More... | |
void | operator= (Config &&)=delete |
For now at least there's no reason for move assignment. More... | |
bool | output_whether_should_log (Sev sev, const Component &component) const |
A key output of Config, this computes the verbosity-filtering answer to Logger::should_log() based on the given log-call-site severity and component and the verbosity configuration in this Config, including the value at *(this_thread_verbosity_override()) , the value from configure_default_verbosity(), and the config from configure_component_verbosity*() . More... | |
bool | output_component_to_ostream (std::ostream *os, const Component &component) const |
An output of Config, this writes a string representation of the given component value to the given ostream , if possible. More... | |
template<typename Component_payload > | |
void | init_component_to_union_idx_mapping (component_union_idx_t enum_to_num_offset, size_t enum_sparse_length) |
Registers a generically-typed enum class that represents the full set of the calling module's possible component values that it will supply at subsequent log call sites from that module. More... | |
template<typename Component_payload > | |
void | init_component_names (const boost::unordered_multimap< Component_payload, std::string > &component_names, bool output_components_numerically=false, util::String_view payload_type_prefix_or_empty=util::String_view()) |
Registers the string names of each member of the enum class Component_payload earlier registered via init_component_to_union_idx_mapping<Component_payload>() . More... | |
void | configure_default_verbosity (Sev most_verbose_sev_default, bool reset) |
Sets the default verbosity to the given value, to be used by subsequent output_whether_should_log() calls whenever one supplies it a component for which no per-component verbosity is configured at that time; optionally wipes out all existing per-component verbosities for a constructor-like reset. More... | |
template<typename Component_payload > | |
bool | configure_component_verbosity (Sev most_verbose_sev, Component_payload component_payload) |
Sets the per-component verbosity for the given component to the given value, to be used by subsequent output_whether_should_log() calls whenever one supplies it the same component value. More... | |
bool | configure_component_verbosity_by_name (Sev most_verbose_sev, util::String_view component_name) |
Like configure_component_verbosity(), but the component is to be specified by its registered string name, well suited to interpreting text config files. More... | |
Static Public Member Functions | |
template<typename Component_payload > | |
static size_t | standard_component_payload_enum_sparse_length () |
Returns highest numeric value in the given component-payload enum , plus 1, assuming that enum was created using the config_enum_start_hdr.macros.hpp mechanism with all requirements followed by user. More... | |
static Sev * | this_thread_verbosity_override () |
Returns pointer to this thread's mutable verbosity override, for querying or assignment alike. More... | |
static util::Scoped_setter< Sev > | this_thread_verbosity_override_auto (Sev most_verbose_sev_or_none) |
Sets *(this_thread_verbosity_override()) = most_verbose_sev_or_none ; and returns an object that shall restore it to its current value when it goes out of scope. More... | |
Public Attributes | |
bool | m_use_human_friendly_time_stamps |
Config setting: If true , time stamps will include a (deterministically formatted) date, time, time zone, all in the OS's current time zone; else raw # of seconds passed since POSIX (Unix) Epoch (1970, Jan 1, 00:00, GMT). More... | |
Static Public Attributes | |
static const Sev | S_MOST_VERBOSE_SEV_DEFAULT = Sev::S_INFO |
Recommended default/catch-all most-verbose-severity value if no specific config is given. | |
Class used to configure the filtering and logging behavior of Logger
s; its use in your custom Logger
s is optional but encouraged; supports dynamically changing filter settings even while concurrent logging occurs.
If you are reading this to know how to configure an existing Logger, then you don't need further background; just see this API to know how to configure such Logger
s in a uniform way.
If you are, instead, reading this when implementing a new custom Logger, then please see implementation recommendations in Logger doc header before continuing here.
Really it's pretty easy to use it, but it's much easier to see how it's done by example rather than a formal-ish description (which is nevertheless below, in the next section of this doc header). To use Config with a Config
-supporting Logger in your flow::log-using module M:
enum
inside the module M. Declare and define the associated index-to-name map for that enum
. While it is possible to manually do this, we provide some tools to utterly minimize the boiler-plate required (which would be considerable otherwise). The files config_enum_{start|end}.macros.[hc]pp
are those tools.enum
(totally separate from any others, such as Flow's flow::Flow_log_component) at log call sites. More precisely, either pass a value to Log_context ctor or to FLOW_LOG_SET_CONTEXT().Config
. Call Config::init_component_to_union_idx_mapping() and Config::init_component_names() to register M's enum
– AND again for every other logging module besides M (such as Flow itself). Call Config::configure_default_verbosity() and Config::configure_component_verbosity() (and friend) to configure verbosity levels. Finally, create the specific Logger and give it a pointer to this Config.Logger
object's config shouldn't be done in libraries/modules but normally at the program level, such as around main()
.init_*()
or configure_*()
methods, with the following important exceptions:Let's get into it more formally.
Firstly, Config simply stores simple scalars controlling output behavior. For example, the public member m_use_human_friendly_time_stamps controls the style of time stamps in the final output. It's just a data store for such things.
Secondly, Config knows how to understand the component values supplied at every single log call site in your program. (This also ties in to the next thing we discuss, verbosity config.) See Component doc header. Now, here's how Config understands components. In your program, you will use various flow::log
-using libraries or modules – including (but not necessarily limited to!) Flow itself. Each module is likely to feature their own component table, in the form of an enum class
. For example, Flow itself has enum class Flow_log_component
(see common.hpp).
enum class
, C1 and C2, respectively. You are to register C1; and separately/similarly C2; using an init_component_to_union_idx_mapping() for each of C1 and C2. (All of this applies for any number of modules and enums, not just two.)C1::
enumeration member AND every C2::
member to a distinct component union index integer. (For example, in the init_component_to_union_idx_mapping() call, you can specify that C1's members will map to union indices 1000, 1001, ...; and C2's to 2000, 2001, ....) These flat union indices between C1 and C2 must never clash.enum class
(e.g., "C1_" for all C1::
members, "C2_" for all C2::
members). One provides (for each of C1, C2) this optional prefix and a simple map from the enum
members to their distinct string names. Use init_component_names().main()
) but outside the modules M1 and M2 themselves, the Config now has:Config
-internal union of all component enum
values.enum
values.Thirdly, and crucially, the verbosity filtering (Logger::should_log()) for the client Logger is entirely implemented via the output_whether_should_log() output method; so Logger::should_log() can simply forward to that method. Here is how one configures its behavior in Config. At construction, or in a subsequent configure_default_verbosity() call, one sets the default verbosity, meaning the most-verbose log::Sev that should_log()
would let through when no per-component verbosity for the log call site's specified Component is configured. In addition, assuming more fine-grained (per-component) verbosity config is desired, one can call configure_component_verbosity*()
to set the most-verbose log::Sev for when should_log()
is passed that specific Component payload.
Setting per-component verbosity can be done by its enum
value. Or one can use the overload that takes the component's distinct (among all source component enum
tables registered before) string name; in which case the aforementioned performant name-to-index mapping is used internally to set the proper union component's verbosity.
(Note that order of calls matters: configure_default_verbosity() wipes out effects of any individual, per-component configure_component_verbosity*()
executed prior to it. It is typical (in a given round of applying config) to first call configure_default_verbosity() and then make 0 or more configure_component_verbosity*()
calls for various individual components.)
Fourthly, output_component_to_ostream() is a significant helper for your Logger::do_log() when actually printing the ultimate character representation of the user's message and metadata. The metadata (Msg_metadata) includes a Component; that method will output its string representation to the ostream
given to it. To do so it will use the aforementioned ability to quickly map the C1::
or C2::
member to the flat union index to that index's distinct name (the same name optionally used to configure verbosity of that component, as explained above).
Or one can opt to print the flat numeric index of the component instead; in which case the reverse name-to-union-idx is not needed.
Formally, Config is thread-safe for all operations when concurrent access is to separate Config
s. There are no static
data involved. Formally, Config is generally NOT thread-safe when concurrent read and write access is w/r/t to a single Config; this includes read/write of any public data members and read/write in the form const
/otherwise method calls. Informally, one could use an outside mutex, including in any Logger implementation that uses *this
, but we recommend against this for performance reasons; and see below "exception."
Also formally for a given *this
: The logging phase is assumed to begin after all init_*()
calls and any initial configure_*()
calls; at this point output_whether_should_log() and output_component_to_ostream() may be used at will by any thread; but the pre-logging-phase non-const
calls are no longer allowed.
There is an important exception to the assertion that Config *this
one must NOT call any write methods once the logging phase has begun. Informally, this exception should make it possible to use Config safely and yet dynamically allow changes to Config without any expensive outside mutex. The exception is as follows:
Assume, as is proper, that you've called all needed init_component_to_union_idx_mapping() and init_component_names() before any concurrent logging and have now started to log – you are in the logging phase. Now assume you want to change verbosity settings during this logging-at-large phase; this is common, for example, when some dynamic config file changes verbosity settings for your program. The following is safe: You may call configure_default_verbosity() and/or configure_component_verbosity*()
while expecting the changes to take effect promptly in all threads; namely, output_whether_should_log() will reflect the change there; and output_component_to_ostream() does not care. Perf-wise, little to nothing is sacrified (internally, a lock-free implementation is used).
Corner case: It is also safe to call configure_default_verbosity() and/or configure_component_verbosity*()
concurrently with themselves. Naturally, it is a race as to which thread "wins." Moreover, configure_default_verbosity() with reset == true
is equivalent to removing the verbosity setting for each individual component; but only each removal itself is atomic, not the overall batch operation; so concurrent execution with another configure_*_verbosity()
call may result in an interleaved (but valid) verbosity table. Informally, we recommend against any design that would allow concurrent configure_*()
calls on *this
; it does not seem wise. It does however result in well-defined behavior as described. The real aim, though, is not this corner case but only the main case of a series of configure_*()
calls in thread 1, while logging may be going on in other threads.
In a pinch, it may be desirable – temporarily and in a given thread of execution only – to change the current verbosity config. To do so in a given scope {}
simply do this:
You may also query the current setting via *(this_thread_verbosity_override())
. Direct assignment of a Sev to the latter is allowed, but generally it is both safer and easier to use the RAII pattern via this_thread_verbosity_override_auto() for setting/restoring the override.
The value Sev::S_END_SENTINEL indicates the thread-local verbosity override is disabled; and is the initial (default) state in any thread. However, generally, it is recommended to use the RAII pattern via this_thread_verbosity_override_auto() instead of direct assignment, for safe and easy save/restore.
Note there are no thread-safety concerns with this feature, as it is entirely thread-local.
Unsigned index into the flat union of component tables maintained by a Config, combining potentially multiple user component enum
tables.
Also suitable for non-negative offsets against such indices.
|
explicit |
Constructs a conceptually blank but functional set of Config.
Namely, no component enum
s are yet registered (call init_component_to_union_idx_mapping() and init_component_names() to register 0 or more such enum
tables). The default verbosity is set to most_verbose_sev_default
.
While you can and should register enum
s after this, if you don't then the object's outputs will act as follows:
true
if and only if sev
is no more verbose than most_verbose_sev_default
arg to this ctor. component
is ignored in the decision.ostream
arg and hence will return false
.Note that – particularly in a pinch and in simple applications – this is perfectly reasonable, simple behavior. One doesn't always need per-component verbosity configuration abilities; and one definitely doesn't always need to print the component name/index in the log output. But if one does need these things, then you can register enum
s as explained in class doc header.
most_verbose_sev_default | Same as in configure_default_verbosity(). |
|
default |
Copy-constructs *this
to be equal to src
config object.
Performance-wise, this will copy internal per-component tables (in addition to a few scalars). These tables are conceptually unions of potentially multiple long enum
s; so this probably shouldn't be done often, but typically Config is constructed at startup or during rare config change events.
configure_component_verbosity*()
call in a different thread completes, then it is possible that call's effect won't register in the resulting *this
. In the case of configure_default_verbosity() with reset == true
the clearing of the per-component verbosities may register only partially in that situation, though *this
will still be valid. Since "very soon" cannot be formally defined, it is therefore best to make such a copy in the same thread as the last verbosity-modifying call on src
. (On the other hand, even otherwise results in valid behavior, but it may not be quite as deterministic as preferred and clean.)src | Source object. |
|
delete |
bool flow::log::Config::configure_component_verbosity | ( | Sev | most_verbose_sev, |
Component_payload | component_payload | ||
) |
Sets the per-component verbosity for the given component to the given value, to be used by subsequent output_whether_should_log() calls whenever one supplies it the same component value.
See also configure_default_verbosity().
This only works (and will return true
) if init_component_to_union_idx_mapping<Component_payload>()
has been called. Otherwise it returns false
(caller may assert()
against this result if it is felt justified).
See class doc header section "What Config controls and how" for more discussion.
most_verbose_sev | The most-verbose (numerically highest) Sev sev value such that output_whether_should_log() will return true , when Component component is not null and has Component::payload<Component_payload>() return a value equal to component_payload . |
component_payload | The component for which verbosity is being set. |
true
on success; false
otherwise. See above for more. bool flow::log::Config::configure_component_verbosity_by_name | ( | Sev | most_verbose_sev, |
util::String_view | component_name | ||
) |
Like configure_component_verbosity(), but the component is to be specified by its registered string name, well suited to interpreting text config files.
The meaning of verbosity is the same as in the other overload.
This only works (and will return true
) if init_component_names() has been called in such a way as to successfully associate a component in the flat union table with the name equal (after normalization of both sides) to component_name
. If the name is unknown, it returns false
.
Name normalization consists of conversion to upper case according to the classic ("C") locale.
See class doc header section "What Config controls and how" for more discussion.
most_verbose_sev | The most-verbose (numerically highest) Sev sev value such that output_whether_should_log() will return true , when Component component is not null and has an associated string name equal to component_name (post-normalization of both sides of comparison). |
component_name | The component for which verbosity is being set. |
true
on success; false
otherwise. See above for more. void flow::log::Config::configure_default_verbosity | ( | Sev | most_verbose_sev_default, |
bool | reset | ||
) |
Sets the default verbosity to the given value, to be used by subsequent output_whether_should_log() calls whenever one supplies it a component for which no per-component verbosity is configured at that time; optionally wipes out all existing per-component verbosities for a constructor-like reset.
This is fairly intuitive; the only aspect one might find non-obvious is reset == true
mode. In that mode all per-component verbosities are forgotten, as after construction. An intended use scenario is when reading a hypothetical config file describing new, dynamic overall verbosity settings to replace any existing ones. Such a config file would probably specify the catch-all (default) verbosity; then 0 or more per-component "exception" verbosities. Hence once would call this method with reset == true
accordingly to reset everything and set the default; then one would call configure_component_verbosity*()
for each "exception."
reset == true
is technically slower than otherwise, though it is doubtful one would call us frequently enough for it to matter. The perf cost of !reset
is constant time and basically that of a scalar assignment. The perf cost of reset == true
is that plus the cost of about N configure_component_verbosity() calls, where N is the highest flat-union-component-table implied by the enum_sparse_length
arg to init_component_to_union_idx_mapping() calls to date. In practice doing this when outside config changes is unlikely to be a perf issue.
*this
If called, it must be called after all init_component_to_union_idx_mapping() calls have completed. It is safe to call concurrently with output_whether_should_log(), meaning dynamic config of verbosities is allowed. See formal details in thread safety notes in class Config doc header.
most_verbose_sev_default | The most-verbose (numerically highest) Sev sev value such that output_whether_should_log() will return true , when Component component is either null or has no per-component verbosity configured at that time. |
reset | If false then per-component verbosities are left unchanged; else they are wiped out, meaning only the catch-all setting has subsequent effect in output_whether_should_log(). |
void flow::log::Config::init_component_names | ( | const boost::unordered_multimap< Component_payload, std::string > & | component_names, |
bool | output_components_numerically = false , |
||
util::String_view | payload_type_prefix_or_empty = util::String_view() |
||
) |
Registers the string names of each member of the enum class Component_payload
earlier registered via init_component_to_union_idx_mapping<Component_payload>()
.
These are used subsequently (as of this writing) to (1) map name to index in one of the configure_component_verbosity*()
methods; and (2) to map index to name in output_component_to_ostream().
Behavior undefined if init_component_to_union_idx_mapping<Component_payload>()
hasn't yet been called. Behavior undefined if init_component_names<Component_payload>()
has already been called. (Informally, something safe might happen, depending, but in general it's a weird/bad idea, so don't.) Behavior undefined if any value in component_names
is empty.
The recommended (but not mandatory) way to auto-generate a component_names
map (as normally doing so by hand is tedious) is to use config_enum_{start|end}_macros.[hc]pp
. As an example, Flow itself does it in common.hpp and common.cpp, defining both flow::Flow_log_component (the enum
) and flow::S_FLOW_LOG_COMPONENT_NAME_MAP (the component_names
map). Basically, via macro magic it names each component according to the enum
member identifier's own name.
component_names
meaningSome subtleties exist in interpreting component_names
.
Firstly, each value (string name) in component_names
– as well as payload_type_prefix_or_empty
– is internally pre-normalized before any other work. Name normalization consists of conversion to upper case according to the classic ("C") locale. output_component_to_ostream() will print in normalized form (if applicable); and configure_component_verbosity_by_name() will normalize the input arg string before lookup.
If empty, payload_type_prefix_or_empty
has no effect. Otherwise, its effect is as if it were empty, but as if component_names[X]
had payload_type_prefix_or_empty
prepended to its actual value at all times. Less formally, it's a constant to prefix every name; then if the program (perhaps around main()
) simply manually provides a distinct, cosmetically useful "namespace-like" prefix in each init_component_names() call, then it can 100% guarantee no name clashes, even if accidentally one of module X's component names A happened to equal an unrelated module Y's component name B. For example, A = B = "UTIL" is fairly likely to collide otherwise. It won't be an issue, if they end up being called "X_UTIL" and "Y_UTIL" ultimately, by supplying prefixes "X_" and "Y_" X and Y's init_component_names() calls.
Within component_names
if a value (name) is present 2+ times, behavior is undefined. Furthermore if payload_type_prefix_or_empty + X
, where X
is in component_names
, is already stored in *this
, behavior is undefined. Either way it's a name collision which should be entirely avoidable using payload_type_prefix_or_empty
as shown above.
It is a multi-map, and key K is allowed to be present 2+ times mapping to 2+ distinct names. The reason this is supported is so one can (discouraged though it is – but for historical reasons tends to come up at times) declare an enum
that includes a few mutually "aliased" members:
Sweet_components::S_COOL_ENGINE
<=> "COOL_ENGINE" <=> 5Sweet_components::S_ENGINE_ALIAS1
<=> "ENGINE_ALIAS1" <=> 5Sweet_components::S_ENGINE_ALIAS2
<=> "ENGINE_ALIAS2" <=> 5 In that example, any of S_{COOL_ENGINE|ENGINE_ALIAS{1|2}}
maps to the rather long name "COOL_ENGINE,ENGINE_ALIAS1,ENGINE_ALIAS2"; and each of "COOL_ENGINE", "ENGINE_ALIAS1", "ENGINE_ALIAS2" maps backwards to a single entry in the component-to-verbosity table. Hence if I configure verbosity X (using configure_component_verbosity*()
) for COOL_ENGINE_ALIAS1, then verbosity X config will equally affect subsequent messages with specified component COOL_ENGINE and ENGINE_ALIAS2 as well.Detail: When concatenating component output names as just described, the prefix payload_type_prefix_or_empty
is prepended only once. So, if the prefix is "SWEET-", then any one of the above 3 enum
example members maps to the name "SWEET-COOL_ENGINE,ENGINE_ALIAS1,ENGINE_ALIAS2".
output_components_numerically
, if and only if set to true
, suppresses the default behavior which is to memorize the string to output (in output_component_to_ostream()) for a given enum
value; instead it doesn't memorize this forward mapping. As a result, output_component_to_ostream() will simply output the numerical value of the enum
member from the flat union component table. This is a cosmetic output choice some prefer to the long-looking component names.
In addition, even if !output_components_numerically
, but a subsequent output_component_to_ostream() call encounters an enum
value that you neglected to register via init_component_names() (omitting it in component_names
in particular), then it will also be printed numerically as if output_components_numerically
.
Finally, even if output_components_numerically == true
, the backwards mapping (from string name to component) is still memorized. Therefore one can still set configure_component_verbosity_by_name() by string name. Again, in practice, I have seen this: Config files will refer to component verbosities by component name, not unhelpful-looking number; but output log files still print them as numbers for brevity.
component_names | Mapping of each possible Component_payload value to its string representation, for both output and per-component config (namely verbosity config) subsequently. Details above. Empty names lead to undefined behavior. |
output_components_numerically | If and only if true , output_component_to_ostream() will output the flat numeric index for all Component_payload -passing log call sites; else it will print the string name from the map (but if not in the map, then it'll fall back to the flat index again). |
payload_type_prefix_or_empty | Optional prefix helpful as a disambiguating "namespace" to preprend to values in component_names . Details above. |
void flow::log::Config::init_component_to_union_idx_mapping | ( | component_union_idx_t | enum_to_num_offset, |
size_t | enum_sparse_length | ||
) |
Registers a generically-typed enum class
that represents the full set of the calling module's possible component values that it will supply at subsequent log call sites from that module.
The caller supplies:
Component_payload
, which is an enum
and is thus castable to the unsigned integer type component_union_idx_t
.enum
value in order to yield the flat-union index in *this
merged table of all component enum
s. For example, if we assume that no module will ever exceed 1,000 components in its enum
, then module 1 can register its enum
C1 with enum_to_num_offset
1,000, module 2 with 2,000, module 3 with 3,000, etc. Then the various C1 enum
values 0, 1, ... will map to merged 1,000, 1,001, ...; C2's 0, 1, ... to 2,000, 2,001, ...; etc.enum
. Details are below.Behavior is undefined if an index collision occurs here or in a subsequent init_*()
or other relevant call. In particular take care to provide sufficient slack space (e.g., if you use enum_to_num_offset
which are multiples of 5, then a collision will probably occur at some point).
If one has called init_component_to_union_idx_mapping<T>()
with the same T
in the past, then behavior is undefined, so don't. (Informally, depending on whether/how one has called init_component_names() and configure_component_verbosity*()
, this can actually be done safely and with well-defined results. However, I did not want to go down that rabbit hole. If it becomes practically necessary, which I doubt, we can revisit. This is not a formal to-do as of this writing.)
Component_payload | See the doc header for the template param Payload on Component::payload(). In addition, in our context, it must be convertible to component_union_idx_t (an unsigned integer). Informally, Component_payload must be a sane unsigned enum with end sentinel S_END_SENTINEL . The various input Component_payload types are distinguished via typeid(Component_payload) and further type_index(typeid(Component_payload)) . I provide this implementation detail purely for general context; it should not be seen as relevant to how one uses the API. |
enum_to_num_offset | For each further-referenced Component_payload value C, its flat union index shall be component_union_idx_t(C) + enum_to_num_offset . So this is the "base" index for the enum you are registering, in the final flat table of components. |
enum_sparse_length | Formally, one plus the highest numeric value of a Component_payload value that will ever be passed to configure_component_verbosity() (directly; or indirectly if using configure_component_verbosity_by_name()). Informally, we recommend that you (a) use the config_enum_start_hdr.macros.hpp mechanism to create Component_payload type in the first place; and (b) therefore use standard_component_payload_enum_sparse_length<Component_payload>() for the present arg's value. |
|
delete |
|
delete |
bool flow::log::Config::output_component_to_ostream | ( | std::ostream * | os, |
const Component & | component | ||
) | const |
An output of Config, this writes a string representation of the given component value to the given ostream
, if possible.
Returns true
if it wrote anything, false
otherwise. Call this only after the full round of construction, init_component_to_union_idx_mapping(), and init_component_names().
If the component's type (component.payload_type()
) has not been properly registered via init_component_to_union_idx_mapping(), it returns false
and writes nothing. Otherwise, if no name was registered (either because it wasn't included in a init_component_names() call, or because in that call output_components_numerically == true
), it will output the component's numeric index in the flat union table; and return true
. Finally, if a name is indeed registered, it will output that string (details in init_component_names() doc header) and also return true
.
os | Pointer (not null) to the ostream to which to possibly write. |
component | The component value from the log call site. component.empty() (no component) is allowed. |
true
if 1 or more characters have been written to *os
; else false
. A key output of Config, this computes the verbosity-filtering answer to Logger::should_log() based on the given log-call-site severity and component and the verbosity configuration in this Config, including the value at *(this_thread_verbosity_override())
, the value from configure_default_verbosity(), and the config from configure_component_verbosity*()
.
Call this only after the full round of construction, init_component_to_union_idx_mapping(), and (initial) configure_..._verbosity()
. In addition, it is specifically safe to concurrently set verbosity via configure_default_verbosity() and/or configure_component_verbosity*()
.
*this
The last sentence means it's possible to change verbosities even while logging (which invokes us), as long as the init_*()
stuff has all been completed. For formal details see notes on thread safety in class Config doc header.
It's a matter of comparing sev
to S
, where S
is the applicable log::Sev verbosity setting. Return true
if and only if sev <= S
.
What is S
? It is the first available value of the following three bits of config:
S = *(this_thread_verbosity_override())
...S
= the verbosity configured via configure_component_verbosity*()
for component
.S
= the value given to configure_component_verbosity() or ctor, whichever happened later.sev | See Logger::should_log(). |
component | See Logger::should_log(). |
true
if we recommend to let the associated message be logged; false
to suppress it.
|
static |
Returns highest numeric value in the given component-payload enum
, plus 1, assuming that enum
was created using the config_enum_start_hdr.macros.hpp mechanism with all requirements followed by user.
This is useful for most invocations of init_component_to_union_idx_mapping() for its enum_sparse_length
argument.
For example, if one wants to store a vector
that uses size_t(X)
, where X
is a Component_payload
, as an associative-key-like index, then the vector
would have to be sized whatever the present method returns to guarantee no out-of-bounds error.
enum_sparse_length
argument.Component_payload | An enum class type created by the mechanism prescribed in config_enum_start_hdr.macros.hpp, using that mechanism and with user following the documented requirements therein. Alternatively (though it's not recommended) the following is sufficient if one makes the type some other way: Component_payload::S_END_SENTINEL must have the highest numeric value, without ties; and the backing type is unsigned and with a bit width no higher than that of size_t (Component::enum_raw_t is what the aforementioned standard mechanism uses as of this writing). |
|
static |
Returns pointer to this thread's mutable verbosity override, for querying or assignment alike.
The value of this override, at any given time, shall affect output_whether_should_log() return value. See output_whether_should_log().
If you would like to query the current setting, use this method.
If you would like to modify the current setting, it is safer and easier to use this_thread_verbosity_override_auto() which supplies RAII-style auto-restore.
For each thread:
S = *(this_thread_verbosity_override())
.S == Sev::S_END_SENTINEL
.S
, per its doc header.S
to any valid log::Sev value via direct assignment.S
and only S
, per its doc header.S
back to Sev::S_END_SENTINEL.S
again.
|
static |
Sets *(this_thread_verbosity_override()) = most_verbose_sev_or_none
; and returns an object that shall restore it to its current value when it goes out of scope.
See class doc header for an example of use.
It is recommended to use this method instead of direct assignment to the location this_thread_verbosity_override(), as then it'll be auto-restored.
most_verbose_sev_or_none | A value suitable for configure_default_verbosity(); or the special value Sev::S_END_SENTINEL which disables the override (meaning C.output_whether_should_log() shall actually follow the config in Config C and not any override). |
bool flow::log::Config::m_use_human_friendly_time_stamps |
Config setting: If true
, time stamps will include a (deterministically formatted) date, time, time zone, all in the OS's current time zone; else raw # of seconds passed since POSIX (Unix) Epoch (1970, Jan 1, 00:00, GMT).
In both cases time is expressed with microsecond resolution (but the accuracy is only as good as the computer's clock hardware and OS software allow, presumably, though this isn't in the purview of class Config).