ALox  V. 2402 R. 0
Home ALox for C++ ALox for C# ALox for Java Download
05 - Scopes in ALox
Attention
In respect to the C++ Version of ALox, this manual is outdated. C++ Users, please visit ALib C++ Library.
The deep-link (we hope this still works, otherwise please quickly find it yourself from the above library link above) should be this.

1. Introduction

ALox uses the concept of Scopes in different ways. The most important and prominent use is to set so called Scope Domains. Those can be registered and then are used as a 'default' domain path with each Log Statement placed within the according Scope. The concept of Scope Domains has been explained already in the previous chapter (see 04 - Log Domains). But to keep it simple, the full variety of ALox Scopes was not yet, explained there. This is what this chapter aims to do.

So, be sure, that you have read and understood chapter 04 - Log Domains, before working yourself through this chapter. Using the more complex possibilities of scopes is optional when using ALox, so you can consider this chapter as an advanced topic.

Furthermore, there are other features in ALox that use Scopes. Those are elaborated in chapters

Note
When talking about Scopes, it is not easy to use a precise wording. (Therefore, we do not even try in this manual and other documentation of ALox!) The reason for this is that the Scope is not one value but is defined as a nested list of values. For example, when we say that two Log Statements that reside in the same file (Java: CLASS) have the same Scope, then this is true for Scope.Filename, but maybe not for Scope.Method. Also, it is not easy in English language to denote exactly what the difference of the Scope of a Scope Domain is in contrast to the Scope of a Log Statement. So, please excuse the imprecise use of that word, we are still sure you will understand what we talk about.

