BDE 4.14.0 Production release
Loading...
Searching...
No Matches
ball_attributecontext.h
Go to the documentation of this file.
1/// @file ball_attributecontext.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_attributecontext.h -*-C++-*-
8#ifndef INCLUDED_BALL_ATTRIBUTECONTEXT
9#define INCLUDED_BALL_ATTRIBUTECONTEXT
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup ball_attributecontext ball_attributecontext
15/// @brief Provide a container for storing attributes and caching results.
16/// @addtogroup bal
17/// @{
18/// @addtogroup ball
19/// @{
20/// @addtogroup ball_attributecontext
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#ball_attributecontext-purpose"> Purpose</a>
25/// * <a href="#ball_attributecontext-classes"> Classes </a>
26/// * <a href="#ball_attributecontext-description"> Description </a>
27/// * <a href="#ball_attributecontext-active-rules"> Active Rules </a>
28/// * <a href="#ball_attributecontext-usage"> Usage </a>
29/// * <a href="#ball_attributecontext-example-1-managing-attributes"> Example 1: Managing Attributes </a>
30/// * <a href="#ball_attributecontext-example-2-calling-hasrelevantactiverules-and-determinethresholdlevels"> Example 2: Calling hasRelevantActiveRules and determineThresholdLevels </a>
31///
32/// # Purpose {#ball_attributecontext-purpose}
33/// Provide a container for storing attributes and caching results.
34///
35/// # Classes {#ball_attributecontext-classes}
36///
37/// - ball::AttributeContext: thread-local list of attribute containers
38/// - ball::AttributeContextProctor: proctor for deleting an attribute context
39///
40/// @see ball_attributecontainer
41///
42/// # Description {#ball_attributecontext-description}
43/// This component provides a mechanism, `ball::AttributeContext`,
44/// used for storing attributes in thread-local storage and evaluating rules
45/// associated with a given category using those stored attributes, and a scoped
46/// proctor, `ball::AttributeContextProctor`, used for destroying the attribute
47/// context of the current thread.
48///
49/// This component participates in the implementation of "Rule-Based Logging".
50/// For more information on how to use that feature, please see the package
51/// level documentation and usage examples for "Rule-Based Logging".
52///
53/// Clients obtain the attribute context for the current thread by calling the
54/// `getContext` class method. Attributes are added and removed from an
55/// attribute context using the `addAttributes` and `removeAttributes` methods,
56/// respectively. Additionally, `ball::AttributeContext` provides methods, used
57/// primarily by other components in the `ball` package' (see {Active Rules}
58/// below), to determine the effect of the current logging rules on the logging
59/// thresholds of a category.
60///
61/// `ball::AttributeContext` contains class data members that must be
62/// initialized, using the `initialize` class method, with a `CategoryManager`
63/// object containing a `RuleSet` representing the currently installed (global)
64/// logging rules for the process. However, clients generally should not call
65/// `initialize` directly. Instead, `initialize` is called *internally* when
66/// the logger manager singleton is initialized.
67///
68/// ## Active Rules {#ball_attributecontext-active-rules}
69///
70///
71/// `ball::AttributeContext` provides two methods, `hasRelevantActiveRules` and
72/// `determineThresholdLevels`, that are used to determine the effect of the
73/// current logging rules maintained by the category manager on the logging
74/// thresholds of a given category. Note that these methods are generally
75/// intended for use by other components in the `ball` package'.
76///
77/// `hasRelevantActiveRules` returns `true` if there is at least one relevant
78/// and active rule (in the global set of rules) that might modify the logging
79/// thresholds of the supplied `category`. A rule is "relevant" if the rule's
80/// pattern matches the category's name, and a rule is "active" if all the
81/// attributes defined for that rule are satisfied by the current thread's
82/// attributes (i.e., `ball::Rule::evaluate` returns `true` for the collection
83/// of attributes maintained for the current thread by the thread's
84/// `ball::AttributeContext` object).
85///
86/// `determineThresholdLevels` returns the logging threshold levels for a
87/// category, factoring in any active rules that apply to the category that
88/// might override the category's thresholds.
89///
90/// ## Usage {#ball_attributecontext-usage}
91///
92///
93/// This section illustrates the intended use of `ball::AttributeContext`.
94///
95/// ### Example 1: Managing Attributes {#ball_attributecontext-example-1-managing-attributes}
96///
97///
98/// First we will define a thread function that will create and install two
99/// attributes. Note that we will use the `AttributeSet` implementation of the
100/// `ball::AttributeContainer` protocol defined in the component documentation
101/// for @ref ball_attributecontainer ; the `ball` package provides a similar class
102/// in the @ref ball_defaultattributecontainer component.
103/// @code
104/// extern "C" void *workerThread1(void *)
105/// {
106/// @endcode
107/// Inside this thread function, we create an attribute set to hold our
108/// attribute values, then we create two `ball::Attribute` objects and add them
109/// to that set:
110/// @code
111/// AttributeSet attributes;
112/// ball::Attribute a1("uuid", 4044457);
113/// ball::Attribute a2("name", "Gang Chen");
114/// attributes.insert(a1);
115/// attributes.insert(a2);
116/// @endcode
117/// Next, we obtain a reference to the current thread's attribute context using
118/// the `getContext` class method (note that in practice we would use a scoped
119/// guard for this purpose; see @ref ball_scopedattributes ):
120/// @code
121/// ball::AttributeContext *context = ball::AttributeContext::getContext();
122/// assert(context);
123/// assert(context == ball::AttributeContext::lookupContext());
124/// @endcode
125/// We can add our attribute container, `attributes`, to the current context
126/// using the `addAttributes` method. We store the returned iterator so that
127/// we can remove `attributes` before it goes out of scope and is destroyed:
128/// @code
129/// ball::AttributeContext::iterator it =
130/// context->addAttributes(&attributes);
131/// assert(context->hasAttribute(a1));
132/// assert(context->hasAttribute(a2));
133/// @endcode
134/// We then call the `removeAttributes` method to remove the attributes from
135/// the attribute context:
136/// @code
137/// context->removeAttributes(it);
138/// assert(false == context->hasAttribute(a1));
139/// assert(false == context->hasAttribute(a2));
140/// @endcode
141/// This completes the first thread function:
142/// @code
143/// return 0;
144/// }
145/// @endcode
146/// The second thread function will simply verify that there is no currently
147/// available attribute context. Note that attribute contexts are created and
148/// managed by individual threads using thread-specific storage, and that
149/// attribute contexts created by one thread are not visible in any other
150/// threads:
151/// @code
152/// extern "C" void *workerThread2(void *)
153/// {
154/// assert(0 == ball::AttributeContext::lookupContext());
155/// return 0;
156/// }
157/// @endcode
158///
159/// ### Example 2: Calling hasRelevantActiveRules and determineThresholdLevels {#ball_attributecontext-example-2-calling-hasrelevantactiverules-and-determinethresholdlevels}
160///
161///
162/// In this example we demonstrate how to call the `hasRelevantActiveRules` and
163/// `determineThresholdLevels` methods. These methods are used (primarily by
164/// other components in the `ball` package) to determine the effect of the
165/// current logging rules on the logging thresholds of a category. Note that a
166/// rule is "relevant" if the rule's pattern matches the category's name, and a
167/// rule is "active" if `ball::Rule::evaluate` returns `true` for the
168/// collection of attributes maintained for the current thread by the thread's
169/// `ball::AttributeContext` object.
170///
171/// We start by creating a `ball::CategoryManager` and use it to initialize the
172/// static data members of `ball::AttributeContext`. Note that, in practice,
173/// this initialization should *not* be performed by clients of the `ball`
174/// package: `ball::AttributeContext::initialize` is called *internally* as part
175/// of the initialization of the `ball::LoggerManager` singleton.
176/// @code
177/// ball::CategoryManager categoryManager;
178/// ball::AttributeContext::initialize(&categoryManager);
179/// @endcode
180/// Next, we add a category to the category manager. Each created category has
181/// a name and the logging threshold levels for that category. The logging
182/// threshold levels indicate the minimum severity for logged messages that will
183/// trigger the relevant action. The four thresholds are the "record level"
184/// (messages logged with a higher severity than this threshold should be added
185/// to the current logger's record buffer), the "pass-through level" (messages
186/// logged with a severity higher than this threshold should be published
187/// immediately), the "trigger level" (messages logged with a higher severity
188/// than this threshold should trigger the publication of the entire contents of
189/// the current logger's record buffer), and the "trigger-all level" (messages
190/// logged with a higher severity than this threshold should trigger the
191/// publication of every logger's record buffer), respectively. Note that
192/// clients are generally most interested in the "pass-through" threshold level.
193/// Also note that a higher number indicates a lower severity.
194/// @code
195/// const ball::Category *cat1 =
196/// categoryManager.addCategory("MyCategory", 128, 96, 64, 32);
197/// @endcode
198/// Next, we obtain the context for the current thread:
199/// @code
200/// ball::AttributeContext *context = ball::AttributeContext::getContext();
201/// @endcode
202/// We call `hasRelevantActiveRules` on `cat1`. This will be `false` because
203/// we haven't supplied any rules:
204/// @code
205/// assert(!context->hasRelevantActiveRules(cat1));
206/// @endcode
207/// We call `determineThresholdLevels` on `cat1`. This will simply return the
208/// logging threshold levels we defined for `cat1` when it was created because
209/// no rules have been defined that might modify those thresholds:
210/// @code
211/// ball::ThresholdAggregate cat1ThresholdLevels(0, 0, 0, 0);
212/// context->determineThresholdLevels(&cat1ThresholdLevels, cat1);
213/// assert(128 == cat1ThresholdLevels.recordLevel());
214/// assert( 96 == cat1ThresholdLevels.passLevel());
215/// assert( 64 == cat1ThresholdLevels.triggerLevel());
216/// assert( 32 == cat1ThresholdLevels.triggerAllLevel());
217/// @endcode
218/// Next, we create a rule that will apply to those categories whose names match
219/// the pattern "My*", where `*` is a wild-card value. The rule defines a set
220/// of thresholds levels that may override the threshold levels of those
221/// categories whose name matches the rule's pattern:
222/// @code
223/// ball::Rule myRule("My*", 120, 110, 70, 40);
224/// categoryManager.addRule(myRule);
225/// @endcode
226/// Now, we call `hasRelevantActiveRules` again for `cat1`, but this time the
227/// method returns `true` because the rule we just added is both "relevant" to
228/// `cat1` and "active". `myRule` is "relevant" to `cat1` because the name of
229/// `cat1` ("MyCategory") matches the pattern for `myRule` ("My*") (i.e.,
230/// `myRule` applies to `cat1`). `myRule` is also "active" because all the
231/// attributes defined for the rule are satisfied by the current thread (in this
232/// case the rule has no attributes, so the rule is always "active"). Note
233/// that we will discuss the meaning of "active" and the use of attributes later
234/// in this example.
235/// @code
236/// assert(context->hasRelevantActiveRules(cat1));
237/// @endcode
238/// Next, we call `determineThresholdLevels` for `cat1`. This method compares
239/// the threshold levels defined for a category with those of any active rules
240/// that apply to that category, and determines the minimum severity (i.e., the
241/// maximum numerical value) for each respective threshold amongst those values.
242/// @code
243/// ball::ThresholdAggregate thresholdLevels(0, 0, 0, 0);
244/// context->determineThresholdLevels(&thresholdLevels, cat1);
245/// assert(128 == thresholdLevels.recordLevel());
246/// assert(110 == thresholdLevels.passLevel());
247/// assert( 70 == thresholdLevels.triggerLevel());
248/// assert( 40 == thresholdLevels.triggerAllLevel());
249/// @endcode
250/// In this case the "pass-through", "trigger", and "trigger-all" threshold
251/// levels defined by `myRule` (110, 70, and 40) are greater (i.e., define a
252/// lower severity) than those respective values defined for `cat1` (96, 64,
253/// and 32), so those values override the values defined for `cat1`. On the
254/// other hand, the "record" threshold level for `cat1` (128) is greater than
255/// the value defined by `myRule` (120), so the threshold level defined for
256/// `cat1` is returned. In effect, `myRule` has lowered the severity at which
257/// messages logged in the "MyCategory" category will be published immediately,
258/// trigger the publication of the current logger's record buffer, and trigger
259/// the publication of every logger's record buffer.
260///
261/// Next we modify `myRule`, adding an attribute indicating that the rule should
262/// only apply if the attribute context for the current thread contains the
263/// attribute `("uuid", 3938908)`:
264/// @code
265/// categoryManager.removeRule(myRule);
266/// ball::ManagedAttribute attribute("uuid", 3938908);
267/// myRule.addAttribute(attribute);
268/// categorymanager.addRule(myRule);
269/// @endcode
270/// When we again call `hasRelevantActiveRules` for `cat1`, it now returns
271/// `false`. The rule, `myRule`, still applies to `cat1` (i.e., it is still
272/// "relevant" to `cat1`), but the attributes defined by `myRule` are no longer
273/// satisfied by the current thread, i.e., the current thread's attribute
274/// context does not contain an attribute matching `("uuid", 3938908)`.
275/// @code
276/// assert(!context->hasRelevantActiveRules(cat1));
277/// @endcode
278/// Next, we call `determineThresholdLevels` on `cat1` and find that it
279/// returns the threshold levels we defined for `cat1` when we created it:
280/// @code
281/// context->determineThresholdLevels(&thresholdLevels, cat1);
282/// assert(thresholdLevels == cat1ThresholdLevels);
283/// @endcode
284/// Finally, we add an attribute to the current thread's attribute context (as
285/// we did in the first example, "Managing Attributes"). Note that we keep an
286/// iterator referring to the added attributes so that we can remove them before
287/// `attributes` goes out of scope and is destroyed. Also note that the class
288/// `AttributeSet` is defined in the component documentation for
289/// @ref ball_attributecontainer .
290/// @code
291/// AttributeSet attributes;
292/// attributes.insert(ball::Attribute("uuid", 3938908));
293/// ball::AttributeContext::iterator it = context->addAttributes(&attributes);
294/// @endcode
295/// The following call to `hasRelevantActiveRules` will return `true` for `cat1`
296/// because there is at least one rule, `myRule`, that is both "relevant"
297/// (i.e., its pattern matches the category name of `cat1`) and "active" (i.e.,
298/// all of the attributes defined for `myRule` are satisfied by the attributes
299/// held by this thread's attribute context):
300/// @code
301/// assert(context->hasRelevantActiveRules(cat1));
302/// @endcode
303/// Now, when we call `determineThresholdLevels`, it will again return the
304/// maximum threshold level from `cat1` and `myRule`:
305/// @code
306/// context->determineThresholdLevels(&thresholdLevels, cat1);
307/// assert(128 == thresholdLevels.recordLevel());
308/// assert(110 == thresholdLevels.passLevel());
309/// assert( 70 == thresholdLevels.triggerLevel());
310/// assert( 40 == thresholdLevels.triggerAllLevel());
311/// @endcode
312/// We must be careful to remove `attributes` from the attribute context before
313/// it goes out of scope and is destroyed. Note that the `ball` package
314/// provides a component, @ref ball_scopedattributes , for adding, and automatically
315/// removing, attributes from the current thread's attribute context.
316/// @code
317/// context->removeAttributes(it);
318/// @endcode
319/// @}
320/** @} */
321/** @} */
322
323/** @addtogroup bal
324 * @{
325 */
326/** @addtogroup ball
327 * @{
328 */
329/** @addtogroup ball_attributecontext
330 * @{
331 */
332
333#include <balscm_version.h>
334
336#include <ball_ruleset.h>
337
338#include <bslma_allocator.h>
339
340#include <bslmt_threadutil.h>
341
342#include <bsls_assert.h>
343#include <bsls_review.h>
344#include <bsls_types.h>
345
346#include <bsl_iosfwd.h>
347
348
349namespace ball {
350
351class Attribute;
352class AttributeContainer;
353class Category;
354class CategoryManager;
355class ThresholdAggregate;
356
357 // ==========================================
358 // class AttributeContext_RuleEvaluationCache
359 // ==========================================
360
361/// This is an implementation type of `AttributeContext` and should not be
362/// used by clients of this package. A rule evaluation cache is a mechanism
363/// for evaluating and caching whether a rule is active. A rule is
364/// considered active if all of its attributes are satisfied by the
365/// collection of attributes held in a `AttributeContainerList` object
366/// (i.e., `Rule::evaluate` returns `true` for the `AttributeContainerList`
367/// object). The rules this cache evaluates are contained in a `RuleSet`
368/// object. `RuleSet::MaskType` is a bit mask for a rule set, where each
369/// bit is a boolean value associated with the rule at the corresponding
370/// index in a rule set. An `AttributeContext` determines, using the
371/// `isDataAvailable` method, if a particular set of rules (described using
372/// a bit mask) have already been evaluated. A context accesses the current
373/// cache of rule evaluations using the `knownActiveRules` method. Finally,
374/// a context updates the cache of rule evaluations using the `update`
375/// method. Note that the `isDataAvailable` method should be used prior to
376/// using `knownActiveRules` in order to ensure the relevant rules have been
377/// evaluated and that those evaluations are up-to-date.
378///
379/// See @ref ball_attributecontext
381
382 // DATA
383 RuleSet::MaskType d_evalMask; // set of bits, each of which
384 // indicates whether the
385 // corresponding rule has been
386 // evaluated and cached in
387 // `d_resultMask` (1 if evaluated and
388 // 0 otherwise)
389
390 RuleSet::MaskType d_resultMask; // set of bits, each of which caches
391 // the result of the most recent
392 // evaluation of the corresponding
393 // rule (1 if the rule is active and
394 // 0 otherwise)
395
396 bsls::Types::Int64 d_sequenceNumber; // sequence number used to determine
397 // if this cache is in sync with the
398 // rule set maintained by the
399 // category manager (see `update`);
400 // if the sequence number changes it
401 // indicates the cache is out of date
402
403 // NOT IMPLEMENTED
408
409 public:
410 // CREATORS
411
412 /// Create an empty rule evaluation cache having a sequence number of -1.
414
415 /// Destroy this object.
417
418 // MANIPULATORS
419
420 /// Clear any currently cached rule evaluation data, restoring this
421 /// object to its default constructed state (empty).
422 void clear();
423
424 /// Update, for the specified `sequenceNumber`, the cache for those
425 /// rules indicated by the specified `relevantRulesMask` bit mask in the
426 /// specified set of `rules`, by evaluating those rules for the
427 /// specified `attributes`; return the bit mask indicating those rules
428 /// that are known to be active. If a bit in the returned bit mask
429 /// value is set to 1, the rule at the corresponding index in `rules` is
430 /// "active"; however, if a bit is set to 0, the corresponding rule is
431 /// either not active *or* has not been evaluated. This operation does,
432 /// however, guarantee that all the rules indicated by the
433 /// `relevantRulesMask` *will* be evaluated. A particular rule is
434 /// considered "active" if all of its attributes are satisfied by
435 /// `attributes` (i.e., if `Rule::evaluate` returns `true` for
436 /// `attributes`). The behavior is undefined unless `rules` is not
437 /// modified during this operation (i.e., any lock associated with
438 /// `rules` must be locked during this operation).
440 RuleSet::MaskType relevantRulesMask,
441 const RuleSet& rules,
442 const AttributeContainerList& attributes);
443
444 // ACCESSORS
445
446 /// Return `true` if this cache contains up-to-date cached rule
447 /// evaluations having the specified `sequenceNumber` for the set of
448 /// rules indicated by the specified `relevantRulesMask` bit mask, and
449 /// `false` otherwise.
450 bool isDataAvailable(bsls::Types::Int64 sequenceNumber,
451 RuleSet::MaskType relevantRulesMask) const;
452
453 /// Return a bit mask indicating those rules, from the set of rules
454 /// provided in the last call to `update`, that are known to be active
455 /// (as of that last call to `update`). If a bit in the returned value
456 /// is set to 1, the rule at the corresponding index is active; however,
457 /// if a bit is set to 0, the corresponding rule is either not active
458 /// *or* has not been evaluated. Note that `isDataAvailable` should be
459 /// called to test if this cache contains up-to-date evaluated rule
460 /// information for the rules in which they are interested before using
461 /// the result of this method.
463
464 /// Format this object to the specified output `stream` at the (absolute
465 /// value of) the optionally specified indentation `level` and return a
466 /// reference to `stream`. If `level` is specified, optionally specify
467 /// `spacesPerLevel`, the number of spaces per indentation level for
468 /// this and all of its nested objects. If `level` is negative,
469 /// suppress indentation of the first line. If `spacesPerLevel` is
470 /// negative, format the entire output on one line, suppressing all but
471 /// the initial indentation (as governed by `level`). If `stream` is
472 /// not valid on entry, this operation has no effect.
473 bsl::ostream& print(bsl::ostream& stream,
474 int level = 0,
475 int spacesPerLevel = 4) const;
476};
477
478// FREE OPERATORS
479
480/// Write a description of the data members of the specified `cache` to the
481/// specified `stream` in some single-line human readable format, and return
482/// the modifiable `stream`.
483bsl::ostream& operator<<(
484 bsl::ostream& stream,
486
487 // ======================
488 // class AttributeContext
489 // ======================
490
491/// This class provides a mechanism for associating attributes with the
492/// current thread, and evaluating the logging rules associated with a
493/// category using those stored attributes. `AttributeContext` contains
494/// class data members that must be initialized (using the `initialize`
495/// class method) with a `CategoryManager` object containing a `RuleSet`
496/// that represents the currently installed logging rules for the process.
497/// Clients can obtain the context for the current thread by calling the
498/// `getContext` class method. The `addAttributes` and `removeAttributes`
499/// methods are used to add and remove collections of attributes from the
500/// (thread-local) context object. Finally, `AttributeContext` provides
501/// methods (used primarily by other components in the `ball` package') to
502/// determine the effect of the current logging rules on the logging
503/// thresholds of a category. The `hasRelevantActiveRules` method returns
504/// `true` if there are any relevant and active rules that might modify the
505/// logging thresholds of the supplied category. A rule is "relevant" if
506/// the rule's pattern matches the category's name, and a rule is "active"
507/// if all the attributes defined for the rule are satisfied by the current
508/// thread's attributes (i.e., `Rule::evaluate` returns `true` for the
509/// collection of attributes maintained for the current thread by the
510/// thread's `AttributeContext` object). The `determineThresholdLevels`
511/// method returns the logging threshold levels for a category, factoring in
512/// any active rules that apply to the category that might override the
513/// category's thresholds. The behavior for the `hasRelevantActiveRules`
514/// and `determineThresholdLevels` methods is undefined unless `initialize`
515/// has been called. Note that, in practice, `initialize` is called
516/// *internally* when the logger manager singleton is initialized; clients
517/// ordinarily should not call `initialize` directly.
518///
519/// See @ref ball_attributecontext
521
522 // PRIVATE TYPES
524
525 // CLASS DATA
526 static CategoryManager *s_categoryManager_p; // holds the rule set, rule
527 // set sequence number, and
528 // rule set mutex
529
530 static bslma::Allocator *s_globalAllocator_p; // allocator for thread-
531 // local context objects
532
533 // DATA
534 AttributeContainerList d_containerList; // list of attribute
535 // containers
536
537 mutable RuleEvaluationCache
538 d_ruleCache_p; // cache of rule evaluations
539
540 bslma::Allocator *d_allocator_p; // allocator used to create
541 // this object (held, not
542 // owned)
543
544 // FRIENDS
546
547 // NOT IMPLEMENTED
549 AttributeContext& operator=(const AttributeContext&);
550
551 // PRIVATE CLASS METHODS
552
553 /// Return a `const` reference to the singleton key for the thread-local
554 /// storage in which the `AttributeContext` object is stored. This
555 /// method creates the key on the first invocation; all subsequent
556 /// invocations return the key created on the initial call. Note that
557 /// it is more efficient to cache the return value of this method than
558 /// to invoke it repeatedly.
559 static const bslmt::ThreadUtil::Key& contextKey();
560
561 /// Destroy the `AttributeContext` object pointed to by the specified
562 /// `arg`. Note that this function is intended to be called by the
563 /// thread-specific storage facility when a thread exits.
564 static void removeContext(void *arg);
565
566 // PRIVATE CREATORS
567
568 /// Create an `AttributeContext` object initially having no attributes.
569 /// Optionally specify a `globalAllocator` used to supply memory. If
570 /// `globalAllocator` is 0, the currently installed global allocator is
571 /// used. Note that the `getContext` class method must be used to
572 /// obtain the address of the attribute context for the current thread.
573 AttributeContext(bslma::Allocator *globalAllocator = 0);
574
575 /// Destroy this object.
577
578 public:
579 // PUBLIC TYPES
581
582 // CLASS METHODS
583
584 /// Return the address of the current thread's attribute context, if
585 /// such context exists; otherwise, create an attribute context, install
586 /// it in thread-local storage, and return the address of the newly
587 /// created context. Note that this method can be invoked safely even
588 /// if the `initialize` class method has not yet been called.
590
591 /// Initialize the static data members of `AttributeContext` using the
592 /// specified `categoryManager`. Optionally specify a `globalAllocator`
593 /// used to supply memory. If `globalAllocator` is 0, the currently
594 /// installed global allocator is used. Unless `reset` is subsequently
595 /// called, invoking this method more than once will log an error
596 /// message using `bsls::Log::platformDefaultMessageHandler`, but will
597 /// have no other effect. Note that in practice this method will be
598 /// called *automatically* when the `LoggerManager` singleton is
599 /// initialized -- i.e., it is not intended to be called directly by
600 /// clients of the `ball` package.
601 static void initialize(CategoryManager *categoryManager,
602 bslma::Allocator *globalAllocator = 0);
603
604 /// Return the address of the modifiable `AttributeContext` object
605 /// installed in local storage for the current thread, or 0 if no
606 /// attribute context has been created for this thread. Note that this
607 /// method can be invoked safely even if the `initialize` class method
608 /// has not yet been called.
610
611 /// Reset the static data members of `AttributeContext` to their initial
612 /// state (0). Unless `initialize` is subsequently called, invoking
613 /// this method more than once has no effect. Note that in practice
614 /// this method will be called *automatically* when the `LoggerManager`
615 /// singleton is destroyed -- i.e., it is not intended to be called
616 /// directly by clients of the `ball` package.
617 static void reset();
618
619 /// Invoke the specified `visitor` for all attributes in all attribute
620 /// containers maintained by this object.
621 static void visitAttributes(
622 const bsl::function<void(const ball::Attribute&)>& visitor);
623
624 // MANIPULATORS
625
626 /// Add the specified `attributes` container to the list of attribute
627 /// containers maintained by this object. The behavior is undefined
628 /// unless `attributes` remains valid *and* *unmodified* until either
629 /// `attributes` is removed from this context, `clearCache` is called,
630 /// or this object is destroyed. Note that this method can be invoked
631 /// safely even if the `initialize` class method has not yet been
632 /// called.
633 iterator addAttributes(const AttributeContainer *attributes);
634
635 /// Clear this object's cache of evaluated rules. Note that this method
636 /// must be called if an `AttributeContainer` object supplied to
637 /// `addAttributes` is modified outside of this context.
638 void clearCache();
639
640 /// Remove the specified `element` from the list of attribute containers
641 /// maintained by this object. Note that this method can be invoked
642 /// safely even if the `initialize` class method has not yet been
643 /// called.
644 void removeAttributes(iterator element);
645
646 // ACCESSORS
647
648 /// Return `true` if there is at least one rule defined for this process
649 /// that is both "relevant" to the specified `category` and "active",
650 /// and `false` otherwise. A rule is "relevant" to `category` if the
651 /// rule's pattern matches `category->categoryName()`, and a rule is
652 /// "active" if all the attributes defined for that rule are satisfied
653 /// by the current thread's attributes (i.e., `Rule::evaluate` returns
654 /// `true` for the collection of attributes maintained by this object).
655 /// This method operates on the set of rules maintained by the category
656 /// manager supplied to the `initialize` class method (which, in
657 /// practice, should be the global set of rules for the process). The
658 /// behavior is undefined unless `initialize` has previously been
659 /// invoked without a subsequent call to `reset`, and `category` is
660 /// contained in the registry maintained by the category manager
661 /// supplied to `initialize`.
662 bool hasRelevantActiveRules(const Category *category) const;
663
664 /// Populate the specified `levels` with the threshold levels for the
665 /// specified `category`. This method compares the threshold levels
666 /// defined by `category` with those of any active rules that apply to
667 /// that category, and determines the minimum severity (i.e., the
668 /// maximum numerical value) for each respective threshold amongst those
669 /// values. A rule applies to `category` if the rule's pattern matches
670 /// `category->categoryName()`, and a rule is active if all the
671 /// attributes defined for that rule are satisfied by the current
672 /// thread's attributes (i.e., `Rule::evaluate` returns `true` for the
673 /// collection of attributes maintained by this object). This method
674 /// operates on the set of rules maintained by the category manager
675 /// supplied to the `initialize` class method (which, in practice,
676 /// should be the global set of rules for the process). The behavior is
677 /// undefined unless `initialize` has previously been invoked without a
678 /// subsequent call to `reset`, and `category` is contained in the
679 /// registry maintained by the category manager supplied to
680 /// `initialize`.
682 const Category *category) const;
683
684 /// Return `true` if an attribute having the specified `value` exists in
685 /// any of the attribute containers maintained by this object, and
686 /// `false` otherwise. Note that this method can be invoked safely even
687 /// if the `initialize` class method has not yet been called.
688 bool hasAttribute(const Attribute& value) const;
689
690 /// Return a `const` reference to the list of attribute containers
691 /// maintained by this object. Note that this method can be invoked
692 /// safely even if the `initialize` class method has not yet been
693 /// called.
694 const AttributeContainerList& containers() const;
695
696 /// Format this object to the specified output `stream` at the (absolute
697 /// value of) the optionally specified indentation `level` and return a
698 /// reference to `stream`. If `level` is specified, optionally specify
699 /// `spacesPerLevel`, the number of spaces per indentation level for
700 /// this and all of its nested objects. If `level` is negative,
701 /// suppress indentation of the first line. If `spacesPerLevel` is
702 /// negative, format the entire output on one line, suppressing all but
703 /// the initial indentation (as governed by `level`). If `stream` is
704 /// not valid on entry, this operation has no effect.
705 bsl::ostream& print(bsl::ostream& stream,
706 int level = 0,
707 int spacesPerLevel = 4) const;
708};
709
710// FREE OPERATORS
711
712/// Write a description of the data members of the specified `context` to
713/// the specified `stream` in a single-line human readable format, and
714/// return a reference to the modifiable `stream`.
715bsl::ostream& operator<<(bsl::ostream& stream,
716 const AttributeContext& context);
717
718 // =============================
719 // class AttributeContextProctor
720 // =============================
721
722/// This class implements a proctor that, on its own destruction, will destroy
723/// the attribute context of the current thread. Attribute contexts are stored
724/// in thread-local memory. On destruction, objects of this type will
725/// deallocate the current thread's attribute context (if one has been
726/// created), and set the thread-local storage pointer to 0.
727///
728/// See @ref ball_attributecontext
730
731 // NOT IMPLEMENTED
734
735 public:
736 // CREATORS
737
738 /// Create an `AttributeContextProctor` object that will destroy the
739 /// current attribute context on destruction.
740 explicit AttributeContextProctor();
741
742 /// Destroy this object (as well as the current attribute context).
744};
745
746// ============================================================================
747// INLINE DEFINITIONS
748// ============================================================================
749
750 // ------------------------------------------
751 // class AttributeContext_RuleEvaluationCache
752 // ------------------------------------------
753
754// CREATORS
755inline
757: d_evalMask(0)
758, d_resultMask(0)
759, d_sequenceNumber(-1)
760{
761}
762
763// MANIPULATORS
764inline
766{
767 d_evalMask = 0;
768 d_resultMask = 0;
769 d_sequenceNumber = -1;
770}
771
772// ACCESSORS
773inline
775 bsls::Types::Int64 sequenceNumber,
776 RuleSet::MaskType relevantRulesMask) const
777{
778 return sequenceNumber == d_sequenceNumber
779 && relevantRulesMask == (relevantRulesMask & d_evalMask);
780}
781
782inline
785{
786 return d_resultMask;
787}
788
789 // ----------------------
790 // class AttributeContext
791 // ----------------------
792
793// MANIPULATORS
794inline
797{
798 BSLS_ASSERT(attributes);
799
800 d_ruleCache_p.clear();
801 return d_containerList.pushFront(attributes);
802}
803
804inline
806{
807 d_ruleCache_p.clear();
808}
809
810inline
812{
813 d_ruleCache_p.clear();
814 d_containerList.remove(element);
815}
816
817// ACCESSORS
818inline
820{
821 return d_containerList;
822}
823
824inline
826{
827 return d_containerList.hasValue(value);
828}
829
830 // -----------------------------
831 // class AttributeContextProctor
832 // -----------------------------
833
834// CREATORS
835inline
839
840} // close package namespace
841
842// FREE OPERATORS
843inline
844bsl::ostream& ball::operator<<(
845 bsl::ostream& stream,
846 const AttributeContext_RuleEvaluationCache& cache)
847{
848 return cache.print(stream, 0, -1);
849}
850
851inline
852bsl::ostream& ball::operator<<(bsl::ostream& stream,
853 const AttributeContext& context)
854{
855 return context.print(stream, 0, -1);
856}
857
858
859
860#endif
861
862// ----------------------------------------------------------------------------
863// Copyright 2015 Bloomberg Finance L.P.
864//
865// Licensed under the Apache License, Version 2.0 (the "License");
866// you may not use this file except in compliance with the License.
867// You may obtain a copy of the License at
868//
869// http://www.apache.org/licenses/LICENSE-2.0
870//
871// Unless required by applicable law or agreed to in writing, software
872// distributed under the License is distributed on an "AS IS" BASIS,
873// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
874// See the License for the specific language governing permissions and
875// limitations under the License.
876// ----------------------------- END-OF-FILE ----------------------------------
877
878/** @} */
879/** @} */
880/** @} */
Definition ball_attributecontainerlist.h:168
Definition ball_attributecontainerlist.h:267
iterator pushFront(const AttributeContainer *container)
bool hasValue(const Attribute &value) const
void remove(const iterator &element)
Definition ball_attributecontainer.h:426
Definition ball_attributecontext.h:729
~AttributeContextProctor()
Destroy this object (as well as the current attribute context).
AttributeContextProctor()
Definition ball_attributecontext.h:836
Definition ball_attributecontext.h:380
~AttributeContext_RuleEvaluationCache()=default
Destroy this object.
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
RuleSet::MaskType update(bsls::Types::Int64 sequenceNumber, RuleSet::MaskType relevantRulesMask, const RuleSet &rules, const AttributeContainerList &attributes)
AttributeContext_RuleEvaluationCache()
Create an empty rule evaluation cache having a sequence number of -1.
Definition ball_attributecontext.h:756
RuleSet::MaskType knownActiveRules() const
Definition ball_attributecontext.h:784
void clear()
Definition ball_attributecontext.h:765
bool isDataAvailable(bsls::Types::Int64 sequenceNumber, RuleSet::MaskType relevantRulesMask) const
Definition ball_attributecontext.h:774
Definition ball_attributecontext.h:520
bool hasAttribute(const Attribute &value) const
Definition ball_attributecontext.h:825
static void initialize(CategoryManager *categoryManager, bslma::Allocator *globalAllocator=0)
const AttributeContainerList & containers() const
Definition ball_attributecontext.h:819
static AttributeContext * getContext()
void removeAttributes(iterator element)
Definition ball_attributecontext.h:811
void determineThresholdLevels(ThresholdAggregate *levels, const Category *category) const
static void visitAttributes(const bsl::function< void(const ball::Attribute &)> &visitor)
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
AttributeContainerList::iterator iterator
Definition ball_attributecontext.h:580
iterator addAttributes(const AttributeContainer *attributes)
Definition ball_attributecontext.h:796
static AttributeContext * lookupContext()
bool hasRelevantActiveRules(const Category *category) const
void clearCache()
Definition ball_attributecontext.h:805
Definition ball_attribute.h:198
Definition ball_categorymanager.h:231
Definition ball_category.h:184
Definition ball_ruleset.h:151
unsigned int MaskType
Definition ball_ruleset.h:158
Definition ball_thresholdaggregate.h:97
Forward declaration.
Definition bslstl_function.h:934
Definition bslma_allocator.h:457
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition ball_administration.h:214
bsl::ostream & operator<<(bsl::ostream &output, const Attribute &attribute)
Imp::Key Key
Thread-specific key type, used to refer to thread-specific storage.
Definition bslmt_threadutil.h:399
long long Int64
Definition bsls_types.h:132