Component of the Week #37: ball_administration
- Summary:
Provides logging administration functions from an application owner’s perspective
The ball_administration
component offers a convenient, high-level interface for administering the
ball logging subsystem. It provides utilities for managing categories,
setting threshold levels, and controlling the category registry - all from an
application owner’s perspective, without needing to interact directly with the
lower-level ball::LoggerManager singleton.
The component is organized in the ball::Administration namespace, offering
a set of utility functions for:
addCategory- Add new categories to the logger registrysetThresholdLevels- Set threshold levels for categories matching a patternsetAllThresholdLevels- Set threshold levels for all existing categoriessetDefaultThresholdLevels- Configure default thresholds for new categoriesrecordLevel,passLevel,triggerLevel,triggerAllLevel- Query threshold levels for specific categoriessetMaxNumCategories- Control the maximum number of categories allowednumCategories,maxNumCategories- Query category registry status
All of these functions require that the logger manager singleton has been initialized and is not in the process of being shut down.
Note
The ball logging system uses four independent threshold levels to
control logging behavior: record, pass, trigger, and
trigger-all. Understanding these levels is crucial for effective logging
administration. See the ball package documentation for details on how
these threshold levels control logging behavior.
Managing Categories
Creating and configuring categories is straightforward with
ball::Administration. Let’s start by initializing the logger manager and
adding some categories:
#include <ball_administration.h>
#include <ball_loggermanager.h>
#include <ball_loggermanagerconfiguration.h>
#include <ball_severity.h>
#include <bsl_iostream.h>
#include <bsl_array.h> // for `bsl::ssize()`
using namespace BloombergLP;
using namespace bsl;
int main()
{
// Initialize the logger manager
ball::LoggerManagerConfiguration lmConfig;
ball::LoggerManagerScopedGuard lmGuard(lmConfig);
// Define category names using hierarchical naming convention
const char *equityCategories[] = {
"EQUITY.MARKET.NYSE",
"EQUITY.MARKET.NASDAQ",
"EQUITY.GRAPHICS.MATH.FACTORIAL"
};
// Add categories with different threshold levels
for (int i = 0; i < bsl::ssize(equityCategories); ++i) {
const int retValue = ball::Administration::addCategory(
equityCategories[i],
ball::Severity::e_TRACE,
ball::Severity::e_WARN,
ball::Severity::e_ERROR,
ball::Severity::e_FATAL);
if (0 == retValue) {
cout << "Successfully added category: "
<< equityCategories[i] << endl;
}
}
return 0;
}
Querying and Modifying Threshold Levels
Once categories are established, you can query their threshold levels and modify them as needed:
// Query threshold levels for a specific category
const char* categoryName = "EQUITY.MARKET.NYSE";
const int recordLevel = ball::Administration::recordLevel(categoryName);
const int passLevel = ball::Administration::passLevel(categoryName);
const int triggerLevel = ball::Administration::triggerLevel(categoryName);
const int triggerAllLevel = ball::Administration::triggerAllLevel(categoryName);
if (recordLevel >= 0) { // Category exists
cout << "Category name: " << categoryName << endl;
cout << "\tRecord level: " << recordLevel << endl;
cout << "\tPass level: " << passLevel << endl;
cout << "\tTrigger level: " << triggerLevel << endl;
cout << "\tTrigger-all level: " << triggerAllLevel << endl;
}
// Modify threshold levels for this category
int numModified = ball::Administration::setThresholdLevels(
categoryName,
ball::Severity::e_TRACE,
ball::Severity::e_INFO,
ball::Severity::e_ERROR,
ball::Severity::e_FATAL);
cout << "Modified " << numModified << " category" << endl;
Pattern-Based Threshold Configuration
One of the most powerful features of ball::Administration is the ability to
set threshold levels for multiple categories at once using pattern matching:
// Set threshold levels for all EQUITY.MARKET.* categories
const int numModified = ball::Administration::setThresholdLevels(
"EQUITY.MARKET*",
ball::Severity::e_INFO,
ball::Severity::e_WARN,
ball::Severity::e_ERROR,
ball::Severity::e_FATAL);
cout << "Modified " << numModified << " categories matching pattern"
<< endl;
// Set threshold levels for ALL categories
const int rc = ball::Administration::setAllThresholdLevels(
ball::Severity::e_TRACE,
ball::Severity::e_INFO,
ball::Severity::e_WARN,
ball::Severity::e_ERROR);
if (0 == rc) {
cout << "Successfully updated all categories" << endl;
}
Note that patterns support only a * at the end of the pattern string, which
matches any string (including the empty string). The pattern “EQUITY.MARKET*”
would match “EQUITY.MARKET”, “EQUITY.MARKET.NYSE”, “EQUITY.MARKET.NASDAQ”, etc.
Controlling Category Registry Capacity
To prevent unbounded growth of the category registry, you can set a maximum capacity:
// Check current registry status
const int currentCount = ball::Administration::numCategories();
const int currentMax = ball::Administration::maxNumCategories();
cout << "Current categories: " << currentCount
<< " of " << currentMax << " max" << endl;
// Lock the registry to its current size
ball::Administration::setMaxNumCategories(currentCount);
// Attempt to add a new category will now fail
const int retValue = ball::Administration::addCategory(
"NEW.CATEGORY",
ball::Severity::e_TRACE,
ball::Severity::e_WARN,
ball::Severity::e_ERROR,
ball::Severity::e_FATAL);
if (0 != retValue) {
cout << "Failed to add category: registry is at capacity" << endl;
}
// Setting capacity to 0 removes the limit
ball::Administration::setMaxNumCategories(0);
Conclusion
The ball::Administration component provides a clean, high-level interface
for managing the ball logging subsystem from an application owner’s point of view.
Whether you’re adding categories, adjusting threshold levels, or controlling registry
capacity, these utilities insulate you from the complexities of the underlying
ball::LoggerManager and make logging administration straightforward and maintainable.
For more information, including details on default threshold levels and advanced usage patterns, see the component documentation.