This Chapter brings us back to talking about Log Domains and their attribute Verbosity which are associated with pairs of a Log Domains and a Logger.
Setting such Verbosity by invoking Lox.SetVerbosity (C++, C#, Java) is easy and straightforward. However, when working in a team, different team members, working on different parts of a software, naturally are interested in different information. Now, when the Verbosity is defined in the source (preferably the bootstrap section of a software), then these would be randomly changed when checking source files in and out of a source control system. Therefore, ALox supports to read Verbosity settings from the command line, from environment variables, from an INI file or from any other custom data source. This way, all personal changes are outside the code - good for your team spirit!
But before we can explain how this is done, we first have to talk about priorities of Verbosity settings. This is an important prerequisite to understanding how external configuration works in ALox.
In the Tutorials (C++, C#, Java), in chapter 04 - Log Domains and elsewhere in the ALox documentation, so far, we have just ignored an optional parameter of overlaoded methods: Lox.SetVerbosity (C++, C#, Java). The parameter is named priority. We did so, because this parameter, while extending the flexibility of ALox, brings a new new level of complexity to the table. The good news is that (as explained in II - ALox Auto-Configuration and Orthogonality) when the parameter is omitted, ALox behaves as if this feature was not existing.
The parameter is of int
type and defaults to constant PrioDefaultValues (C++, C#, Java). The value of the constant is 100
, but for now, this is not of further interest. When passing a higher value here, subsequent invocations for the Log Domain in question (or for one of its parent domains!) which use the standard value, will be ignored. See the following sample:
And its output:
UT_dox_manual.cs(564):Man_ExtVerbosityConfig() [/MYDOM]: This line will be logged UT_dox_manual.cs(567):Man_ExtVerbosityConfig() [/MYDOM]: This line will still be logged
As you see, the second invocation of Lox.SetVerbosity is ignored, because the first had a higher priority.
With ALox internal logging (see 11 - Internal Logging) activated, ALox nicely reports what is going on. We add line:
to the top of the sample. Now the output is:
UT_dox_manual.cs(580):Man_ExtVerbosityConfig() [$/LGR ]: Logger "DEBUG_LOGGER": '$/' = Verbosity.Verbose (Default). UT_dox_manual.cs(582):Man_ExtVerbosityConfig() [$/LGR ]: Logger "MEMORY" added. UT_dox_manual.cs(582):Man_ExtVerbosityConfig() [$/LGR ]: Logger "DEBUG_LOGGER": '/' = Verbosity.Off (Default). UT_dox_manual.cs(582):Man_ExtVerbosityConfig() [$/LGR ]: Logger "DEBUG_LOGGER": '/MYDOM' = Verbosity.Info (Default). UT_dox_manual.cs(582):Man_ExtVerbosityConfig() [$/LGR ]: Logger "DEBUG_LOGGER": '/MYDOM' = Verbosity.Info (10001). UT_dox_manual.cs(583):Man_ExtVerbosityConfig() [/MYDOM]: This line will be logged UT_dox_manual.cs(585):Man_ExtVerbosityConfig() [$/LGR ]: Logger "DEBUG_LOGGER": '/MYDOM' = Verbosity.Off (Default). Lower priority (10000 < 10001). Remains Info. UT_dox_manual.cs(586):Man_ExtVerbosityConfig() [/MYDOM]: This line will still be logged
ALox in its internal log messages tells us that the second request was ignored.
Why is that useful? Well, honestly it really becomes useful only in consideration of external configuration data, described later in this chapter. However, when you think about it, one field of application is in respect to sub-domain settings. Consider the following Log Domain tree:
/UI /UI/MOUSE /UI/DIALOGS /UI/DIALOGS/MOUSE /UI/DIALOGS/KEYS
Imagine you are currently frequently switching the Verbosity of sub-domains of Log Domain '/UI'
because you are currently working on the UI. Now you have a random problem with mouse event handling. As long as this problem occurs, Log Statements related to mouse event should stay Verbose
. Therefore, you enable them 'permanently' by invoking
After that, any changes in parent domains, even for root-domain, will not disable Log Statements of mouse events any more. When the mouse event handling is fixed, these settings can be deleted again.
As you have learned from the previous chapter, 12 - External Configuration, the configuration system of ALib (the utility library that ALox builds upon) works with priorities the same as ALox Verbosity settings do. Now, you might guess what happens! ALox uses the same constants as the ALib configuration system does. The following table gives an overview of these constants:
Constant | Value |
---|---|
PrioProtectedValues (C++, C#, Java) | <max int> |
PrioCLIParameters (C++, C#, Java) | 40000 |
PrioEnvironment (C++, C#, Java) | 30000 |
PrioStandard (C++, C#, Java) | 20000 |
PrioDefaultValues (C++,C#, Java) | 10000 |
PrioAutodetect (C++, C#, Java) | 500 |
When a Verbosity setting is read by ALox from external configuration, the priority of the plug-in that provided the data is used as the priority of the setting, just as if this value was passed to method Lox.SetVerbosity (C++, C#, Java) using optional parameter priority.
As a programmer, you need nothing special to do. The same as ALox creates Log Domains on the fly as soon as you are using them, the same it reads configuration data for these Log Domains without having an explicit mandate for that. It just always does. If no configuration plug-ins are set, nothing is read, ALox will not complain. However, if it finds configuration data that influences the Verbosity setting of Log Domains you are using, then you will get noted by ALox as soon as you have activated Internal Logging.
Before it is explained how the format of configuration looks like, lets talk about two important topics in respect to the priority values given in the table above.
Lox.SetVerbosity
invocations into the source. Your setup is just not affected by this!This was a lot of theory, before we now finally come to to the definition of the configuration variable itself. When a Logger is registered with an instance of class Lox, ALox tries to read configuration variable ALOX_LOXNAME_LOGGERNAME_VERBOSITY. (This is done also whenever a new Log Domain is used and hence created on the fly.)
The portions 'LOXNAME'
and 'LOGGERNAME'
of the variable name have to be replaced by the names of the instances of Lox and Logger in question.
Its format is:
ALOX_<LOXNAME>_<LOGGERNAME>_VERBOSITY = [ writeback [ VAR_NAME ] ; ] [*]domainpath[*] = verbosity [ ; … ]
Let quickly forget about the optional argument 'writeback' (we come back to this in the necht section) and just concentrate on:
[*]domainpath[*] = verbosity
which can appear repeatedly separated by a semicolon ';'
. The pairs of domainpath and verbosity have the following meaning:
domainpath
denotes the path of the Log Domain whose Verbosity is to be set. Optionally the value may contain wildcard character '*'
at the beginning or end of the string or at both places.With having the ability to provide wildcards, the possibilities to define the Verbosity is a little different than when using method Lox.SetVerbosity (C++, C#, Java)! The differences are:
Using configuration variables it is possible to fetch Log Domains which are residing in different sub-domain trees. For example, setting 'ERRORS'
, affects any Log Domain with this substring in the path, like
/ERRORS /UI/DIALOGS/ERRORS /COMM/ERRORS/SEVERE
This is not possible with using method Lox.SetVerbosity which always modifies exactly one Log Domain and its sub-domains.
In general, as already described, controlling the Verbosity using configuration variables is preferred over using method Lox.SetVerbosity. This is the reason why ALox does not provide an interface method to set "rules", similar to those coming from configuration variables from within the source code.
domainpath
. This can also be used as a prefix e.g. INTERNAL_DOMAINS/REPORT = verbose ;However, a Logger that is not configured to log on internal Log Domain, can not be enabled for doing so using this configuration variable. A Logger has to be 'added' to the internal Log Domain tree once by the software itself. This behavior is wanted and similiar to the fact that a Logger can not be added to a different Lox instance by just adding the verbosity setting variable on the command line!
We had so far ignored the portion [ writeback [ VAR_NAME ] ; ]
of configuration variable
ALOX_<LOXNAME>_<LOGGERNAME>_VERBOSITY = [ writeback [ VAR_NAME ] ; ] [*]domainpath[*] = verbosity [ ; … ]
The 'writeback' option tells ALox to write all verbosities back to the configuration as soon as a Logger is removed from a Lox object.
Having ALox writing back the verbosities to your configuration is quite useful, for example, if you have an empty INI file and you want to start configuring ALox using this. Instead of manually building the variable, all you need to do is adding section and variable:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = writeback
The variable name addresses the default debug Logger which is called DEBUG_LOGGER and the default debug Lox which is called LOG.
Now after your next run of your application, ALox will have written back the current configuration and your INI might look like this:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = writeback; \ / =Info; \ /ACTION =Info; \ /AWAX =Info; \ /CMDLINE =Info; \ /TILE =Info; \ /WMI =Info; \ /WMI/XLIB =Info; \ /WMI/XLIB/RANDR =Info; \ /WMI/XLIB/X11 =Info; \
This of-course saves you some work. But there are more benefits. As you see, ALox preserves the attribute writeback in the variable. And you should keep this in. This way, on the next run of your software, the list might get extended by Log Domains that had not been registered on the previous runs. The reason is that ALox recognizes only those domains that are actually used (independend from their Verbosity setting). Subsequent runs may have different execution paths and this way might "touch" other Log Domains.
As ALox reads the variable during the runs, any change you make in the INI-file is well kept.
Let's imagine the developer of the application sampled above has some problems with interfacing the XWindow library. Hence, he or she would focus on the relevant domains and change the Verbosities to this:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = writeback; \ / =Warning; \ /ACTION =Warning; \ /AWAX =Info; \ /CMDLINE =Off; \ /TILE =Off; \ /WMI =Info; \ /WMI/XLIB =Verbose; \ /WMI/XLIB/RANDR =Warning; \ /WMI/XLIB/X11 =Verbose; \
Now, the X11 problems were fixed. However, the developer likes the detailing of the settings and aims to preserve them for the future. All he/she needs to do, is to add optional parameter VAR_NAME of the write back argument [ writeback [ VAR_NAME ] ; ]
. The arbitrary variable name MYSTUFF_X11_DEBUG_VERB is added as shown here:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = writeback MYSTUFF_X11_DEBUG_VERB; \ / =Warning; \ /ACTION =Warning; \ /AWAX =Info; \ /CMDLINE =Off; \ /TILE =Off; \ /WMI =Info; \ /WMI/XLIB =Verbose; \ /WMI/XLIB/RANDR =Warning; \ /WMI/XLIB/X11 =Verbose; \
After the next run, the INI file will contain:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = writeback MYSTUFF_X11_DEBUG_VERB; \ / =Warning; \ /ACTION =Warning; \ /AWAX =Info; \ /CMDLINE =Off; \ /TILE =Off; \ /WMI =Info; \ /WMI/XLIB =Verbose; \ /WMI/XLIB/RANDR =Warning; \ /WMI/XLIB/X11 =Verbose; \ [MYSTUFF] # Created at runtime through config option 'writeback' in variable "ALOX_LOG_DEBUG_LOGGER_VERBOSITY". X11_DEBUG_VERB= / =Warning; \ / =Warning; \ /ACTION =Warning; \ /AWAX =Info; \ /CMDLINE =Off; \ /TILE =Off; \ /WMI =Info; \ /WMI/XLIB =Verbose; \ /WMI/XLIB/RANDR =Warning; \ /WMI/XLIB/X11 =Verbose; \
As you see, ALox created INI file section MYSTUFF and added the variable we specified. You can still fine-tune the verbosity setting in LOG_DEBUG_LOGGER_VERBOSITY or chose different execution paths of your software. On each run, ALox will save what is found in variable ALOX_LOG_DEBUG_LOGGER_VERBOSITY to variable MYSTUFF_X11_DEBUG_VERB! Once you think that the setting is OK, you can stop the writeback feature by changing the Loggers Verbosity setting in the INI file to:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = $MYSTUFF_X11_DEBUG_VERB [MYSTUFF] ... ...
Now we are using a feature of the ALib configuration system called Variable Substitution (C++, C#, Java): With the preceding '$'
symbol (this is the default and can be changed), class Configuration substitutes what is "$MYSTUFF_X11_DEBUG_VERB" with the corresponding variable.
To conclude, lets take some further notes on what was said above:
Of-course, the configuration sets stored can be shortened easily to contain only non-redundant information. ALox, when writing the variable, includes all sub-domains in the list of settings, even those that have the same Verbosity as their parent domain. This is intentionally done to support the user and decrease typing.
Once a setting is fixed, all redundant lines can be deleted easily - but again this is not necessary even, it might just increase readability and shorten the configuration file.
When execution paths are changing between different runs, ALox will remove Verbosity information provided, if a Log Domain was not used. The advantage of this is, that when Log Domains are renamed in the source code, no "garbage" remains in the config file - at least for freshly written variables. If you want to compare an 'old' variable with what the difference would be using the newest version of your software, variable ALOX_LOG_DEBUG_LOGGER_VERBOSITY can be set as follows:
[ALOX] LOG_DEBUG_LOGGER_VERBOSITY = writeback MY_NEW_VAR ; $MY_OLD_VAR
After running the software MY_NEW_VAR will not contain Log Domains that are not existing any more (or have not been touched by the execution path!) but will contain new domains (or those that previously had not been touched by the execution path).
'_'
apply as it is described in Variable Substitution (C++, C#, Java).--verbosity <val>
. Now, the software could write a variable of e.g. ALOX_REL_CONSOLE_VERBOSITY (a release logger responsible for the software's standard output) with either PrioDefaultValues (C++, C#, Java) or PrioProtectedValues (C++, C#, Java) (use the latter to disallow the user to hack in). The value of the variable set 'in code' would either contain substituted system-wide external variables, or hard-coded strings (again, depending on the necessary protection level of the software).As a summary, these are the takeaways of this chapter: