Provide a formatter for log records that renders output in JSON.
More...
Detailed Description
- Outline
-
-
- Purpose:
- Provide a formatter for log records that renders output in JSON.
-
- Classes:
-
- See also:
- Component ball_record, Component ball_recordattributes
-
- Description:
- This component provides a function object class,
ball::RecorJsonFormatter
, that formats a log record as JSON text elements according to a format specification (see Record Format Specification
). ball::RecordJsonFormatter
is designed to match the function signature expected by many concrete ball::Observer
implementations that publish log records (for example, see ball::FileObserver2::setLogFileFunctor
).
- NOTE:
ball::RecorJsonFormatter
renders individual log records as JSON, but, for example, a resulting log file would contain a sequence of JSON strings, which is not itself valid JSON text.
-
- Record Format Specification:
- A format specification is, itself, a JSON array, supplied to a
RecordJsonFormatter
object by the setFormat
function. If no format is specified, the default format is used. Each array element specifies the format of a log record field or a user-defined attribute. Here is a simple example: [{"timestamp":{"format":"iso8601"}}, "pid", "tid", "severity", "message"]
would a result in a log record like: { "timestamp": "2020-08-28T14:43:50.375Z",
"pid": 2313,
"tid": 12349388604,
"severity": "INFO",
"message": "Hello, world!"
}
Again, the format specification is a JSON array, each element of which can be one of the following:
-
A string containing the name of the fixed record field or the name of the user-defined attribute, in which case the field or attribute will be published in the default format. For example,
[timestamp]
, would display the timestamp as: {"timestamp": "2020-08-28T14:43:50.375Z"}
.
-
A JSON object having the name of the fixed field or user-defined attribute and a set of key-values pairs used to customize the output format. For example,
[{"timestamp": {"name": "My Time", "format": "bdePrint"}}]
, would display the timestamp as: {"My Time": "28AUG2020_14:43:50.375"}
.
-
- Field Format Specification:
- The following table lists the predefined string values for each fixed field and user-defined attributes in the log record:
Tag Description Example
-------------- ------------------------- -------------
"timestamp" creation date and time ["timestamp"]
"pid" process id of creator ["pid"]
"tid" thread id of creator ["tid"]
"file" file where created (__FILE__) ["file"]
"line" line number in file (__LINE__) ["line"]
"category" category of logged record ["category"]
"severity" severity of logged record ["severity"]
"message" log message text ["message"]
"attributes" all user-defiend attributes ["attributes"]
<attribute name> specific user-defined attribute ["bas.uuid"]
The output format of each field can be customized by replacing a string value in the JSON array with a JSON object having the same name and a set of key-value pairs (attributes).
-
- Verifying the Format Specification for setFormat:
- The sections that follow describe the set of fields that can be provided in the format specification supplied to
setFormat
. RecordJsonFormatter::setFormat
will ignore fields in the provided format specification that are unknown, but will report an error if a known field contains a property that is not supported. For example: a format specification '["pid", { "timestamp" : {"unknown field!": "value"} }] will be accepted, but ["pid", {"timestamp": {"format": "unknown format" }}]
will produce an error.
- Each key-value pair of a JSON object that specifies a format of an output of a fixed record field or a user-defined attribute has the following constrains:
-
The key is a string of known value listed in the column "Key" in the tables below. Any string that does not match the listed values is ignored.
-
The value is a string of known value (except for the "name" key) in the column "Value Constraint" in the tables below. If the value does not match the string values specified in the tables, the format specification is considered to be inconsistent with the expected schema, and is rejected by the
RecordJsonFormatter::setFormat
method.
-
- The "timestamp" field format:
- The format attributes of the "timestamp" object are given in the following table:
Value Default
Key Description Constraint Value
------------------------ ---------------- ----------- ------------
"name" name by which JSON string "timestamp"
"timestamp" will
be published
"format" datetime format "iso8601", "iso8601"
"bdePrint"
(*Note*)
"fractionalSecPrecision" second precision "none", "microseconds"
"milliseconds",
"microseconds"
"timeZone" time zone "utc", "utc"
"local"
Note: The default "bdePrint" format denotes the following datetime format: For example, the following record format specification: [ { "timestamp": { "name": "Time",
"fractionalSecPrecision": "microseconds",
"timeZone": "local" } }
]
would a result in a log record like: { "Time": "28AUG2020_17:43:50.375345" }
-
- The "pid" (process Id) field format:
- The format attributes of the process Id field are given in the following table:
Value Default
Key Description Constraint Value
------ ------------------------------------- ----------- -------
"name" name by which "pid" will be published JSON string "pid"
For example, the following record format specification: [ { "pid": { "name": "Process Id" } } ]
would a result in a log record like:
-
- The "tid" (thread Id) field format:
- The format attributes of the thread Id field are given in the following table:
Value Default
Key Description Constraint Value
-------- ------------------------------------- ----------- ---------
"name" name by which "tid" will be published JSON string "tid"
"format" output format "decimal", "decimal"
"hex"
For example, the following record format specification: [ { "tid": { "name": "Thread Id",
"format": "hex" } }
]
would a result in a log record like: { "Thread Id": 0xA7654EFF3540 }
-
- The "file" field format:
- The format attributes of the "file" field are given in the following table:
Default
Key Description Value Constraint Value
------ -------------------- ----------------------------- -------
"name" name by which "file" JSON string "file"
will be published
"path" file path "full" (__FILE__), "full"
"file" (basename of __FILE__)
For example, the following record format specification: [ { "file": { "name": "File",
"path": "file" } }
]
would a result in a log record like:
-
- The "line" field format:
- The format attributes of the "line" field are given in the following table:
Value Default
Key Description Constraint Value
------ --------------------------------------- ----------- -------
"name" name by which "line" will be published JSON string "line"
For example, the following record format specification: [ { "line": { "name": "Line" } } ]
would a result in a log record like:
-
- The "category" field format:
- The format attributes of the "category" field are given in the following table:
Value Default
Key Description Constraint Value
------ ------------------------------------------ ----------- ----------
"name" name by which "category" will be published JSON string "category"
For example, the following record format specification: [ { "category": { "name": "Category" } } ]
would a result in a log record like:
-
- The "severity" field format:
- The format attributes of the "severity" field are given in the following table:
Value Default
Key Description Constraint Value
------ ------------------------------------------ ----------- ----------
"name" name by which "severity" will be published JSON string "severity"
For example, the following record format specification: [ { "severity": { "name": "severity" } } ]
would a result in a log record like:
-
- The "message" field format:
- A message is a JSON string which is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes: (", \, \/, \b, \f, \n, \r, \t, \u{4 hex digits}).
- The format attributes of the "message" field are given in the following table:
Value Default
Key Description Constraint Value
------ ----------------------------------------- ----------- ---------
"name" name by which "message" will be published JSON string "message"
For example, the following record format specification: [ { "message": { "name": "msg" } } ]
would a result in a log record like:
-
- The "attributes" format:
- The "attributes" JSON object has no attributes. For example, the following record format specification: would (assuming their are two attributes "bas.requestid" and "mylib.security") result in a log record like:
{ "bas.requestid": 12345, "mylib.security": "My Security" }
-
- A user-defined attribute format:
- Each user-defined attribute has a single "name" attribute that can be used to rename the user-defined attribute:
Value Default
Key Description Constraint Value
------ ---------------------------- ----------- -------
"name" name by which a user-defined JSON string none
attribute will be published
For example, the following record format specification: [ { "bas.uuid": { "name": "BAS.UUID" } } ]
would a result in a log record like:
-
- The Record Separator:
- The record separator is a string that is printed after each formatted record. The default value of the record separator is a single newline, but it can be set to any string of the user's choice using the
RecordJsonFormatter::setRecordSeparator
function.
-
- Usage:
- This section illustrates intended use of this component.
-
- Example: Format log records as JSON and render them to stdout:
- Suppose an application needs to format log records as JSON and output them to
stdout
.
- First we instantiate a JSON record formatter: Next we set a format specification to the newly created
formatter
: int rc = formatter.setFormat("[\"tid\",\"message\"]");
assert(0 == rc);
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.
- Then we create a default
ball::Record
and set the thread Id and message attributes of the record to dummy values: Next, invocation of the formatter
function object to format record
to bsl::cout
: formatter(bsl::cout, record);
yields this output, which is terminated by a single newline: {"tid":6,"message":"Hello, World!"}
Finally, we change the record separator and format the same record again: formatter.setFormat("\n\n");
formatter(bsl::cout, record);
The record is printed in the same format, but now terminated by two newlines: {"tid":6,"message":"Hello, World!"}