ALox Scopes are enumerated in enum-class Scope (C++, C#, Java). The Scopes found here are separated in two sets:

  • Scopes related to the programming language:
    These scopes are identified 'automatically' at compile time with each invocation to a method of class Lox (as well as of class Log in ALox for C# and Java). In Java, for technical reasons, they are identified at runtime, but this does not affect their behavior.
  • Scopes related to the execution thread:
    These scopes are identified at runtime, by examining the thread that is executing a method of class Lox.

2. Language-Related Scopes

ALox adopts the concept of Scopes from each programming language of its implementation (currently C++, C# and Java). A variable declared in one of these languages belongs to a certain scope, e.g. to the class when it is a member variable.

Scopes are nested into each other. We talk about 'outer' and 'inner' scopes. For example the Scope of a method is nested into the Scope of the class that the method belongs to.

The language-related Scopes that ALox supports are (from outer to inner):

  • Scope.Global,
  • Scope.Path (in Java: Scope.PACKAGE),
  • Scope.Filename (in Java: Scope.CLASS) and
  • Scope.Method.

Apart from Scope.Global, to evaluate the actual Scope of an invocation to class Lox, ALox needs to 'automatically' collect information of the calling entity. The techniques are different in each implementation:

  • In ALox for C++ is this is achieved using preprocessor macros for all Log Statements.
  • In ALox for C# the method annotations '[CallerFilePath]', [CallerLineNumber] and [CallerMemberName] are leveraged.
  • In ALox for Java, the detection is performed at runtime by examining the 'stack trace' of an object of type Exception which is solely created for this purpose. (This implies a quite huge performance overhead, which roughly triples the execution time of a Log Statement in Java. However, as soon as such runtime information is not used, e.g. in typical release-logging, the overhead is avoided. And: ALox is fast still!).

As explained in detail in chapter 10 - Differences of Debug- and Release-Logging, for release-logging, such automatic collection is not wanted. Without repeating the reasons for this here, let us emphasize the consequence:

Attention
The Scopes.Path (in Java Scope.PACKAGE), Scope.Filename (in Java Scope.CLASS) and Scope.Method can be used for debug-logging only! While it is possible to set Scope Domains and use other features of ALox which rely on Scopes, in release-logging, scope information values will be empty and hence not distinguishable from each other.
In ALox for Java, if a release application is obfuscated, such missing scope information is not detected and the result of its use is undefined.

The good news is: This is absolutely OK! The rational for claiming this is:

  • In respect to Scope Domains:
    Release-logging statements are quite rare compared to those of debug logging. Furthermore, they should be very well thought, clear and meaningful. It is advisable to not use Scope Domains in release logging anyhow (apart from thread-related and Scope.Global as explained below). Instead, Log Statements that comprise release-logging should specify the Log Domains they refer to explicitly.
  • In respect to Log Data:
    Well, the whole concept of Log Data provided by ALox is merely a tool to support the process of debugging, e.g. to explore the location of an exception in the log output. It is not deemed to be used to implement any functionality of an application, for example to store thread-local information.
  • In respect to method Lox.Once (C++, C#, Java):
    For release logging, the optional parameter group certainly does the job. It should be used because, this makes release logging statements to be more explicit and readable.
  • In respect to Prefix Logables:
    The most important use case for them are to make the output better readable, e.g. by adding recursive indentation. Again, something that should not be too important for release logging. If it still is, a thread-related Scope can be used.

The following sections describe each of the language-related Scopes in detail.

2.1 Scope.Global

As the name of this Scope indicates, this is the 'most outer' Scope of ALox. It is always there and only one single 'instance' of it exists per Lox. In other words, all Log Statements or other invocations of ALox are executed 'within' this singleton scope.

Note
Because scopes are managed by class Lox, each instance of this class provides its own Global scope, the same as a Lox has different Loggers, Log Domains, Scope Domains, Log Data, etc. Well, and this makes perfect sense!

When setting Scope Domains for the Global Scope, all Log Statements have such domain as their root-domain. (Of-course, unless one inner Scope Domain or the statement itself is using an absolute domain path!).

One use case of setting a Scope Domain for Scope.Global could be described as follows: A Lox used for release-logging of special and sparse Log Statements (e.g. logging into the operating systems' journal, aka event log). Now, in debug versions of the executable a debug-Logger is attached to the release lox (in addition to attaching it to the debug-lox), within this debug log output, all of these special Log Statements would be nicely sorted into the Scope Domain of Scope.Global, while non of the Log Statements to this release lox need to specify that domain path.

Another use case are special debug situations. Imagine a dubious behavior of a software is observed rather seldom. A programmer could register a debug Logger with Verbosity All for domain '/DEBUG'. Now, when a certain first indication for the start of the dubious behavior occurs, a setting of the Scope Domain '/DEBUG' for Scope.Global can be activated. From this point in time, all Log Statements would be activated, because all Log Statements of all code would be gathered beyond that temporary Log Domains '/DEBUG' and all sub-domains inherit its Verbosity.

2.2 Scope.Path (In Java Scope.PACKAGE)

This Scope has a different name and meaning in ALox for C++/C# and ALox for Java. Let's start with the Java side of things - well, but, even as a C++ or C# programmer, please continue reading here!

The scope information collected by ALox for each Log Statement incorporates the 'package' name of the class and method that is executing it. Therefore, using method Lox.SetDomain (C++, C#, Java) with Scope PACKAGE in Java instructs ALox to use the given Scope Domain for all Log Statements residing in any class of the package. Now, method Lox.SetDomain optionally offers a parameter packageLevel which defaults to 0. This parameter is ignored with other Scopes. For Scope.PACKAGE, however it allows to refer to an 'outer package'. If this parameter is set to 1, ALox searches the last '.' in the package name and cuts this and the rest of the name off. This way, Scope.PACKAGE can be considered to not denoting just a single Scope, but rather a set of nested scopes itself! Consequently, when executing a Log Statement within a method of a class residing in a nested package for which a Scope Domain is set, then, if any of the 'parent' packages of this package has also set a Scope Domain, each of them is applied!

The corresponding concept of Java 'packages', in C++ and C# are 'namespaces'. Unfortunately, ALox is not able to automatically gather information about the namespace that a Log Statement resides in. To achieve a similar functionality in these languages, the way out, is using the path in the file system of the source file that embeds a Log Statement. The prerequisite for this is that all source files are sorted properly into sub-directories according to the namespace they they belong to. For example, a directory tree could look like this:

    /home/user/myproject/src/main.cpp
    /home/user/myproject/src/ui/menu/menu.cpp
    /home/user/myproject/src/ui/dialogs/about.cpp
    /home/user/myproject/src/io/sockets/http.cpp
    /home/user/myproject/src/io/database/mysql.cpp

With a directory structure similar to the one given above, Scope.Path available in ALox for C++/C# works exactly the same as Scope.PACKAGE in Java. A Log Statement which resides in file

    /home/user/myproject/src/ui/dialogs/about.cpp

would have path

    /home/user/myproject/src/ui/dialogs

as associated Scope.Path. Instead of optional paramter \ packageLevel of method Lox.SetDomain, in C++ and and C# the outer directories can simply be reached by adding an integer value specifying the number of directories to cut, to the enumeration element Scope::Path.

Note
This differences in the interface is caused by the fact that Java does not allow to do arithmetics with elements of enumerations. C# allows this and in C++ we use the concept of ALib arithmetical enums.).

If this is used, for values greater than 0, the corresponding amount of directories are cut from the end of the source files' path to determine the parent directory that a Scope Domain should be set for. As with Java packages, Scope.Path can be considered being not just a single Scope, but rather a set of nested scopes itself. All Scope Domains set for a path of a file as well as those set for parent directories within this path, are applied - from the inner path to the outer path.

Note
In general, the organization of the source code in a well structured tree of directories corresponding to the tree of nested namespaces, is a good idea.
If a project using ALox is not organized this way, and there is no possibility to restructure the source tree for this purpose, then the Scope.Path still can be used. It just will not match and reflect the namespace but (quite as its name indicates) the structure of the source tree.
However, if all sources of a project simply reside just in one single directory, then the use of Scope.Path is not advisable. Its effect would be similar to Scope.Global, with the only difference that a thread-related Scope is applied after Scope.Path but before Scope.Global. (Thread-related Scopes are discussed later in this chapter).
Note
Because ALox is designed to tolerate errors as much as possible, the use of values for parameter packageLevel (in Java, respectively in C++/C# the use of adding interger values to enum element Scope::Path) that are higher than the number of sub-packages (respectively directories) that can be cut, does not result in an error. Instead, an empty package/path name is registered and consequently, a registration with, lets say level 42 would simply be overwritten by a subsequent registration with level 43 and the effect would be nearly similar to using Scope.Global.
In C++/C# on Windows OS, still the drive letter would remain and such setting would apply to all source files residing on the corresponding drive.

2.3 Scope.Filename (In Java Scope.CLASS)

Like Scopes Path/PACKAGE, this Scope.Filename/CLASS has a different name and meaning in ALox for C++/C# and ALox for Java. But here it is quite simple.

In Java, Scope.CLASS simply refers to all statements used within a class.

Again, in C++/C# ALox is unable to automatically identify a class name that a Log Statement resides in. Furthermore, in C++ a Log Statement may not even reside within a class. Therefore, the corresponding Scope.Filename in those languages refer to the name of the source file that a Log Statement resides in. In the usual case when each classes' code resides within a dedicated source file, the effect of both Scopes are the same.

Files with the same name, but residing in different directories are treated as different files.

In C++, if the file name has an extension (like .cpp, .hpp, .h, .hxx, etc.), such extension is ignored. This way, by setting a Scope Domain of Scope.Filename e.g. from within a '.cpp' file, such setting also applies to Log Statements occurring in the corresponding '.hpp' file. Again, this is only true if both files reside in the same directory!

2.4 Scope.Method

Scope.Method (in Java Scope.METHOD) comprises all Log Statements which are residing in a certain method. This is the 'most inner' of the language-related set of Scopes supported by ALox. But it is not the most inner of all ALox Scopes, as we will learn later in this chapter.

As Scope.Method is 'language-related', its behavior is like in the programming language in respect to nested method calls: Same as a method variable is not 'visible' within other methods that are invoked from this method, a Scope Domain set in a method is not 'active' within nested, invoked methods. This of-course makes a lot of sense, otherwise Scope Domains of methods would be overwritten or at least redirected by Scope Domains of a calling method.

Note
ALox also provides a feature of adding a Scope Domain for a method and all methods it invokes! The way how to achieve this is described later in this chapter.

2.5 Anonymous Scopes

The programming languages C++, C# and Java, allow to open and close 'anonymous scopes' using curly braces '{' and '}'. For example, a variable declared in such anonymous scope is not visible to the rest of the method. Unfortunately, these anonymous scopes can not be 'detected' by ALox automatically. In C++, with the help of its concept of strict 'stack-unwinding', it would be possible to extend ALox to support inner Scopes for nested blocks that automatically get unset as soon as program execution leaves an anonymous scope. In favor of keeping the different language versions compatible (and also in favor to not overcomplicate things!), this is not offered by ALox.

But there is an obvious way to reach the goal of setting sub-domains for Log Statements within a block of code: Simply equip each Log Statement of an anonymous source scope with a relative path using parameter domain. Such relative domain paths provided with a Log Statement are placed by ALox within the evaluated, resulting domain path, as if they resulted from a Scope Domain setting of an inner Scope of Scope.Method.

2.6 How To Set Scope Domains for Language-Related Scopes

When reading earlier chapter 04 - Log Domains and the later chapters (06 - Lox.Once(), 07 - Prefix Logables and 08 - Log Data (Debug Variables)), you might be surprised, that the only way to use a specific Scope is to do this with an invocation of a corresponding method of class Lox from within that Scope itself.

Why does ALox not provide alternative interfaces that makes it possible to explicitly address a Scope with an invocation from 'outside' of this scope? E.g. why is it not possible to set the scope for a method by naming the class and method, e.g. in the bootstrap section of an application?

The reason is to avoid ambiguities and misconfigurations. If such possibility existed, even if a method class names were given, the same class and method name, might exist in a library, probably using a different namespace. This makes it obvious that the full 'outer' scope has to be provided. Still, adding the namespace in Java would be easily possible, however in C++/C# we are working with the source files' paths and these are quite volatile things. When working in a team, or already when one person is working in parallel on two different machines (at work and at home) the paths may vary. Furthermore any sort of code refactoring in any respect would enforce a 'manual' change of scope specifications.
The errors and hassle that would quickly occur when the explicit naming of Scopes was supported by ALox would not justify the benefits.

But we do not consider this as a restriction. The responsibility for Log Domains names is deemed to rely in 'the hands' of the code that is defining the Log Statements using these Log Domains. The maintainer of a certain subset of a code within a project should know best which domains and sub-domains are to be used. As an exclamation, the use of rather 'global' domains that collect certain information, e.g. "/CONFIG_ERRORS", should be aligned across the team. Usually those domains are addressed using an absolute path within a Log Statement - and hence are not impacted by the Scope and potentially associated Scope Domains anyhow.

Note
There is one obvious use case, that might let you think about changing Scope Domains set in scopes not reachable by your code: This is when for some reason you want to change the domains that a library (or part of the project you do not have access to) uses. To do this, ALox provides a concept called Domain Substitution, described in 15 - Log Domain Substitution. The huge advantage of this approach is, that this feature substitutes all Log Domains, regardless whether they are evaluated by ALox from Scope Domains or if they are given as parameters of the Log Statement.

Having said this, it is agreed and and understood that the definition of Scope Domains of language-related Scopes has to appear in source code within the Scope itself - optionally within an 'inner' Scope of the Scope. For example, within a method of a class, both Scope.Method and Scope.Filename (in Java Scope.CLASS) can be set.

What should be avoided are Contrary settings. If the same Scope is set with different values, the second invocation just replaces the first one. Therefore, some random behavior might appear when the settings of Scope Domains are contrary. For example, a Scope Domain for a package name (Java) or source folder (C++/C#) could be set from different classes belonging to this package, respectively source folder. As a rule of thumb (to avoid double definitions), it is advised to put the registration code to the most central (important) class of such package.

A snapshot of all current settings can be logged using Lox.State (C++, C#, Java) to investigate which settings have been performed. Alternatively, if the snapshot is not enough to understand what is set, overwritten and used where, a live log of ALox' internal messages can be activated to identify exactly what the code is doing in respect to Scope Domains. See 11 - Internal Logging for more information about how to enable internal log messages.

3. Thread-Related Scopes

This section adds two new Scope 'levels', named:

to the ALox Scope feature. As the name indicates, these Scopes create a reference to the thread that is executing a statement that is using values associated with such Scope.

Note
Even if your application is single-threaded, you should continue reading!

Looking at Scope Domains, of-course, they are used to add an additional component to the overall evaluated Log Domains path of a Log Statement. For Scope.ThreadOuter, such addition is performed at the beginning of the evaluated Log Domains path, directly after Scope.Global. For Scope.ThreadInner, the Scope Domain set is appended at the very end of the evaluated Log Domains path. The term 'very end' is important: This is not only the most 'inner' of all Scopes, it is appended to the assembled Log Domains path even after the optional parameter domain of a Log Statement. In other words, it could be said, that Scope.ThreadInner is even more 'inner' than the local, optional parameter domain of a Log Statement.

The whole list of Scope Domains, together with the parameter domain, which are all concatenated (as long as none of them is an absolute path) results to:

  1. [L] Scope.Global
  2. [T] Scope.ThreadOuter
  3. [L] Scope.Path (PACKAGE)
  4. [L] Scope.Filename (CLASS)
  5. [L] Scope.Method
  6. Parameter domain of a Log Statement
  7. [T] Scope.ThreadInner

Remark: [L] and [T] here indicate language-related and thread-related Scopes.

3.1 Use Cases for Scope.ThreadOuter

An important use case for Scope Domains of Scope.ThreadOuter is useful in single-threaded applications, the same as in multi-threaded. If a Scope Domain is set for Scope.ThreadOuter prior to invoking a method (and removed right after the invocation), all subsequent Log Statements are 'redirected' to the domain path specified, covering the whole call stack of nested method calls. This way, a portion of the program execution can be controlled in respect to the Verbosity of Log Statements easily. You can consider this use as being similar to Scope.Method but lasting not only for the method itself but for all statements of recursively invoked methods as well.

In multi-threaded applications, Scope.ThreadOuter is typically used in situations where the log output of different threads should be separately controlled in respect to the Verbosity of their log output. Imagine a background thread that causes trouble but uses the same code and libraries that the rest of the application does. If you now would increase the Verbosity of such Log Domains where the problems occurred, the log output would be 'cluttered' with a lot of Log Statements caused by any thread of the process. Setting Scope.ThreadOuter allows to 'redirect' all such log-output of the thread in question to a dedicated root domain. Now, controlling the Verbosity of the sub-domains of this thread-specific root domain allows to investigate directly what is happening there. This sample addresses debugging and probably a temporary 'redirect' of domains that is removed when a problem is fixed.

But there are also samples where a permanent setting of a Scope.ThreadOuter makes sense. Most operating systems/programming environments are using a dedicated thread implementing the user interface. Handlers of UI-events like mouse clicks are installed and executed on a per event basis. If now, with the very first UI event firing into the user code, (e.g. signaling that the application is now running, or the main window was created), a Scope Domain like 'UI' is registered with Scope.ThreadOuter, all UI related code magically logs into this domain path. As a consequence, no UI-related code like classes for dialog boxes, menu handlers, etc, need to set such domain themselves (e.g. using Scope.Path in a static constructor).
Furthermore, it becomes very obvious from just looking at the sub-domains that get created, when the UI thread is tasked with things that rather should be moved to a different thread to avoid blocking the application for too long.

Note
This last sample nicely shows, how the use of ALox for all debug-logging tasks, leads to new insights of a software, that simple "debug log statements" do not provide!

3.2 Use Cases for Scope.ThreadInner

While technically Scope.ThreadInner is very similar to Scope.ThreadOuter, the effect and use cases still differs slightly. Instead of 'redirecting' just all log output of a thread into a new sub-tree of Log Domains, Scope.ThreadInner splits all 'leafs' of the overall Log Domain tree by adding a thread-dependent Log Domain to those leafs.

When we think about this for a minute, the obvious use case is to filter the log output of specific Sub-Log Domains by thread. First, when a Scope Domain of Scope.ThreadInner is set, the Verbosity of the new sub-domains will not change. This is true, because all new domains that are created by this thread are sub-domains of those Log Domains used before. And such sub-domains just inherit the setting as long as they are not controlled explicitly (as explained in 6.2 Why Does Verbosity Setting Always Work Recursively?). From here, specifically for this thread, the Verbosity of certain domains can now be tweaked until the right set of Log Statements appear.

Imagine a very general class providing a very general feature, hence frequently used by different parts of a software. Increasing the Verbosity of a Log Domains of such class might increase the overall log output too much. Now, by splitting such Log Domains using a Scope Domain for Scope.ThreadInner it becomes possible to either decrease the Verbosity for threads that are not of current interest or by only increasing the Verbosity of the thread of interest.

Finally it is noteworthy to mention the impact of Scope.ThreadInner being the most inner Scope Domain that is evaluated:

  1. A Log Statement that provides an absolute domain path directly in its statement using optional parameter domain, can still be split by Scope Domains of Scope.ThreadInner.
  2. If an absolute domain path is provided for a Scope Domain of Scope.ThreadInner, then this 'flattens' all log output into exactly this single domain. (Even parameter domain of a Log Statement will not be used!)

3.3 Multiple Use of Thread-Related Scopes

We learned in section 2.2 Scope.Path (In Java Scope.PACKAGE), that this Scope through the use of optional parameter pathLevel of method Lox.SetDomain (C++, C#, Java) may be seen as whole set of nested Scopes itself.

The same is true for Scope.ThreadOuter and Scope.ThreadInner! If multiple Scope Domains are set for one of both Scopes, instead of overwriting the previous setting (as done with language-related scopes), such Scope Domains are added to the ones that were previously set.
This is important for almost all use cases described in the previous sections.

Hereby, subsequent settings are 'inner' Scopes of the previous ones. This means, that during program execution the first Scope Domain that is set, results in a higher level within the domain tree. Subsequent Scope Domains set result in direct sub-domains of the former ones.
ALox, when passing a nulled string with parameter scopeDomain of method Lox.SetDomain removes the most recently set Scope Domain first. But also an out-of-order removal of thread-related Scopes is possible. More details on setting and removing Scope Domains for thread-related Scopes is given in the next section.

3.4 How To Set Scope Domains for Thread-Related Scopes

The same method, Lox.SetDomain (C++, C#, Java) which is used for language-related Scopes is used to set and remove thread-related Scopes.

If a domain path is given with parameter scopeDomain and either Scope.ThreadOuter or Scope.ThreadInner for parameter scope, then this domain path is added to the list of corresponding domains set. The list reflects a set of nested Scopes for itself.

To remove the most recently added Scope Domain, it is sufficient to do the same call, with an empty or nulled parameter scopeDomain. Again, this is the same as with removing or 'un-setting' Scope Domains of other Scope types.

For the case that the reverse order of adding and removing thread-related Scope Domains can not be guaranteed, class Lox offers method Lox.RemoveThreadDomain (C++, C#, Java) which accepts the domain path to be removed explicitly as a parameter.

It was discussed in 2.6 How To Set Scope Domains for Language-Related Scopes, that those types of Scopes can only be set from 'within' the Scope to be set (the same or an inner Scope). This is different with thread-related Scopes. Method Lox.SetDomain (C++, C#, Java) as well as Lox.RemoveThreadDomain (C++, C#, Java) accept an optional parameter thread which allows to explicitly provide the thread object to associate a thread-related Scope Domain to. Of-course, if this parameter is omitted, the 'actual Scope', hence the current thread, is used.

Note
In C++, ALib (the utility library that ALox is based on) provides class aworx::Thread, which is mimicking the basic interface of corresponding classes found in the standard class libraries of C# and Java. Usually, a software using ALox would use a different library to create threads. As long as such library is creating 'native' threads of the underlying operating system, this is no issue. To refer to a thread created with a different library, the approach is as follows:
  • from within the thread that is created, static method Thread::GetCurrent (C++) has to be invoked.
  • The pointer to the aworx::Thread object received has to be passed to the scope of the method that is supposed to set a thread-related Scope value for referencing the thread in question.

When things get more complicated, same as with language related scopes, a snapshot of all current settings can be logged using Lox.State (C++, C#, Java) to investigate which settings have been performed.

Alternatively, if the snapshot is not enough to understand what is set, removed and used where, a live log of ALox' internal messages can be activated to identify exactly what the code is doing in respect to Scope Domains. See 11 - Internal Logging for more information about how to enable internal log messages.

4. Wrap up

We want to summarize the takeaways of this chapter:

  • Scopes are used for different features of ALox, as documented in 04 - Log Domains, 06 - Lox.Once(), 07 - Prefix Logables and 08 - Log Data (Debug Variables).
  • Most of the samples and explanations in this chapter are related to Scope Domains.
  • Scopes are nested, we have inner and outer Scopes.
  • Four (programming-)language-related Scopes were introduced. They work similar to scopes of the programming languages.
  • Two thread-related Scopes were introduced. They are runtime Scopes and associated with the thread executing a Log Statement.
  • The two thread-related Scopes differ only in the 'position' within the hierarchy of Scopes.
  • It was explained, that language-related Scopes are set exclusively by statements that are placed within the according Scope itself...
  • ...while thread-related Scopes can also be set from within other threads, by providing the associated object of type Thread explicitly.
  • Repetitive settings of language-related Scopes are overwriting previous settings.
  • Repetitive settings of thread-related Scopes are each acting as a nested, inner scope of the previous setting.
  • Removing Scope Domains is performed by passing a nulled or empty domain path to method Lox.SetDomain. In the case of thread-related Scopes this removes the most recently added Scope Domains. Therefore, if out-of-order removals are needed, method Lox.RemoveThreadDomain is to be used for removal.
  • To investigate into settings of a Lox, two options exist. Either by creating a snapshot of the current setting (using method Lox.State) or by activating internal log messages and observing which setting is made at which position in the source code and which point in time when running a process.

Finally we want to express an important thought: The three concepts of ALox, namely

  1. Hierarchically organized Log Domains,
  2. Nested Scopes and
  3. Scope Domains,

align very nicely. Clever use of them may lead to true "emergence": Suddenly, log output provides more information than the single Log Statements' messages itself. (Similar to water, which has different "emerged" properties than the pure sum of the properties of each of its molecules.)

But, it should not be forgotten what the main purpose of Log Domains is: It is the control of the Verbosity of subsets of Log Statements. In other words, the main purpose of Log Domains is not to understand and analyze the calling hierarchy (call stack) of a piece of code. While ALox may be used to help here quite nicely, there are other software tools and techniques available for accomplishing this.
Therefore our recommendation is: Do not overuse the concept of Scope Domains. With too many Scope Domains set, the original purpose of Log Domains may become harder to achieve. Already the maintenance of Verbosities may start causing some unwanted effort.


Next chapter: 06 - Lox.Once()
Back to index