...
An important aspect of this is analytics, which requires tracing of requests between components. In a large, distributed and scalable system such as ONAP this is critical to understanding behavior and performance.
...
General
It isn't the aim of this document to reiterate the basicsBest Practices, so advice here is general:
- Use a logger . Consider using such as SLF4J or EELF.
- Write log messages in English.
- Write meaningful messages. Consider what will be useful to consumers of logger output.
- Use errorcodes to characterise exceptions.
- Log at the appropriate level. Be aware of the volume of logs that will be produced.
- Safeguard the information in exceptions, and ensure it is never lost.
- Use errorcodes to characterise exceptions.
- Log in a machine-readable format. See Conventions.
- Log for analytics as well as troubleshooting.
...
- http://www.masterzen.fr/2013/01/13/the-10-commandments-of-logging/
- https://www.loggly.com/blog/how-to-write-effective-logs-for-remote-logging/ And so on
- -of-logging/
- https://www.loggly.com/blog/how-to-write-effective-logs-for-remote-logging/
- And so on.
Standard Attributes
These are attributes common to all log messages. They are either:
- Explicitly required by logging APIs:
- Logger
- Level
- Message
- Exception (note that exception is the only standard attribute that may routinely be empty).
- Implicitly derived by the logging provider:
- Timestamp
- Thread.
See https://www.slf4j.org/api/org/slf4j/Logger.html and https://logback.qos.ch/manual/layouts.html#ClassicPatternLayout for their origins and use.
Logger
This indicates the origin of a log message.
It is confusingly named, and since in Java logging it is normally a class or package name, it's commonly referred to as the logger "class" or "package".
- In Java, report the class or package name.
- In Python, the class or source filename.
Most other languages will fit one of those patterns.
Timestamp
Logged as an ISO8601 UTC datetime. Millisecond (or greater) precision is preferable.
For example:
Code Block | ||
---|---|---|
| ||
2018-07-05T20:21:34.794Z |
Offset timestamps are OK provided the offset is explicit. (In the above example, the "Z" is a shorthand indicating an offset of zero – UTC).
Level
Severity, typically drawn from the enumeration {TRACE, DEBUG, INFO, WARN, ERROR}.
Think carefully about the information you report at each loglevel. The default log level is INFO.
Some loggers define non-standard levels, like FINE, FINER, WARNING, SEVERE, FATAL or CRITICAL. Use these judiciously, or avoid them.
Thread
The name of the thread from which the log message was emitted.
Thread names don't necessarily convey useful information, and their reliability depends on the thread model implemented by different runtimes, but they are sometimes used in heuristic analysis.
Message
The freetext payload of a log event.
Internationalization
Diagnostic log messages generally do not need to be internationalized.
Parameterization
Parameterized messages allow serialization to be deferred until AFTER level threshold checks.
- Favor parameterized messages, especially for DEBUG logging.
- Perform expensive serialization in the #toString method of wrapper classes.
For example:
Code Block | ||
---|---|---|
| ||
logger.debug("This won't hurt: {}", new ToStringWrapper(costlyToSerialize)); |
Exception
The error stacktrace, where applicable.
Log unabridged stacktraces upon error.
When rethrowing, ensure that frame information is not lost:
- By logging the original exception at the point where it was caught.
- By setting the original exception as the cause when rethrowing.
Efficiency
There is tension between verbosity and efficiency. IO bandwidth is finite, and the cost of serialization can be significant, especially at higher diagnostic levels.
Methods and Line Numbers
Many loggers can use reflection to emit the originating (Java) method, and even individual line numbers.
This information is useful, but very expensive. Most logging implementations recommend that this not be enabled in production.
Level Thresholds
Level indicates severity.
Logger output is typically filtered by level. The default logging level is INFO, so particular consideration should be given to the efficiency of INFO-level logging.
When DEBUG-level logging is configured, it's probably for good reason, and a greater overhead is expected. Be aware that it's not unusual for DEBUG logging to be left enabled inadvertently, however.
WARN and ERROR-level messages are generally high-value, and comparatively rare, so their cost is less of a concern.
Conditionals
A common pattern is to place conditionals around (expensive) debug logging.
For example:
Code Block | ||
---|---|---|
| ||
if (logger.isDebugEnabled()) {
logger.debug("This is going to hurt: " + costlyToSerialize);
} |
Parameterized logging is preferable.
Context
MDCs
A Mapped Diagnostic Context (MDC) allows an arbitrary string-valued attribute to be attached to a Java thread via a ThreadLocal variable. The MDC's value is then emitted with each message logged by that thread. The set of MDCs associated with a log message is serialized as unordered name-value pairs (see Text Output).
...
TBD: cover off discussion on reducing log files to two (DEBUG/rest) for C* release
MDC -
...
TargetElement
VNF/PNF context dependent - on CRUD operations of VNF/PNFs
...