Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component ball_context
[Package ball]

Provide a container for the context of a transmitted log record. More...

Namespaces

namespace  ball

Detailed Description

Outline
Purpose:
Provide a container for the context of a transmitted log record.
Classes:
ball::Context context of a transmitted log record
See also:
Component ball_transmission, Component ball_observer, Component ball_record
Description:
This component defines a container for aggregating a message's publication cause, as well as the record (or message) index and sequence length of messages delivered as part of a message sequence. Note that messages that are not part of a sequence (i.e., PASSTHROUGH) will have the index and sequence length fields set to 0 and 1, respectively.
The context attributes held by ball::Context are detailed in the following table:
  Attribute          Type                      Description        Default
  -----------------  ------------------------  -----------------  -----------
  transmissionCause  ball::Transmission::Cause cause of output    PASSTHROUGH
  recordIndex        int                       index in sequence  0
  sequenceLength     int                       # records in seq.  1
Constraints:
This attribute class assumes that the following constraints on contained values hold:
    if (ball::Transmission::e_PASSTHROUGH == transmissionCause()) {
        assert(0 == recordIndex());
        assert(1 == sequenceLength());
    }
    else {
        assert(
         ball::Transmission::e_TRIGGER            == transmissionCause()
      || ball::Transmission::e_TRIGGER_ALL        == transmissionCause()
      || ball::Transmission::e_MANUAL_PUBLISH     == transmissionCause()
      || ball::Transmission::e_MANUAL_PUBLISH_ALL == transmissionCause());
        assert(0 <= recordIndex());
        assert(1 <= sequenceLength());
        assert(recordIndex() < sequenceLength());
    }
A static isValid method is provided to verify that particular transmissionCause, recordIndex, and sequenceLength values are valid before they are used to create or (unilaterally) modify a context object.
Usage:
A ball::Context object holds sufficient information to determine the length of a message sequence and the index of a message within that sequence. In addition, ball::Context indicates the cause for the transmission of a message. The following example illustrates the essentials of working with these contextual attributes.
This example illustrates the use of ball::Context by a hypothetical logging system. First we define a simple logger class named my_Logger:
    // my_logger.h

    #include <string>
    #include <vector>

    class my_Logger {

        bsl::vector<bsl::string> archive;  // log message archive

        // NOT IMPLEMENTED
        my_Logger(const my_Logger&);
        my_Logger& operator=(const my_Logger&);

        // PRIVATE MANIPULATORS
        void publish(const bsl::string&   message,
                     const ball::Context& context);

      public:
        // TYPES
        enum Severity { ERROR = 0, WARN = 1, TRACE = 2 };

        // CREATORS
        my_Logger();
        ~my_Logger();

        // MANIPULATORS
        void logMessage(const bsl::string& message, Severity severity);
    };
Clients of my_Logger log messages at one of three severity levels through the logMessage method. Messages logged with TRACE severity are simply archived by my_Logger. Messages logged with WARN severity are archived and also output to stdout (say, to a console terminal overseen by an operator) through the publish method. Messages logged with ERROR severity report serious conditions; these trigger a dump of the backlog of messages that my_Logger has archived to that point. The ball::Context argument passed to publish provides contextual information regarding the message it is being asked to publish.
A complete implementation of this trivial logger follows:
    // my_Logger.cpp

    // PRIVATE MANIPULATORS
    void my_Logger::publish(const bsl::string&   message,
                            const ball::Context& context)
    {
        using namespace std;

        switch (context.transmissionCause()) {
          case ball::Transmission::e_PASSTHROUGH: {
            cout << "Single Pass-through Message: ";
          } break;
          case ball::Transmission::e_TRIGGER_ALL: {
            cout << "Remotely ";               // no 'break'; concatenated
                                               // output
          } break;
          case ball::Transmission::e_TRIGGER: {
            cout << "Triggered Publication Sequence: Message "
                 << context.recordIndex() + 1  // Account for 0-based index.
                 << " of " << context.sequenceLength() << ": ";
          } break;
          case ball::Transmission::e_MANUAL_PUBLISH: {
            cout << "Manually triggered Message: ";
          } break;
          default: {
            cout << "***ERROR*** Unsupported Message Cause: ";
            return;
          } break;
        }
        cout << message << endl;
    }

    // CREATORS
    my_Logger::my_Logger() { }
    my_Logger::~my_Logger() { }

    // MANIPULATORS
    void my_Logger::logMessage(const bsl::string& message, Severity severity)
    {
        archive.append(message);
        switch (severity) {
          case TRACE: {
            // Do nothing beyond archiving the message.
          } break;
          case WARN: {
            ball::Context context(ball::Transmission::e_PASSTHROUGH, 0, 1);
            publish(message, context);
          } break;
          case ERROR: {
            int index  = 0;
            int length = archive.length();
            ball::Context context(ball::Transmission::e_TRIGGER,
                                  index, length);
            while (length--) {
                publish(archive[length], context);
                context.setRecordIndexRaw(++index);
            }
            archive.removeAll();  // flush archive
          } break;
        }
    }
Note that ball::Transmission::e_TRIGGER_ALL is not used by my_Logger, but is included in the switch statement for completeness.
Finally, we declare a my_Logger named logger and simulate the logging of several messages of varying severity:
      my_Logger   logger;
      bsl::string message;

      message = "TRACE 1";  logger.logMessage(message, my_Logger::TRACE);
      message = "TRACE 2";  logger.logMessage(message, my_Logger::TRACE);
      message = "WARNING";  logger.logMessage(message, my_Logger::WARN);
      message = "TRACE 3";  logger.logMessage(message, my_Logger::TRACE);
      message = "TROUBLE!"; logger.logMessage(message, my_Logger::ERROR);
The following output is produced on stdout:
      Single Pass-through Message: WARNING
      Triggered Publication Sequence: Message 1 of 5: TROUBLE!
      Triggered Publication Sequence: Message 2 of 5: TRACE 3
      Triggered Publication Sequence: Message 3 of 5: WARNING
      Triggered Publication Sequence: Message 4 of 5: TRACE 2
      Triggered Publication Sequence: Message 5 of 5: TRACE 1
Note that the warning message (severity WARN) was emitted first since the trace messages (severity TRACE) were simply archived. When the error message (severity ERROR) was logged, it triggered a dump of the complete message archive (in reverse order).