// ball_recordstringformatter.h -*-C++-*- #ifndef INCLUDED_BALL_RECORDSTRINGFORMATTER #define INCLUDED_BALL_RECORDSTRINGFORMATTER #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a record formatter that uses a 'printf'-style format spec. // //@CLASSES: // ball::RecordStringFormatter: 'printf'-style formatter for log records // //@SEE_ALSO: ball_record, ball_recordattributes // //@DESCRIPTION: This component provides a value-semantic function-object class, // 'ball::RecordStringFormatter', that is used to format log records according // to a 'printf'-style format specification (see "Record Format Specification" // below). A format specification and a timestamp offset (in the form of a // 'bdlt::DatetimeInterval') are optionally supplied upon construction of a // 'ball::RecordStringFormatter' object (or simply "record formatter"). If a // format specification is not supplied, a default one (defined below) is used. // If a timestamp offset is not supplied, it defaults to 0. Both the format // specification and timestamp offset of a record formatter can be modified // following construction. // // An overloaded 'operator()' is defined for 'ball::RecordStringFormatter' that // takes a 'ball::Record' and an 'bsl::ostream' as arguments. This method // formats the given record according to the format specification of the record // formatter and outputs the result to the given stream. Additionally, each // timestamp indicated in the format specification is biased by the timestamp // offset of the record formatter prior to outputting it to the stream. This // facilitates the logging of records in local time, if desired, in the event // that the timestamp attribute of records are in UTC. // ///Record Format Specification ///--------------------------- // The following table lists the 'printf'-style ('%'-prefixed) conversion // specifications, including their expansions, that are recognized within the // format specification of a record formatter: //.. // %d - timestamp in 'DDMonYYYY_HH:MM:SS.mmm' format (27AUG2007_16:09:46.161) // %D - timestamp in 'DDMonYYYY_HH:MM:SS.mmmuuu' format // (27AUG2007_16:09:46.161324) // %dtz - timestamp in 'DDMonYYYY_HH:MM:SS.mmm(+|-)HHMM' format // (27AUG2007_16:09:46.161+0000) // %Dtz - timestamp in 'DDMonYYYY_HH:MM:SS.mmmuuu(+|-)HHMM' format // (27AUG2007_16:09:46.161324+0000) // %i - timestamp in ISO 8601 format (without the millisecond or microsecond // fields) // %I - timestamp in ISO 8601 format (*with* the millisecond field) // %O - timestamp in ISO 8601 format (*with* the millisecond and microsecond // fields) // %p - process Id // %t - thread Id // %T - thread Id in hex // %s - severity // %f - filename (as provided by '__FILE__') // %F - filename abbreviated (basename of '__FILE__' only) // %l - line number (as provided by '__LINE__') // %c - category name // %m - log message // %x - log message with non-printable characters in hex // %X - log message entirely in hex // %u - user-defined fields // %% - single '%' character // %A - log all the attributes of the record // %a - log only those attributes not already logged by the %a[name] or // %av[name] specifier(s) // %a[name] - log an attribute with the specified 'name' as "name=value", // log nothing if the attribute with the specified 'name' is not found // %av[name] - log only the value of an attribute with the specified 'name', // log nothing if the attribute with the specified 'name' is not found //.. // (Note that '%F' is used to indicate the shortened form of '__FILE__' rather // than '%f' because '%f' was given its current interpretation in an earlier // version of this component.) // // In addition, the following '\'-escape sequences are interpolated in the // formatted output as indicated when they occur in the format specification: //.. // \n - newline character // \t - tab character // \\ - single '\' character //.. // Any other text included in the format specification of the record formatter // is output verbatim. // // When not supplied at construction, the default format specification of a // record formatter is: //.. // "\n%d %p:%t %s %f:%l %c %m %u\n" //.. // A default-formatted record having no user-defined fields will have the // following appearance: //.. // 27AUG2007_16:09:46.161 2040:1 WARN subdir/process.cpp:542 FOO.BAR.BAZ <text> //.. // ///Log Record Attributes Rendering Details ///--------------------------------------- // Log record attributes are rendered as space-separated 'name="value"' pairs // (for example: mylibrary.username="mbloomberg"). Note that attribute names // are *not* quoted, whereas attribute values, if they are strings, are // *always* quoted. // ///Usage ///----- // The following snippets of code illustrate how to use an instance of // 'ball::RecordStringFormatter' to format log records. // // First we instantiate a record formatter with an explicit format // specification (but we accept the default timestamp offset since it will not // be used in this example): //.. // ball::RecordStringFormatter formatter("\n%t: %m\n"); //.. // The chosen format specification indicates that, when a record is formatted // using 'formatter', the thread Id attribute of the record will be output // followed by the message attribute of the record. // // Next we create a default 'ball::Record' and set the thread Id and message // attributes of the record to dummy values: //.. // ball::Record record; // // record.fixedFields().setThreadID(6); // record.fixedFields().setMessage("Hello, World!"); //.. // The following "invocation" of the 'formatter' function object formats // 'record' to 'bsl::cout' according to the format specification supplied at // construction: //.. // formatter(bsl::cout, record); //.. // As a result of this call, the following is printed to 'stdout': //.. // 6: Hello, World! //.. #include <balscm_version.h> #include <bdlt_datetimeinterval.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_nestedtraitdeclaration.h> #include <bsl_functional.h> #include <bsl_iosfwd.h> #include <bsl_string.h> #include <bsl_set.h> #include <bsl_vector.h> #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bslalg_typetraits.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES namespace BloombergLP { namespace ball { class Record; // =========================== // class RecordStringFormatter // =========================== class RecordStringFormatter { // This class provides a value-semantic log record formatter that holds a // 'printf'-style format specification and a timestamp offset. The // overloaded 'operator()' provided by the class formats a given record // according to the format specification and outputs the formatted result // to a given stream. The timestamp offset of the record formatter is // added to each timestamp that is output to the stream. // PRIVATE TYPES typedef bsl::function<void(bsl::string *, const Record&)> FieldStringFormatter; // 'FieldStringFormatter' is an alias for a functional object that // render fields provided by a 'ball::Record' to a string. typedef bsl::vector<FieldStringFormatter> FieldStringFormatters; // 'FieldStringFormatters' is an alias for a vector of the // 'FieldStringFormatter' objects. typedef bsl::set<bsl::string_view> SkipAttributes; // 'SkipAttributes' is an alias for a set of keys of attributes that // should not be printed as part of a '%a' format specifier. public: // TYPES typedef bsl::allocator<char> allocator_type; private: // DATA bsl::string d_formatSpec; // 'printf'-style format spec. FieldStringFormatters d_fieldFormatters; // field formatter collection SkipAttributes d_skipAttributes; // set of skipped attributes bdlt::DatetimeInterval d_timestampOffset; // offset added to timestamps // PRIVATE MANIPULATORS void parseFormatSpecification(); // Parse the format specification. public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(RecordStringFormatter, bslma::UsesBslmaAllocator); // PUBLIC CONSTANTS static const char *k_DEFAULT_FORMAT; // The default log format specification used by // 'RecordStringFormatter'. static const char *k_BASIC_ATTRIBUTE_FORMAT; // A simple standard record format that renders 'ball::Attribute' // values in the formatted output. Note that this format is // recommended over the default format, 'k_DEFAULT_FORMAT', for most // applications (the default format is currently maintained for // backwards compatibility). // CREATORS explicit RecordStringFormatter( const allocator_type& allocator = allocator_type()); explicit RecordStringFormatter( bslma::Allocator *basicallocator); // Create a record formatter having a default format specification and // a timestamp offset of 0. Optionally specify an 'allocator' (e.g., // the address of a 'bslma::Allocator' object) to supply memory. If // 'basicAllocator' is not supplied or 0, the currently installed // default allocator is used. The default format specification is: //.. // "\n%d %p:%t %s %f:%l %c %m %u\n" //.. explicit RecordStringFormatter( const char *format, const allocator_type& allocator = allocator_type()); RecordStringFormatter(const char *format, bslma::Allocator *basicAllocator); // Create a record formatter having the specified 'format' // specification and a timestamp offset of 0. Optionally specify an // 'allocator' (e.g., the address of a 'bslma::Allocator' object) to // supply memory. If 'basicAllocator' is not supplied or 0, the // currently installed default allocator is used. explicit RecordStringFormatter( const bdlt::DatetimeInterval& offset, const allocator_type& allocator = allocator_type()); // Create a record formatter having a default format specification and // the specified timestamp 'offset'. Optionally specify an 'allocator' // (e.g., the address of a 'bslma::Allocator' object) to supply memory; // otherwise, the default allocator is used. The default format // specification is: //.. // "\n%d %p:%t %s %f:%l %c %m %u\n" //.. // // !DEPRECATED!: Use a constructor taking 'publishInLocalTime' instead. explicit RecordStringFormatter( bool publishInLocalTime, const allocator_type& allocator = allocator_type()); // Create a record formatter having a default format specification, and // if the specified 'publishInLocalTime' flag is 'true', format the // timestamp of each logged record in the local time of the current // task, and format the timestamp in UTC otherwise. Optionally specify // an 'allocator' (e.g., the address of a 'bslma::Allocator' object) to // supply memory; otherwise, the default allocator is used. The // default format specification is: //.. // "\n%d %p:%t %s %f:%l %c %m %u\n" //.. // Note that local time offsets are calculated for the timestamp of // each formatted record and so track transitions into and out of // Daylight Saving Time. RecordStringFormatter( const char *format, const bdlt::DatetimeInterval& offset, const allocator_type& allocator = allocator_type()); // Create a record formatter having the specified 'format' // specification and the specified timestamp 'offset'. Optionally // specify an 'allocator' (e.g., the address of a 'bslma::Allocator' // object) to supply memory; otherwise, the default allocator is used. // // !DEPRECATED!: Use a constructor taking 'publishInLocalTime' instead. RecordStringFormatter(const char *format, bool publishInLocalTime, const allocator_type& allocator = allocator_type()); // Create a record formatter having the specified 'format' // specification, and if the specified 'publishInLocalTime' flag is // 'true', format the timestamp of each log in the local time of the // current task, and format the timestamp in UTC otherwise. Optionally // specify an 'allocator' (e.g., the address of a 'bslma::Allocator' // object) to supply memory; otherwise, the default allocator is used. // Note that local time offsets are calculated for the timestamp of // each formatted record and so track transitions into and out of // Daylight Saving Time. RecordStringFormatter( const RecordStringFormatter& original, const allocator_type& allocator = allocator_type()); // Create a record formatter initialized to the value of the specified // 'original' record formatter. Optionally specify an 'allocator' // (e.g., the address of a 'bslma::Allocator' object) to supply memory; // otherwise, the default allocator is used. //! ~RecordStringFormatter() = default; // Destroy this object. // MANIPULATORS RecordStringFormatter& operator=(const RecordStringFormatter& rhs); // Assign to this record formatter the value of the specified 'rhs' // record formatter. void disablePublishInLocalTime(); // Disable adjust of the timestamp attribute of to the current local // time by this file observer. This method has no effect if adjustment // to the current local time is not enabled. void enablePublishInLocalTime(); // Enable adjustment of the timestamp attribute to the current local // time. This method has no effect if adjustment to the current local // time is already enabled. void setFormat(const char *format); // Set the format specification of this record formatter to the // specified 'format'. void setTimestampOffset(const bdlt::DatetimeInterval& offset); // Set the timestamp offset of this record formatter to the specified // 'offset'. // // !DEPRECATED!: Use 'enablePublishInLocalTime' instead. // ACCESSORS void operator()(bsl::ostream& stream, const Record& record) const; // Format the specified 'record' according to the format specification // of this record formatter and output the result to the specified // 'stream'. The timestamp offset of this record formatter is added to // each timestamp that is output to 'stream'. const char *format() const; // Return the format specification of this record formatter. bool isPublishInLocalTimeEnabled() const; // Return 'true' if this formatter adjusts the timestamp attribute to // the current local time, and 'false' otherwise. const bdlt::DatetimeInterval& timestampOffset() const; // Return a reference to the non-modifiable timestamp offset of this // record formatter. // // !DEPRECATED!: Use 'isPublishInLocalTimeEnabled' instead. // Aspects allocator_type get_allocator() const; // Return the allocator used by this object to supply memory. Note // that if no allocator was supplied at construction the default // allocator in effect at construction is used. }; // FREE OPERATORS bool operator==(const RecordStringFormatter& lhs, const RecordStringFormatter& rhs); // Return 'true' if the specified 'lhs' and 'rhs' record formatters have // the same value, and 'false' otherwise. Two record formatters have the // same value if they have the same format specification and the same // timestamp offset. bool operator!=(const RecordStringFormatter& lhs, const RecordStringFormatter& rhs); // Return 'true' if the specified 'lhs' and 'rhs' record formatters do not // have the same value, and 'false' otherwise. Two record formatters // differ in value if their format specifications differ or their timestamp // offsets differ. bsl::ostream& operator<<(bsl::ostream& output, const RecordStringFormatter& rhs); // Write the specified 'rhs' record formatter to the specified 'output' // stream in some reasonable (single-line) format and return a reference // to the modifiable 'stream'. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // --------------------------- // class RecordStringFormatter // --------------------------- // MANIPULATORS inline void RecordStringFormatter::setFormat(const char *format) { d_formatSpec = format; parseFormatSpecification(); } inline void RecordStringFormatter::setTimestampOffset( const bdlt::DatetimeInterval& offset) { d_timestampOffset = offset; } // ACCESSORS inline const char *RecordStringFormatter::format() const { return d_formatSpec.c_str(); } inline const bdlt::DatetimeInterval& RecordStringFormatter::timestampOffset() const { return d_timestampOffset; } // Aspects inline RecordStringFormatter::allocator_type RecordStringFormatter::get_allocator() const { return d_formatSpec.get_allocator(); } } // close package namespace // FREE OPERATORS inline bool ball::operator!=(const RecordStringFormatter& lhs, const RecordStringFormatter& rhs) { return !(lhs == rhs); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 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 ----------------------------------