BDE 4.39.x Production Release
Loading...
Searching...
No Matches
ball_recordjsonformatter.h
Go to the documentation of this file.
1/// @file ball_recordjsonformatter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_recordjsonformatter.h -*-C++-*-
8
9#ifndef INCLUDED_BALL_RECORDJSONFORMATTER
10#define INCLUDED_BALL_RECORDJSONFORMATTER
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup ball_recordjsonformatter ball_recordjsonformatter
16/// @brief Provide a formatter for log records that renders output in JSON.
17/// @addtogroup bal
18/// @{
19/// @addtogroup ball
20/// @{
21/// @addtogroup ball_recordjsonformatter
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#ball_recordjsonformatter-purpose"> Purpose</a>
26/// * <a href="#ball_recordjsonformatter-classes"> Classes </a>
27/// * <a href="#ball_recordjsonformatter-description"> Description </a>
28/// * <a href="#ball_recordjsonformatter-simplified-record-format-specification"> Simplified Record Format Specification </a>
29/// * <a href="#ball_recordjsonformatter-json-record-format-specification"> JSON Record Format Specification </a>
30/// * <a href="#ball_recordjsonformatter-field-format-specification"> Field Format Specification </a>
31/// * <a href="#ball_recordjsonformatter-verifying-the-format-specification-for-setjsonformat"> Verifying the Format Specification for setJsonFormat </a>
32/// * <a href="#ball_recordjsonformatter-the-timestamp-field-format"> The "timestamp" field format </a>
33/// * <a href="#ball_recordjsonformatter-the-pid-field-format"> The "pid" (process Id) field format </a>
34/// * <a href="#ball_recordjsonformatter-the-tid-ktid-field-format"> The "tid""ktid" (threadkernel thread Id) field format </a>
35/// * <a href="#ball_recordjsonformatter-the-file-field-format"> The "file" field format </a>
36/// * <a href="#ball_recordjsonformatter-the-line-field-format"> The "line" field format </a>
37/// * <a href="#ball_recordjsonformatter-the-category-field-format"> The "category" field format </a>
38/// * <a href="#ball_recordjsonformatter-the-severity-field-format"> The "severity" field format </a>
39/// * <a href="#ball_recordjsonformatter-the-message-field-format"> The "message" field format </a>
40/// * <a href="#ball_recordjsonformatter-the-attributes-format"> The "attributes" format </a>
41/// * <a href="#ball_recordjsonformatter-a-user-defined-attribute-format"> A user-defined attribute format </a>
42/// * <a href="#ball_recordjsonformatter-the-record-separator"> The Record Separator </a>
43/// * <a href="#ball_recordjsonformatter-usage"> Usage </a>
44/// * <a href="#ball_recordjsonformatter-example-format-log-records-as-json-and-render-them-to-stdout"> Example: Format log records as JSON and render them to stdout </a>
45///
46/// # Purpose {#ball_recordjsonformatter-purpose}
47/// Provide a formatter for log records that renders output in JSON.
48///
49/// # Classes {#ball_recordjsonformatter-classes}
50///
51/// - ball::RecordJsonFormatter: formatter for rendering log records in JSON
52///
53/// @see ball_record, ball_recordattributes
54///
55/// # Description {#ball_recordjsonformatter-description}
56/// This component provides a function object class,
57/// `ball::RecordJsonFormatter`, that formats a log record as JSON text elements
58/// according to a format specification (see {`Record Format Specification`}).
59/// `ball::RecordJsonFormatter` is designed to match the function signature
60/// expected by many concrete `ball::Observer` implementations that publish log
61/// records (for example, see `ball::FileObserver2::setLogFileFunctor`).
62///
63/// NOTE: `ball::RecordJsonFormatter` renders individual log records as JSON,
64/// but, for example, a resulting log file would contain a sequence of JSON
65/// strings, which is not itself valid JSON text.
66///
67/// ## Simplified Record Format Specification {#ball_recordjsonformatter-simplified-record-format-specification}
68///
69///
70/// `RecordJsonFormatter` supports a simplified format using `printf`-style
71/// (`%`-prefixed) conversion specifications via the `setSimplifiedFormat`
72/// method. This format provides a more concise way to specify common logging
73/// patterns without the verbosity of JSON arrays.
74///
75/// Note: The `qjson://` scheme that uses this simplified format is registered
76/// by `ball::RecordFormatterRegistryUtil`, not by this component. Other
77/// schemes could be registered to use the same simplified format syntax.
78///
79/// The following table lists the `%`-prefixed conversion specifications that
80/// are recognized within a simplified format specification:
81/// @code
82/// %d - timestamp in 'DDMonYYYY_HH:MM:SS.mmm' format (28AUG2020_14:43:50.375)
83/// %i - timestamp in ISO 8601 format without fractional seconds
84/// %I - timestamp in ISO 8601 format with millisecond precision
85/// %T - thread Id in hexadecimal
86/// %t - thread Id in decimal
87/// %K - kernel thread Id in hexadecimal
88/// %k - kernel thread Id in decimal
89/// %p - process Id
90/// %F - filename (basename of __FILE__ only)
91/// %f - filename (full path from __FILE__)
92/// %l - line number
93/// %c - category name
94/// %s - severity
95/// %m - log message
96/// %A - all user-defined attributes
97/// %a[name] - specific user-defined attribute with the given name
98/// @endcode
99/// Field specifications may be separated by whitespace (spaces, tabs, newlines)
100/// or commas, which are ignored by the parser. For example, these format
101/// specifications are equivalent:
102/// @code
103/// "%d %T %s %c %m"
104/// "%d, %T, %s, %c, %m"
105/// "%d,%T,%s,%c,%m"
106/// @endcode
107/// For example, the format specification:
108/// @code
109/// "%d %T %s %c %m"
110/// @endcode
111/// passed to `setSimplifiedFormat` would result in a log record like:
112/// @code
113/// { "timestamp": "28AUG2020_14:43:50.375",
114/// "tid": "0xA7654EFF3540",
115/// "severity": "INFO",
116/// "category": "MyCategory",
117/// "message": "Hello, world!"
118/// }
119/// @endcode
120/// Each `%`-prefixed field is rendered as a JSON key-value pair with a default
121/// field name (e.g., "timestamp", "tid", "severity"). Field names can be
122/// customized by prefixing a format specifier with `<fieldName>:`, for example:
123/// `"myTime:%d"` uses "myTime" as the field name instead of "timestamp". For
124/// more advanced formatting options, use the full JSON array format
125/// specification described below.
126///
127/// ## JSON Record Format Specification {#ball_recordjsonformatter-json-record-format-specification}
128///
129///
130/// A full featured format specification is, itself, a JSON array, supplied to a
131/// `RecordJsonFormatter` object by the `setJsonFormat` function. If no format
132/// is specified, the default format is used. Each array element specifies the
133/// format of a log record field or a user-defined attribute.
134///
135/// Note: The `json://` scheme that uses this JSON array format is registered
136/// by `ball::RecordFormatterRegistryUtil`, not by this component. Other
137/// schemes could be registered to use the same JSON output format, like how
138/// `qjson://` is an additional format syntax also resulting in JSON log
139/// records.
140///
141/// Here is a simple example:
142/// @code
143/// [{"timestamp":{"format":"iso8601"}}, "pid", "tid", "severity", "message"]
144/// @endcode
145/// would a result in a log record like:
146/// @code
147/// { "timestamp": "2020-08-28T14:43:50.375Z",
148/// "pid": 2313,
149/// "tid": 12349388604,
150/// "severity": "INFO",
151/// "message": "Hello, world!"
152/// }
153/// @endcode
154/// The format specification is a JSON array, each element of which can be one
155/// of the following:
156///
157/// * A string containing the name of the fixed record field or the name of the
158/// user-defined attribute, in which case the field or attribute will be
159/// published in the default format. For example, `[timestamp]`, would
160/// display the timestamp as: `{"timestamp": "2020-08-28T14:43:50.375Z"}`.
161/// * A JSON object having the name of the fixed field or user-defined
162/// attribute and a set of key-values pairs used to customize the output
163/// format. For example,
164/// `[{"timestamp": {"name": "My Time", "format": "bdePrint"}}]`, would
165/// display the timestamp as: `{"My Time": "28AUG2020_14:43:50.375"}`.
166///
167/// ### Field Format Specification {#ball_recordjsonformatter-field-format-specification}
168///
169///
170/// The following table lists the predefined string values for each fixed field
171/// and user-defined attributes in the log record:
172/// @code
173/// Tag Description Example
174/// -------------- ------------------------- -------------
175/// "timestamp" creation date and time ["timestamp"]
176/// "pid" process id of creator ["pid"]
177/// "tid" thread id of creator ["tid"]
178/// "ktid" kernel thread id of creator ["ktid"]
179/// "file" file where created (__FILE__) ["file"]
180/// "line" line number in file (__LINE__) ["line"]
181/// "category" category of logged record ["category"]
182/// "severity" severity of logged record ["severity"]
183/// "message" log message text ["message"]
184/// "attributes" all user-defined attributes ["attributes"]
185/// <attribute name> specific user-defined attribute ["bas.uuid"]
186/// @endcode
187/// The output format of each field can be customized by replacing a string
188/// value in the JSON array with a JSON object having the same name and a set of
189/// key-value pairs (attributes).
190///
191/// ### Verifying the Format Specification for setJsonFormat {#ball_recordjsonformatter-verifying-the-format-specification-for-setjsonformat}
192///
193///
194/// The sections that follow describe the set of fields that can be provided in
195/// the format specification supplied to `setJsonFormat`.
196/// `RecordJsonFormatter::setJsonFormat` will ignore fields in the provided
197/// format specification that are unknown, but will report an error if a known
198/// field contains a property that is not supported. For example: a format
199/// specification '["pid", { "timestamp" : {"unknown field!": "value"} }] will
200/// be accepted, but `["pid", {"timestamp": {"format": "unknown format" }}]`
201/// will produce an error.
202///
203/// Each key-value pair of a JSON object that specifies a format of an output of
204/// a fixed record field or a user-defined attribute has the following
205/// constrains:
206///
207/// * The key is a string of known value listed in the column "Key" in the
208/// tables below. Any string that does not match the listed values is
209/// ignored.
210/// * The value is a string of known value (except for the "name" key) in the
211/// column "Value Constraint" in the tables below. If the value does not
212/// match the string values specified in the tables, the format specification
213/// is considered to be inconsistent with the expected schema, and is
214/// rejected by the `RecordJsonFormatter::setJsonFormat` method.
215///
216/// #### The "timestamp" field format {#ball_recordjsonformatter-the-timestamp-field-format}
217///
218///
219/// The format attributes of the "timestamp" object are given in the following
220/// table:
221/// @code
222/// Value Default
223/// Key Description Constraint Value
224/// ------------------------ ---------------- ----------- ------------
225/// "name" name by which JSON string "timestamp"
226/// "timestamp" will
227/// be published
228///
229/// "format" datetime format "iso8601", "iso8601"
230/// "bdePrint"
231/// (*Note*)
232///
233/// "fractionalSecPrecision" second precision "none", "milliseconds"
234/// "milliseconds",
235/// "microseconds"
236///
237/// "timeZone" time zone "utc", "utc"
238/// "local"
239/// @endcode
240/// *Note*: The default "bdePrint" format denotes the following datetime format:
241/// @code
242/// DDMonYYYY_HH:MM:SS.mmm
243/// @endcode
244/// For example, the following record format specification:
245/// @code
246/// [ { "timestamp": { "name": "Time",
247/// "fractionalSecPrecision": "microseconds",
248/// "timeZone": "local" } }
249/// ]
250/// @endcode
251/// would a result in a log record like:
252/// @code
253/// { "Time": "28AUG2020_17:43:50.375345" }
254/// @endcode
255///
256/// #### The "pid" (process Id) field format {#ball_recordjsonformatter-the-pid-field-format}
257///
258///
259/// The format attributes of the process Id field are given in the following
260/// table:
261/// @code
262/// Value Default
263/// Key Description Constraint Value
264/// ------ ------------------------------------- ----------- -------
265/// "name" name by which "pid" will be published JSON string "pid"
266/// @endcode
267/// For example, the following record format specification:
268/// @code
269/// [ { "pid": { "name": "Process Id" } } ]
270/// @endcode
271/// would a result in a log record like:
272/// @code
273/// { "Process Id": 2313 }
274/// @endcode
275///
276/// #### The "tid""ktid" (threadkernel thread Id) field format {#ball_recordjsonformatter-the-tid-ktid-field-format}
277///
278///
279/// The format attributes of the thread Id field are given in the following
280/// table:
281/// @code
282/// Value Default
283/// Key Description Constraint Value
284/// -------- ------------------------------------- ----------- ------------
285/// "name" name by which "tid"/"ktid" will be JSON string "tid"/"ktid"
286/// published
287///
288/// "format" output format "decimal", "decimal"
289/// "hex"
290/// @endcode
291/// For example, the following record format specification:
292/// @code
293/// [ { "tid": { "name": "Thread Id",
294/// "format": "hex" } }
295/// ]
296/// @endcode
297/// would a result in a log record like:
298/// @code
299/// { "Thread Id": 0xA7654EFF3540 }
300/// @endcode
301///
302/// #### The "file" field format {#ball_recordjsonformatter-the-file-field-format}
303///
304///
305/// The format attributes of the "file" field are given in the following
306/// table:
307/// @code
308/// Default
309/// Key Description Value Constraint Value
310/// ------ -------------------- ----------------------------- -------
311/// "name" name by which "file" JSON string "file"
312/// will be published
313///
314/// "path" file path "full" (__FILE__), "full"
315/// "file" (basename of __FILE__)
316/// @endcode
317/// For example, the following record format specification:
318/// @code
319/// [ { "file": { "name": "File",
320/// "path": "file" } }
321/// ]
322/// @endcode
323/// would a result in a log record like:
324/// @code
325/// { "File": "test.cpp" }
326/// @endcode
327///
328/// #### The "line" field format {#ball_recordjsonformatter-the-line-field-format}
329///
330///
331/// The format attributes of the "line" field are given in the following
332/// table:
333/// @code
334/// Value Default
335/// Key Description Constraint Value
336/// ------ --------------------------------------- ----------- -------
337/// "name" name by which "line" will be published JSON string "line"
338/// @endcode
339/// For example, the following record format specification:
340/// @code
341/// [ { "line": { "name": "Line" } } ]
342/// @endcode
343/// would a result in a log record like:
344/// @code
345/// { "Line": 512 }
346/// @endcode
347///
348/// #### The "category" field format {#ball_recordjsonformatter-the-category-field-format}
349///
350///
351/// The format attributes of the "category" field are given in the following
352/// table:
353/// @code
354/// Value Default
355/// Key Description Constraint Value
356/// ------ ------------------------------------------ ----------- ----------
357/// "name" name by which "category" will be published JSON string "category"
358/// @endcode
359/// For example, the following record format specification:
360/// @code
361/// [ { "category": { "name": "Category" } } ]
362/// @endcode
363/// would a result in a log record like:
364/// @code
365/// { "category": "Server" }
366/// @endcode
367///
368/// #### The "severity" field format {#ball_recordjsonformatter-the-severity-field-format}
369///
370///
371/// The format attributes of the "severity" field are given in the following
372/// table:
373/// @code
374/// Value Default
375/// Key Description Constraint Value
376/// ------ ------------------------------------------ ----------- ----------
377/// "name" name by which "severity" will be published JSON string "severity"
378/// @endcode
379/// For example, the following record format specification:
380/// @code
381/// [ { "severity": { "name": "severity" } } ]
382/// @endcode
383/// would a result in a log record like:
384/// @code
385/// { "Severity": "ERROR" }
386/// @endcode
387///
388/// #### The "message" field format {#ball_recordjsonformatter-the-message-field-format}
389///
390///
391/// A message is a JSON string which is a sequence of zero or more Unicode
392/// characters, wrapped in double quotes, using backslash escapes: (\", \\, \/,
393/// \b, \f, \n, \r, \t, \u{4 hex digits}).
394///
395/// The format attributes of the "message" field are given in the following
396/// table:
397/// @code
398/// Value Default
399/// Key Description Constraint Value
400/// ------ ----------------------------------------- ----------- ---------
401/// "name" name by which "message" will be published JSON string "message"
402/// @endcode
403/// For example, the following record format specification:
404/// @code
405/// [ { "message": { "name": "msg" } } ]
406/// @endcode
407/// would a result in a log record like:
408/// @code
409/// { "msg": "Log message" }
410/// @endcode
411///
412/// #### The "attributes" format {#ball_recordjsonformatter-the-attributes-format}
413///
414///
415/// The "attributes" JSON object has no attributes. For example, the following
416/// record format specification:
417/// @code
418/// [ "attributes" ]
419/// @endcode
420/// would (assuming there are two attributes "bas.requestid" and
421/// "mylib.security") result in a log record like:
422/// @code
423/// { "bas.requestid": 12345, "mylib.security": "My Security" }
424/// @endcode
425///
426/// #### A user-defined attribute format {#ball_recordjsonformatter-a-user-defined-attribute-format}
427///
428///
429/// Each user-defined attribute has a single "name" attribute that can be used
430/// to rename the user-defined attribute:
431/// @code
432/// Value Default
433/// Key Description Constraint Value
434/// ------ ---------------------------- ----------- -------
435/// "name" name by which a user-defined JSON string none
436/// attribute will be published
437/// @endcode
438/// For example, the following record format specification:
439/// @code
440/// [ { "bas.uuid": { "name": "BAS.UUID" } } ]
441/// @endcode
442/// would a result in a log record like:
443/// @code
444/// { "BAS.UUID": 3593 }
445/// @endcode
446///
447/// ## The Record Separator {#ball_recordjsonformatter-the-record-separator}
448///
449///
450/// The record separator is a string that is printed after each formatted
451/// record. The default value of the record separator is a single newline, but
452/// it can be set to any string of the user's choice using the
453/// `RecordJsonFormatter::setRecordSeparator` function.
454///
455/// ## Usage {#ball_recordjsonformatter-usage}
456///
457///
458/// This section illustrates intended use of this component.
459///
460/// ### Example: Format log records as JSON and render them to stdout {#ball_recordjsonformatter-example-format-log-records-as-json-and-render-them-to-stdout}
461///
462///
463/// Suppose an application needs to format log records as JSON and output them
464/// to `stdout`.
465///
466/// First we instantiate a JSON record formatter:
467/// @code
468/// ball::RecordJsonFormatter formatter;
469/// @endcode
470/// Next we set a format specification to the newly created `formatter`:
471/// @code
472/// const int rc = formatter.setJsonFormat("[\"tid\",\"message\"]");
473/// assert(0 == rc); (void)rc;
474/// @endcode
475/// The chosen format specification indicates that, when a record is formatted
476/// using `formatter`, the thread Id attribute of the record will be output
477/// followed by the message attribute of the record.
478///
479/// Then we create a default `ball::Record` and set the thread Id and message
480/// attributes of the record to dummy values:
481/// @code
482/// ball::Record record;
483///
484/// record.fixedFields().setThreadID(6);
485/// record.fixedFields().setMessage("Hello, World!");
486/// @endcode
487/// Next, invocation of the `formatter` function object to format `record` to
488/// `bsl::cout`:
489/// @code
490/// formatter(bsl::cout, record);
491/// @endcode
492/// yields this output, which is terminated by a single newline:
493/// @code
494/// {"tid":6,"message":"Hello, World!"}
495/// @endcode
496/// Finally, we change the record separator and format the same record again:
497/// @code
498/// formatter.setRecordSeparator("\n\n");
499/// formatter(bsl::cout, record);
500/// @endcode
501/// The record is printed in the same format, but now terminated by two
502/// newlines:
503/// @code
504/// {"tid":6,"message":"Hello, World!"}
505///
506/// @endcode
507/// @}
508/** @} */
509/** @} */
510
511/** @addtogroup bal
512 * @{
513 */
514/** @addtogroup ball
515 * @{
516 */
517/** @addtogroup ball_recordjsonformatter
518 * @{
519 */
520
521#include <balscm_version.h>
522
526
527#include <bslma_allocator.h>
528#include <bslma_bslallocator.h>
529
531#include <bslmf_movableref.h>
532
533#include <bsla_deprecated.h>
534
535#include <bsls_keyword.h>
536
537#include <bsl_functional.h>
538#include <bsl_iosfwd.h>
539#include <bsl_string.h>
540#include <bsl_vector.h>
541
542#include <bsl_ostream.h>
543
544
545namespace baljsn { class SimpleFormatter; }
546namespace ball {
547
548class Record;
549class RecordAttributes;
550class RecordJsonFormatter_FieldFormatter;
551
552 // =========================
553 // class RecordJsonFormatter
554 // =========================
555
556/// This class provides a function object that formats a log record as JSON
557/// text elements and renders them to an output stream. The overloaded
558/// `operator()` provided by the class formats log record according to a
559/// message format specification supplied either by `setJsonFormat` or
560/// `setSimplifiedFormat` manipulator or the default format installed by the
561/// constructor) and outputs the result to the stream. While this functor type
562/// is designed to match the function signature expected by many concrete
563/// `ball::Observer` implementations that publish log records (for example,
564/// see `ball::FileObserver2::setLogFileFunctor`) it is advised to use the
565/// more flexible scheme-based format selection provided now by every BDE-made
566/// observer.
567///
568/// See @ref ball_recordjsonformatter
570
571 // PRIVATE TYPES
572
573 /// `MoveUtil` is an alias for `bslmf::MovableRefUtil`.
575
576 public:
577 // TYPES
578
579 /// `FieldFormatters` is an alias for a vector of the
580 /// `RecordJsonFormatter_FieldFormatter` objects, each of which is
581 /// initialized from the format specification and responsible for
582 /// rendering one field of a `ball::Record` to the output JSON stream.
584
586
587 /// Enumerator to determine the syntax of the specification string.
592
593 private:
594 // DATA
595 bsl::string d_formatSpec; // format specification (json or qjson)
596 SpecSyntax d_specSyntax; // how to interpret `d_formatSpec`
597
599 d_timezoneDefault; // `e_LOCAL` to publish in local time,
600 // `e_UTC` for UTC.
601
602 bsl::string d_recordSeparator; // string to print after each record
603
604 FieldFormatters d_fieldFormatters; // field formatters configured
605 // according to the format
606 // specification
607
608 // PRIVATE MANIPULATORS
609
610 /// Apply the current format specification `d_formatSpec` according to the
611 /// syntax determined by `d_specSyntax` to reconfigure this formatter's
612 // field formatters.
613 void applyCurrentFormat();
614
615 // CLASS METHODS
616
617 /// Destroy the field formatters contained in the specified
618 /// `formatters`.
619 static
620 void releaseFieldFormatters(FieldFormatters *formatters);
621
622 public:
623 // CLASS METHODS
624
625 /// This class method configures a formatter for the "json" scheme using
626 /// the specified `format` and `formatOptions` and if successful loads it
627 /// into the specified `output` and returns zero. In case configuration
628 /// fails a non-zero value is returned and `output` is not modified.
632 const RecordFormatterOptions& formatOptions);
633
634 /// This class method configures a formatter for the "qjson" scheme using
635 /// the specified `format` and `formatOptions` and if successful loads it
636 /// into the specified `output` and returns zero. In case configuration
637 /// fails a non-zero value is returned and `output` is not modified.
641 const RecordFormatterOptions& formatOptions);
642
643 // CREATORS
644
645 /// Create a record JSON formatter having a default format specification
646 /// and record separator. Optionally specify an `allocator` (e.g., the
647 /// address of a `bslma::Allocator` object) to supply memory; otherwise,
648 /// the allocator is used. The default format specification is:
649 /// @code
650 /// ["timestamp", "processId", "threadId", "severity", "file", "line",
651 /// "category", "message", "attributes"]
652 /// @endcode
653 /// The default record separator is "\n".
656
657 /// Create a record JSON formatter initialized to the value of the
658 /// specified `original` record formatter. Optionally specify an
659 /// `allocator` (e.g., the address of a `bslma::Allocator` object) to
660 /// supply memory; otherwise, the default allocator is used.
662 const RecordJsonFormatter& original,
664
665 /// Create a record JSON formatter having the same format specification
666 /// and record separator as in the specified `original` formatter, and
667 /// adopting all outstanding memory allocations and the allocator
668 /// associated with the `original` formatter. `original` is left in a
669 /// valid but unspecified state.
672
673 /// Create a record JSON formatter, having the same format specification
674 /// and record separator as in the specified `original` formatter. The
675 /// format specification of `original` is moved to the new object, and
676 /// all outstanding memory allocations and the specified `allocator` are
677 /// adopted if `allocator == original.get_allocator()`. `original` is
678 /// left in a valid but unspecified state.
681
682 /// Destroy this object.
684
685 // MANIPULATORS
686
687 /// Assign to this object the value of the specified `rhs` object, and
688 /// return a reference providing modifiable access to this object.
690
691 /// Assign to this object the format specification and record separator
692 /// of the specified `rhs` object, and return a reference providing
693 /// modifiable access to this object. The format specification and
694 /// record separator of `rhs` are moved to this object, and all
695 /// outstanding memory allocations and the allocator associated with
696 /// `rhs` are adopted if `get_allocator() == rhs.get_allocator()`.
697 /// `rhs` is left in a valid but unspecified state.
699
700 /// Set the message format specification (see {`Record Format
701 /// Specification`}) of this record JSON formatter to the specified
702 /// JSON-syntax `format`. Return 0 on success, and a non-zero value
703 /// otherwise (if `format` is not valid JSON *or* not a JSON conforming to the expected schema).
704 ///
705 /// \note Note that this is the method used by the
706 /// `json://` scheme.
708
709 /// @deprecated Use @ref setJsonFormat instead.
710 ///
711 /// Set the message format specification (see {`Record Format
712 /// Specification`}) of this record JSON formatter to the specified
713 /// JSON-syntax `format`. Return 0 on success, and a non-zero value
714 /// otherwise (if `format` is not valid JSON *or* not a JSON conforming to
715 /// the expected schema).
717
718 /// Parse the simplified format specification (see {`Simplified Record
719 /// Format Specification`}) in the specified `format` and configure this
720 /// formatter accordingly. Return 0 on success, and a non-zero value
721 /// otherwise.
723
724 /// Set the time zone default for every "timestamp" output without a
725 /// timezone specified in the format string to the specified `timezoneDefault`.
726 ///
727 /// \note Note that this method reapplies the current format
728 /// specification to update all timestamp formatters.
730
731 /// Set the record separator for this record JSON formatter to the
732 /// specified `recordSeparator`. The `recordSeparator` will be printed
733 /// by each invocation of `operator()` after the formatted record. The
734 /// default is a single newline character, "\n".
736
737 // ACCESSORS
738
739 /// Format the specified `record` according to the current `format` and
740 /// `recordSeparator` to the specified `stream`.
741 void operator()(bsl::ostream& stream, const Record& record) const;
742
743 /// Return the message format specification of this record JSON formatter. See {`Record Format Specification`}.
744 ///
745 /// \note Note that the syntax
746 /// of this string depends on `formatSyntax()`.
747 const bsl::string& format() const;
748
749 /// Return the message format specification syntax of this record JSON
750 /// formatter. See {`Record Format Specification`}.
751 SpecSyntax formatSyntax() const;
752
753 /// Get the time zone default setting.
755
756 /// Return the record separator of this record JSON formatter.
757 const bsl::string& recordSeparator() const;
758
759 // Aspects
760
761 /// @deprecated Use @ref get_allocator().mechanism() instead.
764
765 /// Return the allocator used by this object to supply memory.
767};
768
769// FREE OPERATORS
770
771/// Return `true` if the specified `lhs` and `rhs` record formatters have
772/// the same value, and `false` otherwise. Two record formatters have the
773/// same value if they have the same format syntax, format specification,
774/// timezone default, and record separator.
775bool operator==(const RecordJsonFormatter& lhs,
776 const RecordJsonFormatter& rhs);
777
778/// Return `true` if the specified `lhs` and `rhs` record formatters do not
779/// have the same value, and `false` otherwise. Two record formatters
780/// differ in value if their format syntax, format specifications, timezone
781/// defaults, or record separators differ.
782bool operator!=(const RecordJsonFormatter& lhs,
783 const RecordJsonFormatter& rhs);
784
785// ============================================================================
786// INLINE DEFINITIONS
787// ============================================================================
788
789 // -------------------------
790 // class RecordJsonFormatter
791 // -------------------------
792
793// CREATORS
794inline
796 const allocator_type& allocator)
797: d_formatSpec(original.d_formatSpec, allocator)
798, d_specSyntax(original.d_specSyntax)
799, d_timezoneDefault(original.d_timezoneDefault)
800, d_recordSeparator(original.d_recordSeparator, allocator)
801, d_fieldFormatters(allocator)
802{
803 applyCurrentFormat();
804}
805
806inline
809: d_formatSpec(MoveUtil::move(MoveUtil::access(original).d_formatSpec))
810, d_specSyntax(MoveUtil::access(original).d_specSyntax)
811, d_timezoneDefault(
812 MoveUtil::move(MoveUtil::access(original).d_timezoneDefault))
813, d_recordSeparator(
814 MoveUtil::move(MoveUtil::access(original).d_recordSeparator))
815, d_fieldFormatters(
816 MoveUtil::move(MoveUtil::access(original).d_fieldFormatters))
817{
818}
819
820inline
823 const allocator_type& allocator)
824: d_formatSpec(MoveUtil::move(MoveUtil::access(original).d_formatSpec),
825 allocator)
826, d_specSyntax(e_JSON)
827, d_timezoneDefault(
828 MoveUtil::move(MoveUtil::access(original).d_timezoneDefault))
829, d_recordSeparator(
830 MoveUtil::move(MoveUtil::access(original).d_recordSeparator),
831 allocator)
832, d_fieldFormatters(allocator)
833{
834 if (MoveUtil::access(original).get_allocator() == allocator) {
835 d_fieldFormatters = MoveUtil::move(
836 MoveUtil::access(original).d_fieldFormatters);
837 d_specSyntax = MoveUtil::access(original).d_specSyntax;
838 }
839 else {
840 d_specSyntax = MoveUtil::access(original).d_specSyntax;
841 applyCurrentFormat();
842 }
843}
844
845// MANIPULATORS
846inline
849{
850 if (this != &MoveUtil::access(rhs)) {
851 d_recordSeparator = MoveUtil::move(
852 MoveUtil::access(rhs).d_recordSeparator);
853 d_timezoneDefault = MoveUtil::move(
854 MoveUtil::access(rhs).d_timezoneDefault);
855
857 releaseFieldFormatters(&d_fieldFormatters);
858 d_formatSpec = MoveUtil::move(
859 MoveUtil::access(rhs).d_formatSpec);
860 d_fieldFormatters = MoveUtil::move(
861 MoveUtil::access(rhs).d_fieldFormatters);
862 d_specSyntax = MoveUtil::access(rhs).d_specSyntax;
863 }
864 else {
865 d_formatSpec = MoveUtil::access(rhs).d_formatSpec;
866 d_specSyntax = MoveUtil::access(rhs).d_specSyntax;
867 applyCurrentFormat();
868 }
869 }
870
871 return *this;
872}
873
874inline
876 const bsl::string_view& recordSeparator)
877{
878 d_recordSeparator = recordSeparator;
879}
880
881// ACCESSORS
882inline
884{
885 return d_formatSpec;
886}
887
888inline
893
894inline
897{
898 return d_timezoneDefault;
899}
900
901inline
903{
904 return d_recordSeparator;
905}
906
907 // Aspects
908
909inline
911{
912 return d_formatSpec.get_allocator().mechanism();
913}
914
915inline
918{
919 return d_formatSpec.get_allocator();
920}
921
922// PRIVATE MANIPULATORS
923inline
924void RecordJsonFormatter::applyCurrentFormat()
925{
926 if (d_specSyntax == e_SIMPLIFIED) {
927 const int rc = setSimplifiedFormat(d_formatSpec);
928 BSLS_ASSERT(0 == rc); (void) rc;
929 }
930 else {
931 const int rc = setJsonFormat(d_formatSpec);
932 BSLS_ASSERT(0 == rc); (void) rc;
933 }
934}
935
936} // close package namespace
937
938// FREE OPERATORS
939inline
940bool ball::operator==(const RecordJsonFormatter& lhs,
941 const RecordJsonFormatter& rhs)
942{
943 return lhs.formatSyntax() == rhs.formatSyntax() &&
944 lhs.format() == rhs.format() &&
945 lhs.timezoneDefault() == rhs.timezoneDefault() &&
946 lhs.recordSeparator() == rhs.recordSeparator();
947}
948
949inline
950bool ball::operator!=(const RecordJsonFormatter& lhs,
951 const RecordJsonFormatter& rhs)
952{
953 return !(lhs == rhs);
954}
955
956
957
958#endif // INCLUDED_BALL_RECORDJSONFORMATTER
959
960// ----------------------------------------------------------------------------
961// Copyright 2020 Bloomberg Finance L.P.
962//
963// Licensed under the Apache License, Version 2.0 (the "License");
964// you may not use this file except in compliance with the License.
965// You may obtain a copy of the License at
966//
967// http://www.apache.org/licenses/LICENSE-2.0
968//
969// Unless required by applicable law or agreed to in writing, software
970// distributed under the License is distributed on an "AS IS" BASIS,
971// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
972// See the License for the specific language governing permissions and
973// limitations under the License.
974// ----------------------------- END-OF-FILE ----------------------------------
975
976/** @} */
977/** @} */
978/** @} */
Definition ball_recordformatteroptions.h:112
Definition ball_recordjsonformatter.h:569
const bsl::string & recordSeparator() const
Return the record separator of this record JSON formatter.
Definition ball_recordjsonformatter.h:902
SpecSyntax formatSyntax() const
Definition ball_recordjsonformatter.h:889
~RecordJsonFormatter()
Destroy this object.
int setFormat(const bsl::string_view &format)
static int loadQjsonSchemeFormatter(RecordFormatterFunctor::Type *output, const bsl::string_view &format, const RecordFormatterOptions &formatOptions)
void operator()(bsl::ostream &stream, const Record &record) const
allocator_type get_allocator() const
Return the allocator used by this object to supply memory.
Definition ball_recordjsonformatter.h:917
RecordFormatterTimezone::Enum timezoneDefault() const
Get the time zone default setting.
Definition ball_recordjsonformatter.h:896
bsl::allocator allocator_type
Definition ball_recordjsonformatter.h:585
RecordJsonFormatter & operator=(const RecordJsonFormatter &rhs)
bsl::vector< RecordJsonFormatter_FieldFormatter * > FieldFormatters
Definition ball_recordjsonformatter.h:583
void setTimezoneDefault(RecordFormatterTimezone::Enum timezoneDefault)
int setSimplifiedFormat(const bsl::string_view &format)
BSLS_DEPRECATE bslma::Allocator * allocator() const
Definition ball_recordjsonformatter.h:910
SpecSyntax
Enumerator to determine the syntax of the specification string.
Definition ball_recordjsonformatter.h:588
@ e_JSON
Definition ball_recordjsonformatter.h:589
@ e_SIMPLIFIED
Definition ball_recordjsonformatter.h:590
static int loadJsonSchemeFormatter(RecordFormatterFunctor::Type *output, const bsl::string_view &format, const RecordFormatterOptions &formatOptions)
int setJsonFormat(const bsl::string_view &format)
const bsl::string & format() const
Definition ball_recordjsonformatter.h:883
RecordJsonFormatter(const allocator_type &allocator=allocator_type())
void setRecordSeparator(const bsl::string_view &recordSeparator)
Definition ball_recordjsonformatter.h:875
Definition ball_record.h:176
Definition bslma_bslallocator.h:588
BloombergLP::bslma::Allocator * mechanism() const
Definition bslma_bslallocator.h:1146
Definition bslstl_stringview.h:471
Definition bslstl_string.h:1252
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used by this string to supply memory.
Definition bslstl_string.h:7423
Forward declaration.
Definition bslstl_function.h:946
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslmf_movableref.h:752
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_DEPRECATE
Definition bsls_deprecate.h:720
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:674
Definition baljsn_convertfromjsonoptions.h:112
Definition ball_administration.h:214
bool operator!=(const Attribute &lhs, const Attribute &rhs)
bool operator==(const Attribute &lhs, const Attribute &rhs)
ALLOCATOR const STRING_VIEW_LIKE_TYPE & rhs
Definition bslstl_string.h:3918
ALLOCATOR & lhs
Definition bslstl_string.h:3917
Enum
Timezone setting for timestamps in log record formatters.
Definition ball_recordformattertimezone.h:114
Definition bslmf_movableref.h:795
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1039