BDE 4.39.x Production Release
Loading...
Searching...
No Matches
ball_categorymanager.h
Go to the documentation of this file.
1/// @file ball_categorymanager.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_categorymanager.h -*-C++-*-
8#ifndef INCLUDED_BALL_CATEGORYMANAGER
9#define INCLUDED_BALL_CATEGORYMANAGER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup ball_categorymanager ball_categorymanager
15/// @brief Provide a manager of named categories each having "thresholds".
16/// @addtogroup bal
17/// @{
18/// @addtogroup ball
19/// @{
20/// @addtogroup ball_categorymanager
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#ball_categorymanager-purpose"> Purpose</a>
25/// * <a href="#ball_categorymanager-classes"> Classes </a>
26/// * <a href="#ball_categorymanager-description"> Description </a>
27/// * <a href="#ball_categorymanager-category-threshold-levels"> Category Threshold Levels </a>
28/// * <a href="#ball_categorymanager-non-hierarchical-default-threshold-mechanisms"> Non-Hierarchical Default Threshold Mechanisms </a>
29/// * <a href="#ball_categorymanager-hierarchical-category-management"> Hierarchical Category Management </a>
30/// * <a href="#ball_categorymanager-category-name-filtering"> Category Name Filtering </a>
31/// * <a href="#ball_categorymanager-registry-capacity-management"> Registry Capacity Management </a>
32/// * <a href="#ball_categorymanager-thread-safety"> Thread Safety </a>
33/// * <a href="#ball_categorymanager-usage"> Usage </a>
34/// * <a href="#ball_categorymanager-example-1-basic-usage"> Example 1: Basic Usage </a>
35/// * <a href="#ball_categorymanager-example-2-hierarchical-category-management"> Example 2: Hierarchical Category Management </a>
36///
37/// # Purpose {#ball_categorymanager-purpose}
38/// Provide a manager of named categories each having "thresholds".
39///
40/// # Classes {#ball_categorymanager-classes}
41///
42/// - ball::CategoryManager: manager of category registry
43///
44/// @see ball_category, ball_loggermanager, ball_loggercategoryutil
45///
46/// # Description {#ball_categorymanager-description}
47/// This component provides a registry for category information and
48/// functions to manage the registry and its members. By "category" we mean a
49/// named entity that identifies a region or functional area of a program. A
50/// category name can be an arbitrary string, including the empty string. Note
51/// that category names are case-sensitive.
52///
53/// Associated with each category, besides its name, are four threshold levels
54/// known as "record", "pass", "trigger", and "trigger-all". Threshold levels
55/// are values in the range `[0 .. 255]`. (See the @ref ball_loggermanager
56/// component-level documentation for a typical interpretation of these four
57/// thresholds.)
58///
59/// A category is represented by a `ball::Category` object. Although instances
60/// of `ball::Category` can be created directly, within the BALL logging
61/// framework they are generally created by the `ball::CategoryManager` class.
62/// `ball::CategoryManager` manages a registry of categories and exposes methods
63/// to add new categories to the registry (`addCategory`) and modify the
64/// threshold levels of existing categories (`setThresholdLevels`).
65/// `ball::Category` provides accessors for direct access to the name and
66/// threshold levels of a given category, and a single manipulator to set the
67/// four threshold levels levels (see @ref ball_category ).
68///
69/// ## Category Threshold Levels {#ball_categorymanager-category-threshold-levels}
70///
71///
72/// Every category has four severity threshold levels that govern logging
73/// behavior: **Record**, **Pass**, **Trigger**, and **Trigger-All**. These
74/// threshold levels can be set explicitly when a category is created (via
75/// `addCategory`) or derived from default values when using `addCategory` with
76/// fewer arguments or `addCategoryHierarchically`.
77///
78/// The threshold levels have the following meanings in the logging framework:
79///
80/// * **Record**: If a log message's severity is at least as severe as the
81/// Record threshold, the message will be stored in the logger's record
82/// buffer.
83///
84/// * **Pass**: If a log message's severity is at least as severe as the Pass
85/// threshold, the message will be immediately published to observers.
86///
87/// * **Trigger**: If a log message's severity is at least as severe as the
88/// Trigger threshold, the message will cause immediate publication of that
89/// message and all messages in the logger's record buffer.
90///
91/// * **Trigger-All**: If a log message's severity is at least as severe as the
92/// Trigger-All threshold, the message will cause immediate publication of
93/// that message and all messages stored by all active loggers.
94///
95/// ## Non-Hierarchical Default Threshold Mechanisms {#ball_categorymanager-non-hierarchical-default-threshold-mechanisms}
96///
97///
98/// The category manager provides several mechanisms for determining threshold
99/// levels when categories are created without explicit threshold values:
100///
101/// * **Default Threshold Levels**: The category manager maintains a set of
102/// default threshold levels that can be queried via
103/// `defaultRecordThresholdLevel()`, `defaultPassThresholdLevel()`,
104/// `defaultTriggerThresholdLevel()`, and
105/// `defaultTriggerAllThresholdLevel()`. These defaults can be modified
106/// at any time using `setDefaultThresholdLevels`.
107///
108/// * **Default Threshold Callback**: A `DefaultThresholdLevelsCallback`
109/// functor can be installed (via `setDefaultThresholdLevelsCallback`) to
110/// dynamically compute threshold levels for new categories. When installed,
111/// this callback takes precedence over the (above) default threshold levels
112/// mechanism. The callback receives the category name and loads four
113/// threshold values into output parameters. This allows for sophisticated
114/// threshold management strategies.
115///
116/// * **Factory Default Thresholds**: The "factory defaults" are the
117/// threshold values that the category manager is initialized with at
118/// construction. These values can be restored at any time by calling
119/// `resetDefaultThresholdLevels`.
120///
121/// The precedence order for determining thresholds when creating categories is:
122/// 1. Explicit threshold values provided to `addCategory`
123/// 2. Default threshold callback (if installed)
124/// 3. Current default threshold levels
125///
126/// ## Hierarchical Category Management {#ball_categorymanager-hierarchical-category-management}
127///
128///
129/// While categories are fundamentally flat (category names have no intrinsic
130/// hierarchical structure), the category manager provides functions that
131/// support hierarchical naming conventions. The `addCategoryHierarchically`
132/// method creates a new category that inherits threshold levels from an
133/// existing category whose name is the longest prefix match. The
134/// `setThresholdLevelsHierarchically` method modifies thresholds for all
135/// categories whose names share a common prefix.
136///
137/// For example, consider categories named "EQUITY", "EQUITY.MARKET", and
138/// "EQUITY.MARKET.NYSE". Using `addCategoryHierarchically` to add
139/// "EQUITY.MARKET.NYSE" would cause it to inherit threshold levels from
140/// "EQUITY.MARKET" (the longest prefix match), not from "EQUITY" or the
141/// defaults. Using `setThresholdLevelsHierarchically("EQUITY.MARKET", ...)`
142/// would update both "EQUITY.MARKET" and "EQUITY.MARKET.NYSE", but not
143/// "EQUITY".
144///
145/// This hierarchical support facilitates organizing logging categories into
146/// logical groupings where related categories can share common threshold
147/// configurations while still allowing fine-grained control.
148///
149/// In order to keep the hierarchical category management sane the empty
150/// category (the default category added by `LoggerManager`) is treated as if it
151/// did not exist for hierarchical settings. So when looking for the longest
152/// matching prefix, if it is found to be the empty string, we use the default
153/// threshold levels instead of the levels of the empty category. Similarly,
154/// setting hierarchical levels with an empty prefix will never store an
155/// orphaned setting (even if the default category does not exist) but instead
156/// we just update the threshold levels of all existing categories and drop all
157/// orphaned settings.
158///
159/// ## Category Name Filtering {#ball_categorymanager-category-name-filtering}
160///
161///
162/// Category names can be transformed by a `CategoryNameFilterCallback` functor
163/// before being stored in the registry. This allows for normalization of
164/// category names, such as converting all names to lowercase. When a name
165/// filter is installed (via `setCategoryNameFilterCallback`), it is applied to
166/// every category name on addition and lookup operations, ensuring consistent
167/// naming regardless of how client code specifies names.
168///
169/// ## Registry Capacity Management {#ball_categorymanager-registry-capacity-management}
170///
171///
172/// The category registry can have a maximum capacity limit set via
173/// `setMaxNumCategories`. A value of 0 (the default) means no limit is
174/// imposed. When the limit is reached, attempts to add new categories will
175/// fail (methods that add categories will return null pointers). The current
176/// capacity limit can be queried via `maxNumCategories`, and the current number
177/// of categories via `length`.
178///
179/// ## Thread Safety {#ball_categorymanager-thread-safety}
180///
181///
182/// `ball::CategoryManager` is *thread-safe*, meaning that any operation on the
183/// same instance can be safely invoked from any thread concurrently with any
184/// other operation.
185///
186/// ## Usage {#ball_categorymanager-usage}
187///
188///
189/// This section illustrates intended use of this component.
190///
191/// ### Example 1: Basic Usage {#ball_categorymanager-example-1-basic-usage}
192///
193///
194/// The code fragments in the following example illustrate some basic operations
195/// of category management including (1) adding categories to the registry,
196/// (2) accessing and modifying the threshold levels of existing categories,
197/// and (3) iterating over the categories in the registry.
198///
199/// First we define some hypothetical category names:
200/// @code
201/// const char *myCategories[] = {
202/// "EQUITY.MARKET.NYSE",
203/// "EQUITY.MARKET.NASDAQ",
204/// "EQUITY.GRAPHICS.MATH.FACTORIAL",
205/// "EQUITY.GRAPHICS.MATH.ACKERMANN"
206/// };
207/// @endcode
208/// Next we create a `ball::CategoryManager` named `manager` and use the
209/// `addCategory` method to define a category for each of the names in
210/// `myCategories`. The threshold levels of each of the categories are set to
211/// slightly different values to help distinguish them when they are displayed
212/// later:
213/// @code
214/// ball::CategoryManager manager;
215///
216/// const int NUM_CATEGORIES = sizeof myCategories / sizeof *myCategories;
217/// for (int i = 0; i < NUM_CATEGORIES; ++i) {
218/// manager.addCategory(myCategories[i],
219/// 192 + i, 96 + i, 64 + i, 32 + i);
220/// }
221/// @endcode
222/// In the following, each of the new categories is accessed from the registry
223/// and their names and threshold levels printed:
224/// @code
225/// for (int i = 0; i < NUM_CATEGORIES; ++i) {
226/// const ball::Category *category =
227/// manager.lookupCategory(myCategories[i]);
228/// bsl::cout << "[ " << myCategories[i]
229/// << ", " << category->recordLevel()
230/// << ", " << category->passLevel()
231/// << ", " << category->triggerLevel()
232/// << ", " << category->triggerAllLevel()
233/// << " ]" << bsl::endl;
234/// }
235/// @endcode
236/// The following is printed to `stdout`:
237/// @code
238/// [ EQUITY.MARKET.NYSE, 192, 96, 64, 32 ]
239/// [ EQUITY.MARKET.NASDAQ, 193, 97, 65, 33 ]
240/// [ EQUITY.GRAPHICS.MATH.FACTORIAL, 194, 98, 66, 34 ]
241/// [ EQUITY.GRAPHICS.MATH.ACKERMANN, 195, 99, 67, 35 ]
242/// @endcode
243/// We next use the `setLevels` method of `ball::Category` to adjust the
244/// threshold levels of our categories. The following also demonstrates use of
245/// the `recordLevel`, etc., accessors of `ball::Category`:
246/// @code
247/// for (int i = 0; i < NUM_CATEGORIES; ++i) {
248/// ball::Category *category = manager.lookupCategory(myCategories[i]);
249/// category->setLevels(category->recordLevel() + 1,
250/// category->passLevel() + 1,
251/// category->triggerLevel() + 1,
252/// category->triggerAllLevel() + 1);
253/// }
254/// @endcode
255/// Repeating the second `for` loop from above generates the following output
256/// on `stdout`:
257/// @code
258/// [ EQUITY.MARKET.NYSE, 193, 97, 65, 33 ]
259/// [ EQUITY.MARKET.NASDAQ, 194, 98, 66, 34 ]
260/// [ EQUITY.GRAPHICS.MATH.FACTORIAL, 195, 99, 67, 35 ]
261/// [ EQUITY.GRAPHICS.MATH.ACKERMANN, 196, 100, 68, 36 ]
262/// @endcode
263/// Next we illustrate use of the index operator as a means of iterating over
264/// the registry of categories. In particular, we illustrate an alternate
265/// approach to modifying the threshold levels of our categories by iterating
266/// over the categories in the registry of `manager` to increment their
267/// threshold levels a second time:
268/// @code
269/// for (int i = 0; i < manager.length(); ++i) {
270/// ball::Category& category = manager[i];
271/// category.setLevels(category.recordLevel() + 1,
272/// category.passLevel() + 1,
273/// category.triggerLevel() + 1,
274/// category.triggerAllLevel() + 1);
275/// }
276/// @endcode
277/// Finally, we iterate over the categories in the registry to print them out
278/// one last time:
279/// @code
280/// for (int i = 0; i < manager.length(); ++i) {
281/// const ball::Category& category = manager[i];
282/// bsl::cout << "[ " << category.categoryName()
283/// << ", " << category.recordLevel()
284/// << ", " << category.passLevel()
285/// << ", " << category.triggerLevel()
286/// << ", " << category.triggerAllLevel()
287/// << " ]" << bsl::endl;
288/// }
289/// @endcode
290/// This iteration produces the following output on `stdout`:
291/// @code
292/// [ EQUITY.MARKET.NYSE, 194, 98, 66, 34 ]
293/// [ EQUITY.MARKET.NASDAQ, 195, 99, 67, 35 ]
294/// [ EQUITY.GRAPHICS.MATH.FACTORIAL, 196, 100, 68, 36 ]
295/// [ EQUITY.GRAPHICS.MATH.ACKERMANN, 197, 101, 69, 37 ]
296/// @endcode
297///
298/// ### Example 2: Hierarchical Category Management {#ball_categorymanager-example-2-hierarchical-category-management}
299///
300///
301/// The following example demonstrates hierarchical category management using
302/// `addCategoryHierarchically` and `setThresholdLevelsHierarchically`. These
303/// methods support a hierarchical naming scheme where categories can inherit
304/// threshold levels from ancestor categories based on prefix matching.
305///
306/// First, we create a category manager and set default threshold levels:
307/// @code
308/// ball::CategoryManager manager;
309/// manager.setDefaultThresholdLevels(191, 95, 63, 31);
310/// @endcode
311/// Then, we create two new categories, `"EQ"` and `"EQ.MARKET"`, with
312/// explicitly set threshold levels (different from the defaults):
313/// @code
314/// manager.addCategory("EQ", 192, 96, 64, 32);
315/// manager.addCategory("EQ.MARKET", 193, 97, 65, 33);
316/// @endcode
317/// Next, we add a new category using `addCategoryHierarchically`. This method
318/// finds the longest prefix match among existing categories and inherits
319/// threshold levels from that category:
320/// @code
321/// ball::Category *nyseCategory =
322/// manager.addCategoryHierarchically("EQ.MARKET.NYSE");
323/// @endcode
324/// The new category `"EQ.MARKET.NYSE"` inherits its threshold levels from
325/// `"EQ.MARKET"` (rather than from `"EQ"` or the defaults) because
326/// `"EQ.MARKET"` is the longest prefix match:
327/// @code
328/// assert(193 == nyseCategory->recordLevel());
329/// assert( 97 == nyseCategory->passLevel());
330/// assert( 65 == nyseCategory->triggerLevel());
331/// assert( 33 == nyseCategory->triggerAllLevel());
332/// @endcode
333/// Then, we use `setThresholdLevelsHierarchically` to adjust the threshold
334/// levels for all categories whose name starts with `"EQ.MARKET"`:
335/// @code
336/// int numUpdated = manager.setThresholdLevelsHierarchically("EQ.MARKET",
337/// 194,
338/// 98,
339/// 66,
340/// 34);
341/// assert(2 == numUpdated); // Updated "EQ.MARKET" and "EQ.MARKET.NYSE"
342/// @endcode
343/// We can verify that both `"EQ.MARKET"` and `"EQ.MARKET.NYSE"` have been
344/// updated, while `"EQ"` remains unchanged:
345/// @code
346/// const ball::Category *eqCategory = manager.lookupCategory("EQ");
347/// const ball::Category *marketCategory =
348/// manager.lookupCategory("EQ.MARKET");
349/// const ball::Category *nyseCategory2 =
350/// manager.lookupCategory("EQ.MARKET.NYSE");
351///
352/// assert(192 == eqCategory->recordLevel()); // unchanged
353/// assert(194 == marketCategory->recordLevel()); // updated
354/// assert(194 == nyseCategory2->recordLevel()); // updated
355/// @endcode
356/// Finally, if we add another category under `"EQ.MARKET"` using
357/// `addCategoryHierarchically`, it will inherit the updated thresholds:
358/// @code
359/// ball::Category *nasdaqCategory =
360/// manager.addCategoryHierarchically("EQ.MARKET.NASDAQ");
361/// assert(194 == nasdaqCategory->recordLevel());
362/// assert( 98 == nasdaqCategory->passLevel());
363/// assert( 66 == nasdaqCategory->triggerLevel());
364/// assert( 34 == nasdaqCategory->triggerAllLevel());
365/// @endcode
366/// Note that hierarchical category management facilitates organizing logging
367/// categories into logical groupings where related categories can share common
368/// threshold configurations while still allowing fine-grained control over
369/// individual categories.
370/// @}
371/** @} */
372/** @} */
373
374/** @addtogroup bal
375 * @{
376 */
377/** @addtogroup ball
378 * @{
379 */
380/** @addtogroup ball_categorymanager
381 * @{
382 */
383
384#include <balscm_version.h>
385
386#include <ball_category.h>
391#include <ball_ruleset.h>
394
395#include <bdlb_cstringequalto.h>
396#include <bdlb_cstringhash.h>
397
398#include <bslma_allocator.h>
399
400#include <bslmt_mutex.h>
401#include <bslmt_readlockguard.h>
404#include <bslmt_writelockguard.h>
405
406#include <bsls_atomic.h>
407#include <bsls_types.h>
408
409#include <bsl_string.h>
410#include <bsl_string_view.h>
411#include <bsl_unordered_map.h>
412#include <bsl_vector.h>
413
414
415namespace ball {
416
417 // =====================
418 // class CategoryManager
419 // =====================
420
421/// This class manages a set (or "registry") of categories. Categories may be
422/// added to the registry, but they cannot be removed. However, the threshold
423/// levels of existing categories may be accessed and modified directly.
424///
425/// See @ref ball_categorymanager
427
428 public:
429 // TYPES
430
431 /// `CategoryNameFilterCallback` is the type of the user-supplied functor
432 /// that translates external category names to internal names.
434
435 /// `DefaultThresholdLevelsCallback` is the type of the functor that
436 /// determines default threshold levels for categories added to the
437 /// registry by the `setCategory(const char *)` method.
440
441 private:
442 // PRIVATE TYPES
443 typedef bsl::unordered_map<const char *,
444 int,
447
449
452
454
455 // DATA
456 Category *d_defaultCategory_p;
457 // holds *Default*
458 // *Category*
459
460 mutable bslmt::ReaderWriterMutex d_defaultThresholdsCallbackMutex;
461 // protector
462
463 DefaultThresholdLevelsCallback d_defaultThresholdsCallback;
464 // user defined functor
465 // for obtaining default
466 // threshold levels for a
467 // category name
468
469 mutable bslmt::ReaderWriterMutex d_defaultThresholdsLevelsMutex;
470 // protector
471
472 ThresholdAggregate d_defaultThresholdLevels;
473 // default threshold
474 // level values
475
476 const ThresholdAggregate d_factoryThresholdLevels;
477 // factory default
478 // threshold levels
479
480 CategoryNameFilterCallback d_categoryNameFilterCallback;
481 // category name filter
482 // functor
483
484 unsigned int d_maxNumCategoriesMinusOne;
485 // one less than the
486 // current allowed
487 // capacity of this
488 // registry
489
490 CategoryMap d_registry; // mapping names to
491 // indices in
492 // `d_categories`
493
494 bsls::AtomicInt64 d_ruleSetSequenceNumber;
495 // sequence number that
496 // is incremented each
497 // time the rule set is
498 // changed
499
500 RuleSet d_ruleSet; // rule set that contains
501 // all registered rules
502
503 bslmt::Mutex d_ruleSetMutex; // serialize access to
504 // `d_ruleset`
505
506 CategoryPtrVector d_categories; // providing random
507 // access to categories
508
509 CategoryPrefixer d_categoryPrefixer;
510 // Data structure that
511 // maps category names
512 // as prefixes to
513 // threshold settings to
514 // support quick
515 // hierarchical
516 // operations on
517 // prefixes of category
518 // name (not O(N)).
519 // Note that it maps to
520 // indexes into
521 // `d_categories`.
522
523 HierarchicalSettings d_orphanHierarchicalSettings;
524 // A data structure that
525 // contains hierarchical
526 // category threshold
527 // level settings that
528 // have no corresponding
529 // category name for
530 // their category name
531 // prefix. The data
532 // structure efficiently
533 // maps the category
534 // prefix to the
535 // settings object for
536 // optimal prefix-based
537 // operations.
538
539 mutable bslmt::ReaderWriterLock d_registryLock; // ensuring MT-safety of
540 // category map
541
542 bslma::Allocator *d_allocator_p; // memory allocator
543 // (held, not owned)
544
545 private:
546 // NOT IMPLEMENTED
548 CategoryManager& operator=(const CategoryManager&);
549
550 // PRIVATE MANIPULATORS
551
552 /// Add to the registry of this category manager a category having the
553 /// specified `filteredCategoryName` and the specified `recordLevel`,
554 /// `passLevel`, `triggerLevel`, and `triggerAllLevel` threshold values,
555 /// respectively, if there is no category having `filteredCategoryName` and
556 /// each of the specified threshold values is in the range `[0 .. 255]`.
557 /// Return the address of the newly-created, modifiable category on
558 /// success, and 0 otherwise. If a newly-created category is returned and
559 /// the specified `categoryHolder` is non-null, then also load into
560 /// `categoryHolder` the returned category and its maximum level and link `categoryHolder` to the category.
561 ///
562 /// \note Note that if a category having
563 /// `filteredCategoryName` already exists in the registry, 0 is returned.
564 Category *addFilteredCategory(CategoryHolder *categoryHolder,
565 const char *filteredCategoryName,
566 int recordLevel,
567 int passLevel,
568 int triggerLevel,
569 int triggerAllLevel);
570
571 /// Add to the registry of this category manager a category having the
572 /// specified `filteredCategoryName` and the specified `recordLevel`,
573 /// `passLevel`, `triggerLevel`, and `triggerAllLevel` threshold values,
574 /// respectively. Return the address of the newly-created, modifiable category.
575 ///
576 /// \pre The behavior is undefined unless a category having
577 /// `filteredCategoryName` does not already exist in the registry and each
578 /// of the specified threshold values is in the range `[0 .. 255]`. The
579 /// behavior is also undefined unless the caller holds a write lock on the
580 /// `d_registryLock` mutex.
581 Category *addNewCategory(const char *filteredCategoryName,
582 int recordLevel,
583 int passLevel,
584 int triggerLevel,
585 int triggerAllLevel);
586
587 /// Return the address of the modifiable category having the specified
588 /// `filteredCategoryName` in the registry of this category manager, or 0 if no such category exists.
589 ///
590 /// \pre The behavior is undefined if the caller
591 /// holds a read or write lock on the `d_registryLock` mutex.
592 Category *lookupFilteredCategory(const char *filteredCategoryName);
593
594 /// Return the address of the modifiable category having the specified
595 /// `filteredCategoryName` in the registry of this category manager, or 0
596 /// if no such category exists. If a category is returned and the
597 /// specified `categoryHolder` is non-null, then also load into
598 /// `categoryHolder` the returned category and its maximum level and link
599 /// `categoryHolder` to the category if it has not yet been linked.
600 ///
601 /// \pre The behavior is undefined if the caller holds a read or write lock on the
602 /// `d_registryLock` mutex.
603 Category *lookupFilteredCategory(CategoryHolder *categoryHolder,
604 const char *filteredCategoryName);
605
606 /// Apply all rules in the rule set to the specified `category`.
607 ///
608 /// \pre The behavior is undefined unless the caller holds a lock on the
609 /// `d_ruleSetMutex` mutex.
610 void privateApplyRulesToCategory(Category *category);
611
612 /// Apply all rules in the rule set to all categories. Use the
613 /// specified `ruleGuard` to provide synchronization.
614 ///
615 /// \pre The behavior is undefined unless `ruleGuard` holds a lock on `d_ruleSetMutex`.
616 ///
617 /// \note Note that all methods that modify the rule set must lock `d_ruleSetMutex`
618 /// to perform that modification, so passing the guard avoids needlessly
619 /// unlocking and re-locking the mutex.
620 void privateApplyRulesToAllCategories(
622
623 // PRIVATE ACCESSORS
624
625 /// If `d_categoryNameFilter` is a non-null functor, apply
626 /// `d_categoryNameFilter` to the specified `originalName`, store the
627 /// translated result in the specified `filteredNameBuffer`, and return the
628 /// address of the non-modifiable data of `filteredNameBuffer`; return
629 /// `originalName` otherwise (i.e., if `d_categoryNameFilter` is null).
630 const char *filterCategoryName(bsl::string *filteredNameBuffer,
631 const char *originalName) const;
632
633 /// Return the address of the non-modifiable category having the specified
634 /// `filteredCategoryName` in the registry of this category manager, or 0 if no such category exists.
635 ///
636 /// \pre The behavior is undefined if the caller
637 /// holds a read or write lock on the `d_registryLock` mutex.
638 const Category *lookupFilteredCategory(
639 const char *filteredCategoryName) const;
640
641 public:
642 // BDE_VERIFY pragma: push
643 // BDE_VERIFY pragma: -FABC01 // Functions not in alphanumeric order
644
645 // CREATORS
646
647 /// Create a category manager with the hardwired default levels for new
648 /// categories and no defaults or namefilter callback set. Optionally
649 /// specify a `basicAllocator` used to supply memory. If `basicAllocator`
650 /// is 0, the currently installed default allocator is used.
651 explicit CategoryManager(bslma::Allocator *basicAllocator = 0);
652
653 /// Create a category manager with the specified default threshold level
654 /// values `defaultRecordLevel`, `defaultPassLevel`, `defaultTriggerLevel`,
655 /// `defaultTriggerAllLevel`, the `defaultThresholdLevelsCallback`, and
656 /// the `categoryNameFilterCallback`. Optionally specify a
657 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0, the
658 /// currently installed default allocator is used.
660 int defaultRecordLevel,
661 int defaultPassLevel,
662 int defaultTriggerLevel,
663 int defaultTriggerAllLevel,
664 const DefaultThresholdLevelsCallback& defaultThresholdLevelsCallback,
665 const CategoryNameFilterCallback& categoryNameFilterCallback,
666 bslma::Allocator *basicAllocator = 0);
667
668 /// Destroy this category manager.
670
671 // MANIPULATORS
672
673 /// Return a non-`const` reference to the category at the specified
674 /// `index` in the registry of this category manager.
675 ///
676 /// \pre The behavior is undefined unless `0 <= index < length()`.
677 Category& operator[](int index);
678
679 /// Add to the registry of this category manager a category having the
680 /// specified `categoryName`, possibly changed by the registered category
681 /// name filter callback, and having the specified `recordLevel`,
682 /// `passLevel`, `triggerLevel`, and `triggerAllLevel` threshold values,
683 /// respectively, if there is no category having (the possibly filtered)
684 /// `categoryName` and each of the specified threshold values is in the
685 /// range `[0 .. 255]`. Return the address of the newly-created,
686 /// modifiable category on success, and 0 otherwise.
687 ///
688 /// \pre The behavior is undefined unless a lock is not held by this thread on the mutex returned by `rulesetMutex`.
689 ///
690 /// \note Note that if a category having (the
691 /// possibly filtered) `categoryName` already exists in the registry, 0 is returned.
692 ///
693 /// \note Note that an existing category will not be modified if a
694 /// category with the (possibly filtered) `categoryName` already exists.
695 Category *addCategory(const char *categoryName,
696 int recordLevel,
697 int passLevel,
698 int triggerLevel,
699 int triggerAllLevel);
700
701 /// Add to the registry of this category manager a category having the
702 /// specified `categoryName`, possibly changed by the registered category
703 /// name filter callback, and having the specified `recordLevel`,
704 /// `passLevel`, `triggerLevel`, and `triggerAllLevel` threshold values,
705 /// respectively, if there is no category having (the possibly filtered)
706 /// `categoryName` and each of the specified threshold values is in the
707 /// range `[0 .. 255]`. Return the address of the newly-created,
708 /// modifiable category on success, and 0 otherwise. If a newly-created
709 /// category is returned and the specified `categoryHolder` is non-null,
710 /// then also load into `categoryHolder` the returned category and its
711 /// maximum level and link `categoryHolder` to the category.
712 ///
713 /// \pre The behavior is undefined unless a lock is not held by this thread on the mutex returned by `rulesetMutex`.
714 ///
715 /// \note Note that if a category having (the
716 /// possibly filtered) `categoryName` already exists in the registry, 0 is returned.
717 ///
718 /// \note Note that an existing category will not be modified if a
719 /// category with the (possibly filtered) `categoryName` already exists.
721 const char *categoryName,
722 int recordLevel,
723 int passLevel,
724 int triggerLevel,
725 int triggerAllLevel);
726
727 /// Add a new category with the specified `categoryName`, possibly changed
728 /// by the registered category name filter callback, unless it already
729 /// exists. Return a pointer to the newly added category in case it did
730 /// not already exist. Determine the threshold levels for the category by
731 /// finding the longest category name or category name prefix that is a
732 /// prefix of this (possibly filtered) `categoryName` and use its settings.
733 /// If no such category or category hierarchical setting exists use the
734 /// defaults. Otherwise, if a category already exists with (the possibly
735 /// filtered) `categoryName` do nothing and return 0.
736 Category *addCategoryHierarchically(const char *categoryName);
737
738 /// If this method is called the first time (`d_defaultCategory_p` is
739 /// null) add a new category with the (unspecified) default category name
740 /// (possibly changed by the registered category name filter callback).
741 /// Use the default threshold levels for the new category.
742 ///
743 /// \pre The behavior is undefined if the default category already exists but has not been added
744 /// by this method.
746
747 /// Return a non-`const` reference to the *Default* *Category* in this category registry.
748 ///
749 /// \pre The behavior is undefined unless
750 /// `addDefaultCategory` has been called.
752
753 /// Return the address of the modifiable category having the specified
754 /// `categoryName`in the registry of this category manager, or 0 if no such category exists.
755 ///
756 /// \note Note that the category name is possibly changed
757 /// by the registered category name filter callback before the lookup.
758 Category *lookupCategory(const char *categoryName);
759
760 /// Return the address of the modifiable category having the specified
761 /// `categoryName` in the registry of this category manager, or 0 if no
762 /// such category exists. If a category is returned and the specified
763 /// `categoryHolder` is non-null, then also load into `categoryHolder`
764 /// the returned category and its maximum level and link
765 /// `categoryHolder` to the category if it has not yet been linked.
766 ///
767 /// \note Note that the category name is possibly changed by the registered category
768 /// name filter callback before the lookup.
770 const char *categoryName);
771
772 /// Reset the category holders to which all categories in the registry
773 /// of this category manager are linked to their default value. See the
774 /// function-level documentation of `CategoryHolder::reset()` for
775 /// further information on the default value of category holders.
777
778 /// Reset the default threshold levels to the original "factory-supplied"
779 /// default values or the factory overrides supplied at construction.
781
782 /// Add to this category registry a new category having the specified
783 /// `categoryName`, possibly changed by the registered category name filter
784 /// callback, and default threshold levels if (the possibly filtered)
785 /// `categoryName` is not present in the registry and the number of
786 /// categories in the registry is less than the registry capacity. Return
787 /// the address of the (possibly newly-created) non-modifiable category
788 /// having (the possibly filtered) `categoryName`, if such a category
789 /// exists, and the address of the non-modifiable *Default* *Category* otherwise.
790 ///
791 /// \pre The behavior is undefined unless `categoryName` is null-terminated.
792 ///
793 /// \note Note that a valid category address is *always*
794 /// returned.
795 const Category *setCategory(const char *categoryName);
796
797 /// Add to this category registry a new category having the specified
798 /// `categoryName`, possibly changed by the registered category name filter
799 /// callback, and default threshold levels if (the possibly filtered)
800 /// `categoryName` is not present in the registry and the number of
801 /// categories in the registry is less than the registry capacity. Return
802 /// the address of the (possibly newly-created) non-modifiable category
803 /// having (the possibly filtered) `categoryName`, if such a category
804 /// exists, and the address of the non-modifiable *Default* *Category*
805 /// otherwise. If the specified `categoryHolder` is non-null, then also
806 /// load into `categoryHolder` the returned category and its maximum level
807 /// and link `categoryHolder` to the category if it has not yet been linked.
808 ///
809 /// \pre The behavior is undefined unless `categoryName` is null-terminated.
810 ///
811 /// \note Note that a valid category address is *always*
812 /// returned.
813 const Category *setCategory(CategoryHolder *categoryHolder,
814 const char *categoryName);
815
816 /// Add to this category registry a new category having the specified
817 /// `categoryName`, possibly changed by the registered category name filter
818 /// callback, and having `recordLevel`, `passLevel`, `triggerLevel`, and
819 /// `triggerAllLevel` threshold levels, respectively, if (1) (the possibly
820 /// filtered) `categoryName` is not present in the registry, (2) the number
821 /// of categories in the registry is less than the registry capacity, and
822 /// (3) `recordLevel`, `passLevel`, `triggerLevel`, and `triggerAllLevel`
823 /// are all within the range `[0 .. 255]`. If (the possibly filtered)
824 /// `categoryName` is already present and each threshold level is within
825 /// the valid range then reset the threshold levels of (the possibly
826 /// filtered) `categoryName` to the specified values. Return the address
827 /// of the (possibly newly-created) modifiable category having (the
828 /// possibly filtered) `categoryName` if that `categoryName` was either
829 /// created or its thresholds reset, and 0 otherwise.
830 ///
831 /// \pre The behavior is undefined unless `categoryName` is null-terminated.
832 /// \note Note that 0, and
833 /// *not* the *Default* *Category*, is returned on failure.
834 Category *setCategory(const char *categoryName,
835 int recordLevel,
836 int passLevel,
837 int triggerLevel,
838 int triggerAllLevel);
839
840 /// Set the default threshold levels to the specified `recordLevel`,
841 /// `passLevel`, `triggerLevel`, and `triggerAllLevel` values,
842 /// respectively, if each threshold level is in the range `[0 .. 255]`.
843 /// Return 0 on success, and a non-zero value otherwise (with no effect on
844 /// any of the default threshold levels).
845 int setDefaultThresholdLevels(int recordLevel,
846 int passLevel,
847 int triggerLevel,
848 int triggerAllLevel);
849
850 /// Set the default-thresholds callback to the specified
851 /// `defaultThresholdLevelsCallback` if it is not null, and remove any
852 /// existing callback if `defaultThresholdLevelsCallback` is null.
854 const DefaultThresholdLevelsCallback *defaultThresholdLevelsCallback);
855
856 /// Set the threshold levels of the category having the specified
857 /// `categoryName`, possibly changed by the registered category name filter
858 /// callback, in the registry of this category manager to the specified
859 /// `recordLevel`, `passLevel`, `triggerLevel`, and `triggerAllLevel`
860 /// values, respectively, if a category having (the possibly filtered)
861 /// `categoryName` exists and each of the specified threshold values is in
862 /// the range `[0 .. 255]`. Otherwise, add to the registry a category
863 /// having (the possibly filtered) `categoryName` and `recordLevel`,
864 /// `passLevel`, `triggerLevel`, and `triggerAllLevel` threshold values,
865 /// respectively, if there is no category having (the possibly filtered)
866 /// `categoryName` and each of the specified threshold values is in the
867 /// range `[0 .. 255]`. Return the address of the (possibly newly-created)
868 /// modifiable category on success, and 0 otherwise (with no effect on any category).
869 ///
870 /// \pre The behavior is undefined unless a lock is not held by this
871 /// thread on the mutex returned by `rulesetMutex`.
872 Category *setThresholdLevels(const char *categoryName,
873 int recordLevel,
874 int passLevel,
875 int triggerLevel,
876 int triggerAllLevel);
877
878 /// Set the threshold levels of all existing and future categories whose
879 /// name starts with the specified `categoryNamePrefix` unless it is empty,
880 /// possibly changed by the registered category name filter callback, to
881 /// the specified `recordLevel`, `passLevel`, `triggerLevel`, and
882 /// `triggerAllLevel` if those levels form valid settings and return the
883 /// number of categories updated (zero or a positive number). In case
884 /// `categoryNamePrefix` is empty update all categories with the threshold
885 /// levels and delete all stored orphan hierarchical settings. In other
886 /// words an empty category setting will never overwrite the defaults for future hierarchical categories.
887 ///
888 /// \pre The behavior is undefined unless a
889 /// lock is not held by this thread on the mutex returned by
890 /// `rulesetMutex`. If any of the specified threshold levels is invalid,
891 /// return a negative value.
892 int setThresholdLevelsHierarchically(const char *categoryNamePrefix,
893 int recordLevel,
894 int passLevel,
895 int triggerLevel,
896 int triggerAllLevel);
897
898 /// Add the specified `ruleToAdd` to the set of (unique) rules maintained
899 /// by this object. Return the number of rules added (i.e., 1 on success
900 /// and 0 if a rule with the same value is already present).
901 ///
902 /// \pre The behavior is undefined unless a lock is not held by this thread on the mutex
903 /// returned by `rulesetMutex`.
904 int addRule(const Rule& ruleToAdd);
905
906 /// Add each rule in the specified `ruleSet` to the set of (unique)
907 /// rules maintained by this object. Return the number of rules added.
908 ///
909 /// \pre The behavior is undefined unless a lock is not held by this thread on the mutex returned by `rulesetMutex`.
910 ///
911 /// \note Note that each rule having
912 /// the same value as an existing rule will be ignored.
914
915 /// Remove the specified `ruleToRemove` from the set of (unique) rules
916 /// maintained by this object. Return the number of rules removed
917 /// (i.e., 1 on success and 0 if no rule having the same value is found).
918 ///
919 /// \pre The behavior is undefined unless a lock is not held by this
920 /// thread on the mutex returned by `rulesetMutex`.
921 int removeRule(const Rule& ruleToRemove);
922
923 /// Remove each rule in the specified `ruleSet` from the set of rules
924 /// maintained by this object. Return the number of rules removed.
925 ///
926 /// \pre The behavior is undefined unless a lock is not held by this thread on
927 /// the mutex returned by `rulesetMutex`.
929
930 /// Remove every rule from the set of rules maintained by this object.
931 ///
932 /// \pre The behavior is undefined unless a lock is not held by this thread
933 /// on the mutex returned by `rulesetMutex`.
935
936 /// Return a non-`const` reference to the mutex that is used to guard
937 /// against concurrent access to the rule set. A lock on the returned
938 /// mutex should be acquired before accessing the properties of the rule set returned by `ruleSet`.
939 ///
940 /// \pre The behavior is undefined unless a lock
941 /// is acquired solely for the purpose of calling `ruleSet`.
943
944 /// Set the capacity of this category registry to the specified `length`.
945 /// If `length` is 0, no limit will be imposed. No categories are removed
946 /// from the registry if the current number of categories exceeds `length`.
947 /// However, subsequent attempts to add categories to the registry will fail.
948 ///
949 /// \pre The behavior is undefined unless `0 <= length`.
950 void setMaxNumCategories(int length);
951
952 /// Invoke the specified `visitor` functor on each category managed by
953 /// this object, supplying that functor modifiable access to each
954 /// category. `visitor` must be a functor that can be called as if it
955 /// had the following signature:
956 /// @code
957 /// void operator()(Category *);
958 /// @endcode
959 ///
960 /// \pre The behavior is undefined if `visitor` calls any method on this
961 /// `CategoryManager` object.
962 template <class t_CATEGORY_VISITOR>
963 void visitCategories(const t_CATEGORY_VISITOR& visitor);
964
965 // ACCESSORS
966
967 /// Return a `const` reference to the category at the specified `index`
968 /// in the registry of this category manager.
969 ///
970 /// \pre The behavior is undefined unless `0 <= index < length()`.
971 const Category& operator[](int index) const;
972
973 /// Return a `const` reference to the *Default* *Category* in this category registry.
974 ///
975 /// \pre The behavior is undefined unless `addDefaultCategory` has
976 /// been called.
977 const Category& defaultCategory() const;
978
979 /// Return the number of categories in the registry of this category
980 /// manager.
981 int length() const;
982
983 /// Return the address of the non-modifiable category having the specified
984 /// `categoryName`, possibly changed by the registered category name filter
985 /// callback, in the registry of this category manager,
986 /// or 0 if no such category exists.
987 const Category *lookupCategory(const char *categoryName) const;
988
989 /// Return the current capacity of this category registry. A capacity of 0
990 /// implies that no limit will be imposed; otherwise, new categories may be
991 /// added only if `numCategories() < maxNumCategories()`.
992 ///
993 /// \note Note that `0 < maxNumCategories() < numCategories()` *is* a valid state, implying
994 /// no new categories may be added.
995 int maxNumCategories() const;
996
997 /// Return a `const` reference to the rule set maintained by this
998 /// category manager. The mutex returned by `rulesetMutex` should be
999 /// locked prior to accessing the rule set.
1000 const RuleSet& ruleSet() const;
1001
1002 /// Return the sequence number that tracks changes to the rule set
1003 /// maintained by this category manager. The value returned by this
1004 /// method is guaranteed to monotonically increase between calls before
1005 /// and after the rule set is changed, and is otherwise implementation
1006 /// defined.
1008
1009 /// Set the threshold levels of the specified `category` in this category
1010 /// registry of this category manager to the current default threshold values.
1011 ///
1012 /// \pre The behavior is undefined unless `category` is non-null.
1014
1015 /// Set the threshold levels of the specified `category` in the category
1016 /// registry of this category manager to the original "factory-supplied"
1017 /// default values or the factory overrides supplied at construction.
1018 ///
1019 /// \pre The behavior is undefined unless `category` is non-null.
1021
1022 /// Invoke the specified `visitor` functor on each category managed by
1023 /// this object, supplying that functor non-modifiable access to each
1024 /// category. `visitor` must be a functor that can be called as if it
1025 /// had the following signature:
1026 /// @code
1027 /// void operator()(const Category *);
1028 /// @endcode
1029 ///
1030 /// \pre The behavior is undefined if `visitor` calls any method on this
1031 /// `CategoryManager` object.
1032 template <class t_CATEGORY_VISITOR>
1033 void visitCategories(const t_CATEGORY_VISITOR& visitor) const;
1034
1035 // Individual Default Levels
1036
1037 /// Return the default pass threshold level of this object.
1039
1040 /// Return the default record threshold level of this object.
1042
1043 /// Return the default trigger-all threshold level of this object.
1045
1046 /// Return the default trigger threshold level of this object.
1048
1049 // Default Levels Aggregate
1050
1051 /// Return the default threshold levels associated with this object.
1053
1054 // Determine Default Threshold Levels
1055
1056 /// Load into the specified `*levels` the threshold levels that would be
1057 /// set for a newly and non-hierarchically created category. Return 0 on
1058 /// success and a non-zero value otherwise. If the client has configured a
1059 /// default threshold levels callback, the `categoryName`, possibly changed
1060 /// by the registered category name filter callback, will be supplied to
1061 /// that callback which will set `*levels`. Otherwise, if no default
1062 /// threshold levels callback has been provided, the default threshold levels are used.
1063 ///
1064 /// \note Note that this function will report an error if the
1065 /// callback returns invalid levels.
1067 const char *categoryName) const;
1068
1069 // BDE_VERIFY pragma: pop
1070};
1071
1072#ifndef BDE_OMIT_INTERNAL_DEPRECATED
1073
1074 // =========================
1075 // class CategoryManagerIter
1076 // =========================
1077
1078/// This class defines an iterator providing sequential, read-only access to
1079/// the categories in the registry of a category manager. The order of the
1080/// iteration is undefined.
1081///
1082/// @deprecated Use @ref CategoryManager::visitCategories accessor
1083/// instead.
1084///
1085/// See @ref ball_categorymanager
1087
1088 // DATA
1089 const CategoryManager *d_cm_p; // associated category manager (held)
1090 int d_index; // index into category manager
1091
1092 private:
1093 // NOT IMPLEMENTED
1095 CategoryManagerIter& operator=(const CategoryManagerIter&);
1096
1097 public:
1098 // CREATORS
1099
1100 /// Create an iterator providing non-modifiable access to the categories
1101 /// in the specified `categoryManager` that is initialized to refer to
1102 /// the first category in the sequence of categories in the registry of
1103 /// `categoryManager`, if one exists, and is initialized to be invalid
1104 /// otherwise. The order of iteration is undefined.
1105 ///
1106 /// \pre The behavior is undefined unless the lifetime of `categoryManager` is at least as
1107 /// long as the lifetime of this iterator.
1108 explicit CategoryManagerIter(const CategoryManager& categoryManager);
1109
1110 /// Destroy this iterator.
1112
1113 // MANIPULATORS
1114
1115 /// Advance this iterator to refer to the next unvisited category. If
1116 /// no such category exists, this iterator becomes invalid.
1117 ///
1118 /// \pre The behavior is undefined unless this iterator is initially valid.
1119 ///
1120 /// \note Note that the order of iteration is undefined.
1121 void operator++();
1122
1123 // ACCESSORS
1124
1125 /// Return a non-zero value if this iterator is valid, and 0 otherwise.
1126 operator const void *() const;
1127
1128 /// Return a `const` reference to the category currently referred to by this iterator.
1129 ///
1130 /// \pre The behavior is undefined unless this iterator is
1131 /// valid.
1132 const Category& operator()() const;
1133};
1134
1135 // ==========================
1136 // class CategoryManagerManip
1137 // ==========================
1138
1139/// This class defines an iterator providing sequential, modifiable access
1140/// to the categories in the registry of a category manager. The order of
1141/// the iteration is undefined.
1142///
1143/// @deprecated Use @ref CategoryManager::visitCategories manipulator
1144/// instead.
1145///
1146/// See @ref ball_categorymanager
1148
1149 // DATA
1150 CategoryManager *d_cm_p; // associated category manager (held)
1151 int d_index; // index into category manager
1152
1153 private:
1154 // NOT IMPLEMENTED
1156 CategoryManagerManip& operator=(const CategoryManagerManip&);
1157
1158 public:
1159 // CREATORS
1160
1161 /// Create an iterator providing modifiable access to the categories in
1162 /// the specified `categoryManager` that is initialized to refer to the
1163 /// first category in the sequence of categories in the registry of
1164 /// `categoryManager`, if one exists, and is initialized to be invalid
1165 /// otherwise. The order of iteration is undefined.
1166 ///
1167 /// \pre The behavior is undefined unless the lifetime of `categoryManager` is at least as
1168 /// long as the lifetime of this iterator.
1169 explicit CategoryManagerManip(CategoryManager *categoryManager);
1170
1171 /// Destroy this iterator.
1173
1174 // MANIPULATORS
1175
1176 /// Advance this iterator to refer to the next unvisited category. If
1177 /// no such category exists, this iterator becomes invalid.
1178 ///
1179 /// \pre The behavior is undefined unless this iterator is initially valid.
1180 ///
1181 /// \note Note that the order of iteration is undefined.
1182 void advance();
1183
1184 /// Return a non-`const` reference to the category currently referred to by this iterator.
1185 ///
1186 /// \pre The behavior is undefined unless this iterator is
1187 /// valid.
1189
1190 // ACCESSORS
1191
1192 /// Return a non-zero value if this iterator is valid, and 0 otherwise.
1193 operator const void *() const;
1194};
1195
1196#endif // BDE_OMIT_INTERNAL_DEPRECATED
1197
1198// ============================================================================
1199// INLINE FUNCTION DEFINITIONS
1200// ============================================================================
1201
1202 // ---------------------
1203 // class CategoryManager
1204 // ---------------------
1205
1206// MANIPULATORS
1207inline
1209{
1210 bslmt::ReadLockGuard<bslmt::ReaderWriterLock> guard(&d_registryLock);
1211 return *d_categories[index];
1212}
1213
1214inline
1215Category *CategoryManager::addCategory(const char *categoryName,
1216 int recordLevel,
1217 int passLevel,
1218 int triggerLevel,
1219 int triggerAllLevel)
1220{
1221 BSLS_ASSERT(categoryName);
1222
1223 return addCategory(0,
1224 categoryName,
1225 recordLevel,
1226 passLevel,
1227 triggerLevel,
1228 triggerAllLevel);
1229}
1230
1231inline
1233{
1234 return *d_defaultCategory_p;
1235}
1236
1237inline
1239{
1240 return d_ruleSetMutex;
1241}
1242
1243inline
1244const Category *CategoryManager::setCategory(const char *categoryName)
1245{
1246 return setCategory(0, categoryName);
1247}
1248
1249inline
1251{
1253 d_maxNumCategoriesMinusOne = length - 1;
1254}
1255
1256template <class t_CATEGORY_VISITOR>
1257void CategoryManager::visitCategories(const t_CATEGORY_VISITOR& visitor)
1258{
1259 bslmt::ReadLockGuard<bslmt::ReaderWriterLock> guard(&d_registryLock);
1260 for (CategoryPtrVector::iterator it = d_categories.begin();
1261 it != d_categories.end();
1262 ++it) {
1263 visitor(*it);
1264 }
1265}
1266
1267// ACCESSORS
1268inline
1270{
1271 bslmt::ReadLockGuard<bslmt::ReaderWriterLock> guard(&d_registryLock);
1272 return *d_categories[index];
1273}
1274
1275inline
1277{
1278 return *d_defaultCategory_p;
1279}
1280
1281inline
1283{
1284 bslmt::ReadLockGuard<bslmt::ReaderWriterLock> guard(&d_registryLock);
1285 return static_cast<int>(d_categories.size());
1286}
1287
1288inline
1290{
1291 bslmt::ReadLockGuard<bslmt::ReaderWriterLock> guard(&d_registryLock);
1292 return static_cast<int>(d_maxNumCategoriesMinusOne) + 1;
1293}
1294
1295inline
1297{
1298 return d_ruleSet;
1299}
1300
1301inline
1303{
1304 return d_ruleSetSequenceNumber;
1305}
1306
1307template <class t_CATEGORY_VISITOR>
1308void CategoryManager::visitCategories(const t_CATEGORY_VISITOR& visitor) const
1309{
1310 bslmt::ReadLockGuard<bslmt::ReaderWriterLock> guard(&d_registryLock);
1311 for (CategoryPtrVector::const_iterator it = d_categories.begin();
1312 it != d_categories.end();
1313 ++it) {
1314 visitor(*it);
1315 }
1316}
1317
1318#ifndef BDE_OMIT_INTERNAL_DEPRECATED
1319
1320 // -------------------------
1321 // class CategoryManagerIter
1322 // -------------------------
1323
1324// CREATORS
1325inline
1326CategoryManagerIter::CategoryManagerIter(
1327 const CategoryManager& categoryManager)
1328: d_cm_p(&categoryManager)
1329, d_index(0)
1330{
1331}
1332
1333// MANIPULATORS
1334inline
1336{
1337 ++d_index;
1338}
1339
1340// ACCESSORS
1341inline
1342CategoryManagerIter::operator const void *() const
1343{
1344 return (0 <= d_index && d_index < d_cm_p->length()) ? this : 0;
1345}
1346
1347inline
1349{
1350 return d_cm_p->operator[](d_index);
1351}
1352
1353 // --------------------------
1354 // class CategoryManagerManip
1355 // --------------------------
1356
1357// CREATORS
1358inline
1359CategoryManagerManip::CategoryManagerManip(CategoryManager *categoryManager)
1360: d_cm_p(categoryManager)
1361, d_index(0)
1362{
1363}
1364
1365// MANIPULATORS
1366inline
1368{
1369 ++d_index;
1370}
1371
1372inline
1374{
1375 return d_cm_p->operator[](d_index);
1376}
1377
1378// ACCESSORS
1379inline
1380CategoryManagerManip::operator const void *() const
1381{
1382 return (0 <= d_index && d_index < d_cm_p->length()) ? this : 0;
1383}
1384
1385#endif // BDE_OMIT_INTERNAL_DEPRECATED
1386
1387} // close package namespace
1388
1389
1390#endif
1391
1392// ----------------------------------------------------------------------------
1393// Copyright 2015 Bloomberg Finance L.P.
1394//
1395// Licensed under the Apache License, Version 2.0 (the "License");
1396// you may not use this file except in compliance with the License.
1397// You may obtain a copy of the License at
1398//
1399// http://www.apache.org/licenses/LICENSE-2.0
1400//
1401// Unless required by applicable law or agreed to in writing, software
1402// distributed under the License is distributed on an "AS IS" BASIS,
1403// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1404// See the License for the specific language governing permissions and
1405// limitations under the License.
1406// ----------------------------- END-OF-FILE ----------------------------------
1407
1408/** @} */
1409/** @} */
1410/** @} */
Definition ball_category.h:367
Definition ball_categorymanager.h:1086
const Category & operator()() const
Definition ball_categorymanager.h:1348
void operator++()
Definition ball_categorymanager.h:1335
~CategoryManagerIter()=default
Destroy this iterator.
Definition ball_categorymanager.h:1147
void advance()
Definition ball_categorymanager.h:1367
~CategoryManagerManip()=default
Destroy this iterator.
Category & operator()()
Definition ball_categorymanager.h:1373
Definition ball_categorymanager_radixtree.h:434
Definition ball_categorymanager.h:426
void setMaxNumCategories(int length)
Definition ball_categorymanager.h:1250
Category * lookupCategory(const char *categoryName)
CategoryManager(bslma::Allocator *basicAllocator=0)
void setCategoryThresholdsToCurrentDefaults(Category *category) const
Category * addCategory(const char *categoryName, int recordLevel, int passLevel, int triggerLevel, int triggerAllLevel)
Definition ball_categorymanager.h:1215
CategoryManager(int defaultRecordLevel, int defaultPassLevel, int defaultTriggerLevel, int defaultTriggerAllLevel, const DefaultThresholdLevelsCallback &defaultThresholdLevelsCallback, const CategoryNameFilterCallback &categoryNameFilterCallback, bslma::Allocator *basicAllocator=0)
const RuleSet & ruleSet() const
Definition ball_categorymanager.h:1296
int addRule(const Rule &ruleToAdd)
int addRules(const RuleSet &ruleSet)
int defaultRecordThresholdLevel() const
Return the default record threshold level of this object.
int removeRules(const RuleSet &ruleSet)
int maxNumCategories() const
Definition ball_categorymanager.h:1289
Category * lookupCategory(CategoryHolder *categoryHolder, const char *categoryName)
const Category * lookupCategory(const char *categoryName) const
bsls::Types::Int64 ruleSetSequenceNumber() const
Definition ball_categorymanager.h:1302
int setThresholdLevelsHierarchically(const char *categoryNamePrefix, int recordLevel, int passLevel, int triggerLevel, int triggerAllLevel)
const Category * setCategory(CategoryHolder *categoryHolder, const char *categoryName)
int removeRule(const Rule &ruleToRemove)
int defaultTriggerThresholdLevel() const
Return the default trigger threshold level of this object.
int defaultTriggerAllThresholdLevel() const
Return the default trigger-all threshold level of this object.
Category & operator[](int index)
Definition ball_categorymanager.h:1208
Category * setCategory(const char *categoryName, int recordLevel, int passLevel, int triggerLevel, int triggerAllLevel)
ThresholdAggregate defaultThresholdLevels() const
Return the default threshold levels associated with this object.
Category * addCategoryHierarchically(const char *categoryName)
Category * setThresholdLevels(const char *categoryName, int recordLevel, int passLevel, int triggerLevel, int triggerAllLevel)
int length() const
Definition ball_categorymanager.h:1282
Category & defaultCategory()
Definition ball_categorymanager.h:1232
CategoryCallbacks::DefaultThresholdLevels DefaultThresholdLevelsCallback
Definition ball_categorymanager.h:439
void setCategoryThresholdsToFactoryDefaults(Category *category) const
int setDefaultThresholdLevels(int recordLevel, int passLevel, int triggerLevel, int triggerAllLevel)
int defaultPassThresholdLevel() const
Return the default pass threshold level of this object.
void visitCategories(const t_CATEGORY_VISITOR &visitor)
Definition ball_categorymanager.h:1257
Category * addCategory(CategoryHolder *categoryHolder, const char *categoryName, int recordLevel, int passLevel, int triggerLevel, int triggerAllLevel)
void setDefaultThresholdLevelsCallback(const DefaultThresholdLevelsCallback *defaultThresholdLevelsCallback)
CategoryCallbacks::NameFilter CategoryNameFilterCallback
Definition ball_categorymanager.h:433
bslmt::Mutex & rulesetMutex()
Definition ball_categorymanager.h:1238
void resetDefaultThresholdLevels()
~CategoryManager()
Destroy this category manager.
int thresholdLevelsForNewCategory(ThresholdAggregate *levels, const char *categoryName) const
const Category * setCategory(const char *categoryName)
Definition ball_categorymanager.h:1244
Definition ball_category.h:184
Definition ball_ruleset.h:151
Definition ball_rule.h:177
Definition ball_thresholdaggregate.h:101
Definition bslstl_string.h:1252
Forward declaration.
Definition bslstl_function.h:946
Definition bslstl_unorderedmap.h:1123
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this vector.
Definition bslstl_vector.h:3019
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2866
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2874
Definition bslstl_vector.h:1120
Category * * iterator
Definition bslstl_vector.h:1152
Category * const * const_iterator
Definition bslstl_vector.h:1153
Definition bslma_allocator.h:545
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:317
Definition bslmt_readlockguard.h:287
Definition bslmt_readerwriterlock.h:294
Definition bslmt_readerwritermutex.h:244
Definition bslmt_writelockguard.h:221
Definition bsls_atomic.h:896
#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::function< void(bsl::string *buffer, const char *categoryName)> NameFilter
Definition ball_categorycallbacks.h:173
Definition bdlb_cstringequalto.h:123
Definition bdlb_cstringhash.h:237
long long Int64
Definition bsls_types.h:134