BDE 4.39.x 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_functional.h>
347#include <bsl_iosfwd.h>
348
349
350namespace ball {
351
352class Attribute;
353class AttributeContainer;
354class Category;
355class CategoryManager;
356class ThresholdAggregate;
357
358 // ==========================================
359 // class AttributeContext_RuleEvaluationCache
360 // ==========================================
361
362/// This is an implementation type of `AttributeContext` and should not be
363/// used by clients of this package. A rule evaluation cache is a mechanism
364/// for evaluating and caching whether a rule is active. A rule is
365/// considered active if all of its attributes are satisfied by the
366/// collection of attributes held in a `AttributeContainerList` object
367/// (i.e., `Rule::evaluate` returns `true` for the `AttributeContainerList`
368/// object). The rules this cache evaluates are contained in a `RuleSet`
369/// object. `RuleSet::MaskType` is a bit mask for a rule set, where each
370/// bit is a boolean value associated with the rule at the corresponding
371/// index in a rule set. An `AttributeContext` determines, using the
372/// `isDataAvailable` method, if a particular set of rules (described using
373/// a bit mask) have already been evaluated. A context accesses the current
374/// cache of rule evaluations using the `knownActiveRules` method. Finally,
375/// a context updates the cache of rule evaluations using the `update` method.
376///
377/// \note Note that the `isDataAvailable` method should be used prior to
378/// using `knownActiveRules` in order to ensure the relevant rules have been
379/// evaluated and that those evaluations are up-to-date.
380///
381/// See @ref ball_attributecontext
383
384 // DATA
385 RuleSet::MaskType d_evalMask; // set of bits, each of which
386 // indicates whether the
387 // corresponding rule has been
388 // evaluated and cached in
389 // `d_resultMask` (1 if evaluated and
390 // 0 otherwise)
391
392 RuleSet::MaskType d_resultMask; // set of bits, each of which caches
393 // the result of the most recent
394 // evaluation of the corresponding
395 // rule (1 if the rule is active and
396 // 0 otherwise)
397
398 bsls::Types::Int64 d_sequenceNumber; // sequence number used to determine
399 // if this cache is in sync with the
400 // rule set maintained by the
401 // category manager (see `update`);
402 // if the sequence number changes it
403 // indicates the cache is out of date
404
405 private:
406 // NOT IMPLEMENTED
411
412 public:
413 // CREATORS
414
415 /// Create an empty rule evaluation cache having a sequence number of -1.
417
418 /// Destroy this object.
420
421 // MANIPULATORS
422
423 /// Clear any currently cached rule evaluation data, restoring this
424 /// object to its default constructed state (empty).
425 void clear();
426
427 /// Update, for the specified `sequenceNumber`, the cache for those
428 /// rules indicated by the specified `relevantRulesMask` bit mask in the
429 /// specified set of `rules`, by evaluating those rules for the
430 /// specified `attributes`; return the bit mask indicating those rules
431 /// that are known to be active. If a bit in the returned bit mask
432 /// value is set to 1, the rule at the corresponding index in `rules` is
433 /// "active"; however, if a bit is set to 0, the corresponding rule is
434 /// either not active *or* has not been evaluated. This operation does,
435 /// however, guarantee that all the rules indicated by the
436 /// `relevantRulesMask` *will* be evaluated. A particular rule is
437 /// considered "active" if all of its attributes are satisfied by
438 /// `attributes` (i.e., if `Rule::evaluate` returns `true` for `attributes`).
439 ///
440 /// \pre The behavior is undefined unless `rules` is not
441 /// modified during this operation (i.e., any lock associated with
442 /// `rules` must be locked during this operation).
444 RuleSet::MaskType relevantRulesMask,
445 const RuleSet& rules,
446 const AttributeContainerList& attributes);
447
448 // ACCESSORS
449
450 /// Return `true` if this cache contains up-to-date cached rule
451 /// evaluations having the specified `sequenceNumber` for the set of
452 /// rules indicated by the specified `relevantRulesMask` bit mask, and
453 /// `false` otherwise.
454 bool isDataAvailable(bsls::Types::Int64 sequenceNumber,
455 RuleSet::MaskType relevantRulesMask) const;
456
457 /// Return a bit mask indicating those rules, from the set of rules
458 /// provided in the last call to `update`, that are known to be active
459 /// (as of that last call to `update`). If a bit in the returned value
460 /// is set to 1, the rule at the corresponding index is active; however,
461 /// if a bit is set to 0, the corresponding rule is either not active *or* has not been evaluated.
462 ///
463 /// \note Note that `isDataAvailable` should be
464 /// called to test if this cache contains up-to-date evaluated rule
465 /// information for the rules in which they are interested before using
466 /// the result of this method.
468
469 /// Format this object to the specified output `stream` at the (absolute
470 /// value of) the optionally specified indentation `level` and return a
471 /// reference to `stream`. If `level` is specified, optionally specify
472 /// `spacesPerLevel`, the number of spaces per indentation level for
473 /// this and all of its nested objects. If `level` is negative,
474 /// suppress indentation of the first line. If `spacesPerLevel` is
475 /// negative, format the entire output on one line, suppressing all but
476 /// the initial indentation (as governed by `level`). If `stream` is
477 /// not valid on entry, this operation has no effect.
478 bsl::ostream& print(bsl::ostream& stream,
479 int level = 0,
480 int spacesPerLevel = 4) const;
481};
482
483// FREE OPERATORS
484
485/// Write a description of the data members of the specified `cache` to the
486/// specified `stream` in some single-line human readable format, and return
487/// the modifiable `stream`.
488bsl::ostream& operator<<(
489 bsl::ostream& stream,
491
492 // ======================
493 // class AttributeContext
494 // ======================
495
496/// This class provides a mechanism for associating attributes with the
497/// current thread, and evaluating the logging rules associated with a
498/// category using those stored attributes. `AttributeContext` contains
499/// class data members that must be initialized (using the `initialize`
500/// class method) with a `CategoryManager` object containing a `RuleSet`
501/// that represents the currently installed logging rules for the process.
502/// Clients can obtain the context for the current thread by calling the
503/// `getContext` class method. The `addAttributes` and `removeAttributes`
504/// methods are used to add and remove collections of attributes from the
505/// (thread-local) context object. Finally, `AttributeContext` provides
506/// methods (used primarily by other components in the `ball` package') to
507/// determine the effect of the current logging rules on the logging
508/// thresholds of a category. The `hasRelevantActiveRules` method returns
509/// `true` if there are any relevant and active rules that might modify the
510/// logging thresholds of the supplied category. A rule is "relevant" if
511/// the rule's pattern matches the category's name, and a rule is "active"
512/// if all the attributes defined for the rule are satisfied by the current
513/// thread's attributes (i.e., `Rule::evaluate` returns `true` for the
514/// collection of attributes maintained for the current thread by the
515/// thread's `AttributeContext` object). The `determineThresholdLevels`
516/// method returns the logging threshold levels for a category, factoring in
517/// any active rules that apply to the category that might override the
518/// category's thresholds. The behavior for the `hasRelevantActiveRules`
519/// and `determineThresholdLevels` methods is undefined unless `initialize` has been called.
520///
521/// \note Note that, in practice, `initialize` is called
522/// *internally* when the logger manager singleton is initialized; clients
523/// ordinarily should not call `initialize` directly.
524///
525/// See @ref ball_attributecontext
527
528 // PRIVATE TYPES
530
531 // CLASS DATA
532 static CategoryManager *s_categoryManager_p; // holds the rule set, rule
533 // set sequence number, and
534 // rule set mutex
535
536 static bslma::Allocator *s_globalAllocator_p; // allocator for thread-
537 // local context objects
538
539 // DATA
540 AttributeContainerList d_containerList; // list of attribute
541 // containers
542
543 mutable RuleEvaluationCache
544 d_ruleCache_p; // cache of rule evaluations
545
546 bslma::Allocator *d_allocator_p; // allocator used to create
547 // this object (held, not
548 // owned)
549
550 // FRIENDS
552
553 private:
554 // NOT IMPLEMENTED
556 AttributeContext& operator=(const AttributeContext&);
557
558 // PRIVATE CLASS METHODS
559
560 /// Return a `const` reference to the singleton key for the thread-local
561 /// storage in which the `AttributeContext` object is stored. This
562 /// method creates the key on the first invocation; all subsequent
563 /// invocations return the key created on the initial call.
564 ///
565 /// \note Note that it is more efficient to cache the return value of this method than
566 /// to invoke it repeatedly.
567 static const bslmt::ThreadUtil::Key& contextKey();
568
569 /// Destroy the `AttributeContext` object pointed to by the specified `arg`.
570 ///
571 /// \note Note that this function is intended to be called by the
572 /// thread-specific storage facility when a thread exits.
573 static void removeContext(void *arg);
574
575 // PRIVATE CREATORS
576
577 /// Create an `AttributeContext` object initially having no attributes.
578 /// Optionally specify a `globalAllocator` used to supply memory. If
579 /// `globalAllocator` is 0, the currently installed global allocator is used.
580 ///
581 /// \note Note that the `getContext` class method must be used to
582 /// obtain the address of the attribute context for the current thread.
583 AttributeContext(bslma::Allocator *globalAllocator = 0);
584
585 /// Destroy this object.
587
588 public:
589 // PUBLIC TYPES
591
592 // CLASS METHODS
593
594 /// Return the address of the current thread's attribute context, if
595 /// such context exists; otherwise, create an attribute context, install
596 /// it in thread-local storage, and return the address of the newly created context.
597 ///
598 /// \note Note that this method can be invoked safely even
599 /// if the `initialize` class method has not yet been called.
601
602 /// Initialize the static data members of `AttributeContext` using the
603 /// specified `categoryManager`. Optionally specify a `globalAllocator`
604 /// used to supply memory. If `globalAllocator` is 0, the currently
605 /// installed global allocator is used. Unless `reset` is subsequently
606 /// called, invoking this method more than once will log an error
607 /// message using `bsls::Log::platformDefaultMessageHandler`, but will have no other effect.
608 ///
609 /// \note Note that in practice this method will be
610 /// called *automatically* when the `LoggerManager` singleton is
611 /// initialized -- i.e., it is not intended to be called directly by
612 /// clients of the `ball` package.
613 static void initialize(CategoryManager *categoryManager,
614 bslma::Allocator *globalAllocator = 0);
615
616 /// Return the address of the modifiable `AttributeContext` object
617 /// installed in local storage for the current thread, or 0 if no attribute context has been created for this thread.
618 ///
619 /// \note Note that this
620 /// method can be invoked safely even if the `initialize` class method
621 /// has not yet been called.
623
624 /// Reset the static data members of `AttributeContext` to their initial
625 /// state (0). Unless `initialize` is subsequently called, invoking this method more than once has no effect.
626 ///
627 /// \note Note that in practice
628 /// this method will be called *automatically* when the `LoggerManager`
629 /// singleton is destroyed -- i.e., it is not intended to be called
630 /// directly by clients of the `ball` package.
631 static void reset();
632
633 /// Invoke the specified `visitor` for all attributes in all attribute
634 /// containers maintained by this object.
635 static void visitAttributes(
636 const bsl::function<void(const ball::Attribute&)>& visitor);
637
638 // MANIPULATORS
639
640 /// Add the specified `attributes` container to the list of attribute
641 /// containers maintained by this object.
642 ///
643 /// \pre The behavior is undefined unless `attributes` remains valid *and* *unmodified* until either
644 /// `attributes` is removed from this context, `clearCache` is called, or this object is destroyed.
645 ///
646 /// \note Note that this method can be invoked
647 /// safely even if the `initialize` class method has not yet been
648 /// called.
649 iterator addAttributes(const AttributeContainer *attributes);
650
651 /// Clear this object's cache of evaluated rules.
652 /// \note Note that this method
653 /// must be called if an `AttributeContainer` object supplied to
654 /// `addAttributes` is modified outside of this context.
655 void clearCache();
656
657 /// Remove the specified `element` from the list of attribute containers maintained by this object.
658 ///
659 /// \note Note that this method can be invoked
660 /// safely even if the `initialize` class method has not yet been
661 /// called.
662 void removeAttributes(iterator element);
663
664 // ACCESSORS
665
666 /// Return `true` if there is at least one rule defined for this process
667 /// that is both "relevant" to the specified `category` and "active",
668 /// and `false` otherwise. A rule is "relevant" to `category` if the
669 /// rule's pattern matches `category->categoryName()`, and a rule is
670 /// "active" if all the attributes defined for that rule are satisfied
671 /// by the current thread's attributes (i.e., `Rule::evaluate` returns
672 /// `true` for the collection of attributes maintained by this object).
673 /// This method operates on the set of rules maintained by the category
674 /// manager supplied to the `initialize` class method (which, in
675 /// practice, should be the global set of rules for the process).
676 ///
677 /// \pre The behavior is undefined unless `initialize` has previously been
678 /// invoked without a subsequent call to `reset`, and `category` is
679 /// contained in the registry maintained by the category manager
680 /// supplied to `initialize`.
681 bool hasRelevantActiveRules(const Category *category) const;
682
683 /// Populate the specified `levels` with the threshold levels for the
684 /// specified `category`. This method compares the threshold levels
685 /// defined by `category` with those of any active rules that apply to
686 /// that category, and determines the minimum severity (i.e., the
687 /// maximum numerical value) for each respective threshold amongst those
688 /// values. A rule applies to `category` if the rule's pattern matches
689 /// `category->categoryName()`, and a rule is active if all the
690 /// attributes defined for that rule are satisfied by the current
691 /// thread's attributes (i.e., `Rule::evaluate` returns `true` for the
692 /// collection of attributes maintained by this object). This method
693 /// operates on the set of rules maintained by the category manager
694 /// supplied to the `initialize` class method (which, in practice,
695 /// should be the global set of rules for the process).
696 ///
697 /// \pre The behavior is undefined unless `initialize` has previously been invoked without a
698 /// subsequent call to `reset`, and `category` is contained in the
699 /// registry maintained by the category manager supplied to
700 /// `initialize`.
702 const Category *category) const;
703
704 /// Return `true` if an attribute having the specified `value` exists in
705 /// any of the attribute containers maintained by this object, and `false` otherwise.
706 ///
707 /// \note Note that this method can be invoked safely even
708 /// if the `initialize` class method has not yet been called.
709 bool hasAttribute(const Attribute& value) const;
710
711 /// Return a `const` reference to the list of attribute containers maintained by this object.
712 ///
713 /// \note Note that this method can be invoked
714 /// safely even if the `initialize` class method has not yet been
715 /// called.
716 const AttributeContainerList& containers() const;
717
718 /// Format this object to the specified output `stream` at the (absolute
719 /// value of) the optionally specified indentation `level` and return a
720 /// reference to `stream`. If `level` is specified, optionally specify
721 /// `spacesPerLevel`, the number of spaces per indentation level for
722 /// this and all of its nested objects. If `level` is negative,
723 /// suppress indentation of the first line. If `spacesPerLevel` is
724 /// negative, format the entire output on one line, suppressing all but
725 /// the initial indentation (as governed by `level`). If `stream` is
726 /// not valid on entry, this operation has no effect.
727 bsl::ostream& print(bsl::ostream& stream,
728 int level = 0,
729 int spacesPerLevel = 4) const;
730};
731
732// FREE OPERATORS
733
734/// Write a description of the data members of the specified `context` to
735/// the specified `stream` in a single-line human readable format, and
736/// return a reference to the modifiable `stream`.
737bsl::ostream& operator<<(bsl::ostream& stream,
738 const AttributeContext& context);
739
740 // =============================
741 // class AttributeContextProctor
742 // =============================
743
744/// This class implements a proctor that, on its own destruction, will destroy
745/// the attribute context of the current thread. Attribute contexts are stored
746/// in thread-local memory. On destruction, objects of this type will
747/// deallocate the current thread's attribute context (if one has been
748/// created), and set the thread-local storage pointer to 0.
749///
750/// See @ref ball_attributecontext
752
753 private:
754 // NOT IMPLEMENTED
757
758 public:
759 // CREATORS
760
761 /// Create an `AttributeContextProctor` object that will destroy the
762 /// current attribute context on destruction.
763 explicit AttributeContextProctor();
764
765 /// Destroy this object (as well as the current attribute context).
767};
768
769// ============================================================================
770// INLINE DEFINITIONS
771// ============================================================================
772
773 // ------------------------------------------
774 // class AttributeContext_RuleEvaluationCache
775 // ------------------------------------------
776
777// CREATORS
778inline
780: d_evalMask(0)
781, d_resultMask(0)
782, d_sequenceNumber(-1)
783{
784}
785
786// MANIPULATORS
787inline
789{
790 d_evalMask = 0;
791 d_resultMask = 0;
792 d_sequenceNumber = -1;
793}
794
795// ACCESSORS
796inline
798 bsls::Types::Int64 sequenceNumber,
799 RuleSet::MaskType relevantRulesMask) const
800{
801 return sequenceNumber == d_sequenceNumber
802 && relevantRulesMask == (relevantRulesMask & d_evalMask);
803}
804
805inline
808{
809 return d_resultMask;
810}
811
812 // ----------------------
813 // class AttributeContext
814 // ----------------------
815
816// MANIPULATORS
817inline
820{
821 BSLS_ASSERT(attributes);
822
823 d_ruleCache_p.clear();
824 return d_containerList.pushFront(attributes);
825}
826
827inline
829{
830 d_ruleCache_p.clear();
831}
832
833inline
835{
836 d_ruleCache_p.clear();
837 d_containerList.remove(element);
838}
839
840// ACCESSORS
841inline
843{
844 return d_containerList;
845}
846
847inline
849{
850 return d_containerList.hasValue(value);
851}
852
853 // -----------------------------
854 // class AttributeContextProctor
855 // -----------------------------
856
857// CREATORS
858inline
862
863} // close package namespace
864
865// FREE OPERATORS
866inline
867bsl::ostream& ball::operator<<(
868 bsl::ostream& stream,
869 const AttributeContext_RuleEvaluationCache& cache)
870{
871 return cache.print(stream, 0, -1);
872}
873
874inline
875bsl::ostream& ball::operator<<(bsl::ostream& stream,
876 const AttributeContext& context)
877{
878 return context.print(stream, 0, -1);
879}
880
881
882
883#endif
884
885// ----------------------------------------------------------------------------
886// Copyright 2015 Bloomberg Finance L.P.
887//
888// Licensed under the Apache License, Version 2.0 (the "License");
889// you may not use this file except in compliance with the License.
890// You may obtain a copy of the License at
891//
892// http://www.apache.org/licenses/LICENSE-2.0
893//
894// Unless required by applicable law or agreed to in writing, software
895// distributed under the License is distributed on an "AS IS" BASIS,
896// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
897// See the License for the specific language governing permissions and
898// limitations under the License.
899// ----------------------------- END-OF-FILE ----------------------------------
900
901/** @} */
902/** @} */
903/** @} */
Definition ball_attributecontainerlist.h:168
Definition ball_attributecontainerlist.h:271
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:751
~AttributeContextProctor()
Destroy this object (as well as the current attribute context).
AttributeContextProctor()
Definition ball_attributecontext.h:859
Definition ball_attributecontext.h:382
~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:779
RuleSet::MaskType knownActiveRules() const
Definition ball_attributecontext.h:807
void clear()
Definition ball_attributecontext.h:788
bool isDataAvailable(bsls::Types::Int64 sequenceNumber, RuleSet::MaskType relevantRulesMask) const
Definition ball_attributecontext.h:797
Definition ball_attributecontext.h:526
bool hasAttribute(const Attribute &value) const
Definition ball_attributecontext.h:848
static void initialize(CategoryManager *categoryManager, bslma::Allocator *globalAllocator=0)
const AttributeContainerList & containers() const
Definition ball_attributecontext.h:842
static AttributeContext * getContext()
void removeAttributes(iterator element)
Definition ball_attributecontext.h:834
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:590
iterator addAttributes(const AttributeContainer *attributes)
Definition ball_attributecontext.h:819
static AttributeContext * lookupContext()
bool hasRelevantActiveRules(const Category *category) const
void clearCache()
Definition ball_attributecontext.h:828
Definition ball_attribute.h:199
Definition ball_categorymanager.h:426
Definition ball_category.h:184
Definition ball_ruleset.h:151
unsigned int MaskType
Definition ball_ruleset.h:158
Definition ball_thresholdaggregate.h:101
Forward declaration.
Definition bslstl_function.h:946
Definition bslma_allocator.h:545
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
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:403
long long Int64
Definition bsls_types.h:134