Logging should use consistent structured format. Logging should include timestamp, and unique IDs (such as session ID, user ID, application ID, facility ID, etc). We may need to build our own logger that extend the base logging library. Structure and consistent logging makes program easier to debug and maintain.

Log level should be configured at reasonable level. There should be a way to dynamically change the log level at the container level, or individually change the log level at the user level. Verbose logging can severely impact application performance

What should be logged?

In general, anything that may take a long time, or fail should be logged.

Wherever possible, both the beginning and the end of an operation should be logged

Service initiation, configuration, and termination: Whenever a service starts up or a service request thread is launched, this should be logged. If the service can be configured, this message must contains a reference to the service configuration used. The termination message should include a status or termination message or code

Errors: All errors that cause a component to exit should be logged

Authentication and authorization operations: Authentication events should include the authentication method and claimed identity. Authorization events should include the remote identity, mechanism, and mechanism-specific attributes. We should also include a reason for authentication error. It may make sense to define different reason codes for different authentication methods – for example, standard X.509 authentication may have reasons like “certificate expired” or “certificate issued by untrusted CA”, while username/password authentication may have reasons like “unknown user” or “bad password”.

Remote Connection: When a log message pertains to an attempted connection to/from a remote service, the log should contain the IP address and port number.

Entering or exiting functions and major loops

How should events be logged?

The essential elements for constructing high-quality logs are as follows:

Event types: Unique names for each logged event from a heirarchical namespace

Timestamps: High-resolution timestamps in a standard format

Identifier: Explicit and clearly labeled identifier for resources

When should we log?

At the beginning of each function. We should log the function name, and the values of simple parameters (except possibly for parameters that are objects, in which case we can test to see if the parameters are defined)

Every decision points

At the end of each function. We should log the name of the function, and its return value.

When should we not log?

Avoid logging in a tight loop

Why do we need to use logging?

Inserting log statements into code is a low-tech method for debugging it. It may also be the only way because debuggers are not always available or applicable. This is usually the case for multithreaded applications and distributed applications at large. Experience indicates that logging was an important component of the development cycle. It offers several advantages. It provides precise context about a run of the application. Once inserted into the code, the generation of logging output requires no human intervention. Moreover, log output can be saved in persistent medium to be studied at a later time. In addition to its use in the development cycle, a sufficiently rich logging package can also be viewed as an auditing tool.