// ball_streamobserver.h                                              -*-C++-*-
#ifndef INCLUDED_BALL_STREAMOBSERVER
#define INCLUDED_BALL_STREAMOBSERVER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an observer that emits log records to a stream.
//
//@CLASSES:
//  ball::StreamObserver: observer that emits log records to a stream
//
//@SEE_ALSO: ball_record, ball_context, ball_loggermanager
//
//@DESCRIPTION: This component provides a concrete implementation of the
// 'ball::Observer' protocol for receiving and processing log records:
//..
//                 ,--------------------.
//                ( ball::StreamObserver )
//                 `--------------------'
//                           |              ctor
//                           |              setRecordFormatFunctor
//                           V
//                    ,--------------.
//                   ( ball::Observer )
//                    `--------------'
//                                          publish
//                                          releaseRecords
//                                          dtor
//..
// 'ball::StreamObserver' is a concrete class derived from 'ball::Observer'
// that processes the log records it receives through its 'publish' method by
// writing them to an output stream.  Given its minimal functionality,
// 'ball::StreamObserver' should be used with care in a production environment.
// It is not recommended to construct this observer with file-based streams due
// to lack of any file rotation functionality.
//
///Log Record Formatting
///---------------------
// By default, the output format of published log records is:
//..
//  DATE_TIME PID THREAD-ID SEVERITY FILE LINE CATEGORY MESSAGE USER-FIELDS
//..
// where 'DATE' and 'TIME' are of the form 'DDMonYYYY' and 'HH:MM:SS.mmm',
// respectively ('Mon' being the 3-letter abbreviation for the month).  For
// example, assuming that no user-defined fields are present, a log record
// will have the following appearance when the default format is in effect:
//..
//  18MAY2005_18:58:12.076 7959 1 WARN ball_streamobserver2.t.cpp 404 TEST hi!
//..
// The default format can be overridden by supplying a suitable formatting
// functor to 'setRecordFormatFunctor'.  For example, an instance of
// 'ball::RecordStringFormatter' conveniently provides such a functor:
//..
//  streamObserver.setRecordFormatFunctor(
//              ball::RecordStringFormatter("\n%I %p:%t %s %f:%l %c %m %u\n"));
//..
// The above statement will cause subsequent records to be logged in a format
// that is almost identical to the default format except that the timestamp
// attribute will be written in ISO 8601 format.  See
// {'ball_recordstringformatter'} for information on how format specifications
// are defined and interpreted.
//
// Note that the observer emits newline characters at the beginning and at the
// end of a log record by default, so the user needs to add them explicitly to
// the format string to preserve this behavior.
//
// Also note that in the sample message above the timestamp has millisecond
// precision ('18MAY2005_18:58:12.076').  If microsecond precision is desired
// instead, consider using either the '%D' or '%O' format specification
// supported by 'ball_recordstringformatter'.
//
///Thread Safety
///-------------
// All methods of 'ball::StreamObserver' are thread-safe, and can be called
// concurrently by multiple threads.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Usage
/// - - - - - - - - - - -
// The following snippets of code illustrate the basic usage of
// 'ball::StreamObserver'.
//
// First create a 'ball::Record' object 'record' and a 'ball::Context' object
// 'context'.  Note that the default values for these objects (or their
// contained objects) are perfectly suitable for logging purposes.
//..
//  ball::RecordAttributes attributes;
//  ball::UserFields       fieldValues;
//  ball::Context          context;
//
//  bslma::Allocator *ga = bslma::Default::globalAllocator(0);
//  const bsl::shared_ptr<const ball::Record>
//             record(new (*ga) ball::Record(attributes, fieldValues, ga), ga);
//..
// Next, create a stream observer 'observer' with the 'bsl::cout' as the output
// stream.
//..
//  ball::StreamObserver observer(&bsl::cout);
//..
// Finally, publish 'record' and 'context' to 'observer'.
//..
//  observer.publish(record, context);
//..
// This will produce the following output on 'stdout':
//..
//  01JAN0001_24:00:00.000 0 0 OFF  0
//..

#include <balscm_version.h>

#include <ball_observer.h>

#include <bslma_allocator.h>
#include <bslma_stdallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_nestedtraitdeclaration.h>

#include <bslmt_mutex.h>

#include <bsls_assert.h>
#include <bsls_review.h>

#include <bsl_iosfwd.h>
#include <bsl_functional.h>

namespace BloombergLP {
namespace ball {

class Context;
class Record;

                           // ====================
                           // class StreamObserver
                           // ====================

class StreamObserver : public Observer {
    // This class provides a concrete implementation of the 'Observer'
    // protocol.  The 'publish' method of this class outputs the log records
    // that it receives to an instance of 'bsl::ostream' supplied at
    // construction.

  public:
    // TYPES
    typedef bsl::function<void(bsl::ostream&, const Record&)>
                                                           RecordFormatFunctor;
        // 'RecordFormatFunctor' is an alias for the type of the functor used
        // for formatting log records to a stream.

    typedef bsl::allocator<char> allocator_type;

  private:
    // DATA
    bsl::ostream        *d_stream_p;   // output sink for log records

    bslmt::Mutex         d_mutex;      // serializes concurrent calls to
                                       // 'publish'

    RecordFormatFunctor  d_formatter;  // formatting functor used when writing
                                       // to log file

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

    // CLASS METHODS
    static
    void logRecordDefault(bsl::ostream& stream, const Record& record);
        // Write the specified log 'record' to the specified output 'stream'
        // using the default record format of this stream observer.

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(StreamObserver, bslma::UsesBslmaAllocator);

    // CREATORS
    explicit
    StreamObserver(bsl::ostream          *stream,
                   const allocator_type&  allocator = allocator_type());
        // Create a stream observer that transmits log records to the specified
        // 'stream'.  Optionally specify an 'allocator' (e.g., the address of a
        // 'bslma::Allocator' object) to supply memory; otherwise, the default
        // allocator is used.  Note that a default record format is in effect
        // for stream logging (see 'setLogFileFunctor').

    virtual ~StreamObserver();
        // Destroy this stream observer.

    // MANIPULATORS
    using Observer::publish;

    virtual void publish(const bsl::shared_ptr<const Record>& record,
                         const Context&                       context);
        // Process the specified log 'record' having the specified publishing
        // 'context'.  Print 'record' and 'context' to the 'bsl::ostream'
        // supplied at construction.  The behavior is undefined if 'record' or
        // 'context' is modified during the execution of this method.

    virtual void releaseRecords();
        // Discard any shared reference to a 'Record' object that was supplied
        // to the 'publish' method, and is held by this observer.  Note that
        // this operation should be called if resources underlying the
        // previously provided shared-pointers must be released.

    void setRecordFormatFunctor(const RecordFormatFunctor& formatter);
        // Set the formatting functor used when writing records to the log file
        // of this file observer to the specified 'formatter' functor.  Note
        // that a default format ("\n%d %p %t %s %f %l %c %m %u\n") is in
        // effect until this method is called (see
        // 'ball_recordstringformatter').  Also note that the observer emits
        // newline characters at the beginning and at the end of a log record
        // by default, so the user needs to add them explicitly to the format
        // string to preserve this behavior.
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                           // --------------------
                           // class StreamObserver
                           // --------------------

// MANIPULATORS
inline
void StreamObserver::releaseRecords()
{
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2017 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------