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 registry

  • setThresholdLevels - Set threshold levels for categories matching a pattern

  • setAllThresholdLevels - Set threshold levels for all existing categories

  • setDefaultThresholdLevels - Configure default thresholds for new categories

  • recordLevel, passLevel, triggerLevel, triggerAllLevel - Query threshold levels for specific categories

  • setMaxNumCategories - Control the maximum number of categories allowed

  • numCategories, 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.