BDE 4.14.0 Production release
|
Provide a container for storing attributes and caching results.
This component provides a mechanism, ball::AttributeContext
, used for storing attributes in thread-local storage and evaluating rules associated with a given category using those stored attributes, and a scoped proctor, ball::AttributeContextProctor
, used for destroying the attribute context of the current thread.
This component participates in the implementation of "Rule-Based Logging". For more information on how to use that feature, please see the package level documentation and usage examples for "Rule-Based Logging".
Clients obtain the attribute context for the current thread by calling the getContext
class method. Attributes are added and removed from an attribute context using the addAttributes
and removeAttributes
methods, respectively. Additionally, ball::AttributeContext
provides methods, used primarily by other components in the ball
package' (see {Active Rules} below), to determine the effect of the current logging rules on the logging thresholds of a category.
ball::AttributeContext
contains class data members that must be initialized, using the initialize
class method, with a CategoryManager
object containing a RuleSet
representing the currently installed (global) logging rules for the process. However, clients generally should not call initialize
directly. Instead, initialize
is called internally when the logger manager singleton is initialized.
ball::AttributeContext
provides two methods, hasRelevantActiveRules
and determineThresholdLevels
, that are used to determine the effect of the current logging rules maintained by the category manager on the logging thresholds of a given category. Note that these methods are generally intended for use by other components in the ball
package'.
hasRelevantActiveRules
returns true
if there is at least one relevant and active rule (in the global set of rules) that might modify the logging thresholds of the supplied category
. A rule is "relevant" if the rule's pattern matches the category's name, and a rule is "active" if all the attributes defined for that rule are satisfied by the current thread's attributes (i.e., ball::Rule::evaluate
returns true
for the collection of attributes maintained for the current thread by the thread's ball::AttributeContext
object).
determineThresholdLevels
returns the logging threshold levels for a category, factoring in any active rules that apply to the category that might override the category's thresholds.
This section illustrates the intended use of ball::AttributeContext
.
First we will define a thread function that will create and install two attributes. Note that we will use the AttributeSet
implementation of the ball::AttributeContainer
protocol defined in the component documentation for ball_attributecontainer ; the ball
package provides a similar class in the ball_defaultattributecontainer component.
Inside this thread function, we create an attribute set to hold our attribute values, then we create two ball::Attribute
objects and add them to that set:
Next, we obtain a reference to the current thread's attribute context using the getContext
class method (note that in practice we would use a scoped guard for this purpose; see ball_scopedattributes ):
We can add our attribute container, attributes
, to the current context using the addAttributes
method. We store the returned iterator so that we can remove attributes
before it goes out of scope and is destroyed:
We then call the removeAttributes
method to remove the attributes from the attribute context:
This completes the first thread function:
The second thread function will simply verify that there is no currently available attribute context. Note that attribute contexts are created and managed by individual threads using thread-specific storage, and that attribute contexts created by one thread are not visible in any other threads:
In this example we demonstrate how to call the hasRelevantActiveRules
and determineThresholdLevels
methods. These methods are used (primarily by other components in the ball
package) to determine the effect of the current logging rules on the logging thresholds of a category. Note that a rule is "relevant" if the rule's pattern matches the category's name, and a rule is "active" if ball::Rule::evaluate
returns true
for the collection of attributes maintained for the current thread by the thread's ball::AttributeContext
object.
We start by creating a ball::CategoryManager
and use it to initialize the static data members of ball::AttributeContext
. Note that, in practice, this initialization should not be performed by clients of the ball
package: ball::AttributeContext::initialize
is called internally as part of the initialization of the ball::LoggerManager
singleton.
Next, we add a category to the category manager. Each created category has a name and the logging threshold levels for that category. The logging threshold levels indicate the minimum severity for logged messages that will trigger the relevant action. The four thresholds are the "record level" (messages logged with a higher severity than this threshold should be added to the current logger's record buffer), the "pass-through level" (messages logged with a severity higher than this threshold should be published immediately), the "trigger level" (messages logged with a higher severity than this threshold should trigger the publication of the entire contents of the current logger's record buffer), and the "trigger-all level" (messages logged with a higher severity than this threshold should trigger the publication of every logger's record buffer), respectively. Note that clients are generally most interested in the "pass-through" threshold level. Also note that a higher number indicates a lower severity.
Next, we obtain the context for the current thread:
We call hasRelevantActiveRules
on cat1
. This will be false
because we haven't supplied any rules:
We call determineThresholdLevels
on cat1
. This will simply return the logging threshold levels we defined for cat1
when it was created because no rules have been defined that might modify those thresholds:
Next, we create a rule that will apply to those categories whose names match the pattern "My*", where *
is a wild-card value. The rule defines a set of thresholds levels that may override the threshold levels of those categories whose name matches the rule's pattern:
Now, we call hasRelevantActiveRules
again for cat1
, but this time the method returns true
because the rule we just added is both "relevant" to cat1
and "active". myRule
is "relevant" to cat1
because the name of cat1
("MyCategory") matches the pattern for myRule
("My*") (i.e., myRule
applies to cat1
). myRule
is also "active" because all the attributes defined for the rule are satisfied by the current thread (in this case the rule has no attributes, so the rule is always "active"). Note that we will discuss the meaning of "active" and the use of attributes later in this example.
Next, we call determineThresholdLevels
for cat1
. This method compares the threshold levels defined for a category with those of any active rules that apply to that category, and determines the minimum severity (i.e., the maximum numerical value) for each respective threshold amongst those values.
In this case the "pass-through", "trigger", and "trigger-all" threshold levels defined by myRule
(110, 70, and 40) are greater (i.e., define a lower severity) than those respective values defined for cat1
(96, 64, and 32), so those values override the values defined for cat1
. On the other hand, the "record" threshold level for cat1
(128) is greater than the value defined by myRule
(120), so the threshold level defined for cat1
is returned. In effect, myRule
has lowered the severity at which messages logged in the "MyCategory" category will be published immediately, trigger the publication of the current logger's record buffer, and trigger the publication of every logger's record buffer.
Next we modify myRule
, adding an attribute indicating that the rule should only apply if the attribute context for the current thread contains the attribute ("uuid", 3938908)
:
When we again call hasRelevantActiveRules
for cat1
, it now returns false
. The rule, myRule
, still applies to cat1
(i.e., it is still "relevant" to cat1
), but the attributes defined by myRule
are no longer satisfied by the current thread, i.e., the current thread's attribute context does not contain an attribute matching ("uuid", 3938908)
.
Next, we call determineThresholdLevels
on cat1
and find that it returns the threshold levels we defined for cat1
when we created it:
Finally, we add an attribute to the current thread's attribute context (as we did in the first example, "Managing Attributes"). Note that we keep an iterator referring to the added attributes so that we can remove them before attributes
goes out of scope and is destroyed. Also note that the class AttributeSet
is defined in the component documentation for ball_attributecontainer .
The following call to hasRelevantActiveRules
will return true
for cat1
because there is at least one rule, myRule
, that is both "relevant" (i.e., its pattern matches the category name of cat1
) and "active" (i.e., all of the attributes defined for myRule
are satisfied by the attributes held by this thread's attribute context):
Now, when we call determineThresholdLevels
, it will again return the maximum threshold level from cat1
and myRule
:
We must be careful to remove attributes
from the attribute context before it goes out of scope and is destroyed. Note that the ball
package provides a component, ball_scopedattributes , for adding, and automatically removing, attributes from the current thread's attribute context.