Introduction#
Logging is the process of recording events, errors, and informational messages from an application. It helps developers and system administrators track the application's behavior and troubleshoot issues.
Think of logging like keeping a detailed diary or journal in your daily life. Just as you might jot down important events, thoughts, and feelings to remember what happened during your day, logging records events and messages generated by your software.
For example, if you encountered a problem, you’d look back through your diary to find clues about what went wrong. Similarly, in software development, logs help developers track issues, understand the flow of their application, and debug problems by providing a historical record of events. Just as a well-organized diary makes it easier to find information, effective logging helps streamline troubleshooting and improves the overall maintenance of the application.
Key aspects of logging include:#
- Types of Logs: Common types are error logs, access logs, and application logs. Each serves a different purpose, like capturing errors or tracking user activity.
- Log Levels: Logs can be categorized by severity, such as DEBUG, INFO, WARN, ERROR, and FATAL, allowing developers to filter and focus on relevant messages.
- Logging Frameworks: Many programming languages have libraries and frameworks (like Log4j, SLF4J, or Python’s logging module) that simplify the logging process and offer advanced features like formatting and log rotation.
- Best Practices: Effective logging involves ensuring that logs are clear, consistent, and stored in a way that facilitates easy searching and analysis. Sensitive information should be omitted for security reasons.
Logging#
Logging is the process of tracking all the events that happen after a piece of code is run. It is a very important aspect of software development as it helps to track where exactly the code crashes and thus eases debugging. A logging framework can be used to perform all the tasks like setting log file destinations, customizing log messages , etc.
SLF4J#
SLF4J (Simple Logging Facade for Java) is a simple and flexible logging framework that serves as a facade or abstraction for various logging frameworks such as Log4j, Logback, and java.util.logging. It allows developers to write logging code without being tied to a specific logging implementation. This flexibility enables easy switching between different logging frameworks without modifying the application code.
With SLF4J, you can log messages at different levels (e.g., DEBUG, INFO, WARN, ERROR) and include parameters in your log messages for more context. It also supports various logging backends, allowing you to choose the one that best fits your needs. Overall, SLF4J simplifies logging in Java applications while providing a consistent API across different logging solutions.
Elements of Logging Framework#
Every logging framework comes with three elements.
- Logger — capture the messages
- Formatter — formats the messages captured by the logger
- Handler — Dispatches the messages by printing them on the console , or storing them in a file , sending an email, etc.
Each component plays a crucial role in how logging is implemented and utilized, ensuring that messages are captured, formatted, and dispatched appropriately.
Log Levels#
The messages logged can be of various security levels . Spring Boot supports five log levels which are
- FATAL – fatal error crashing the system
- ERROR — runtime errors
- WARN — warning
- INFO — events occurring at the run time
- DEBUG — Information about the flow of the system
- TRACE — more detailed information about the flow of the system
Each level serves a specific purpose, helping developers prioritize and filter log messages based on their severity or importance.
EmployeeClient
OutPut
After running two applications (prod_ready_features test file, Employees application file)
Note:
INFO, WARN, ERROR logs are enabled by default. To enable TRACE and DEBUG logs, we need to configure the log levels explicitly.
Setting Log Levels#
- When you enable a level, Log4j logs these events at that level and all levels above it. For example, enabling WARN events will show WARN through FATAL events, but not INFO through TRACE.
logging.level.root=INFO
Setting logging.level.root=INFO
in your configuration file (like application.properties
or application.yml
) will configure the root logger to print logs at the INFO level and higher.
Here's how it works:
What Happens When logging.level.root=INFO
is Set:#
- INFO level logs are printed.
- WARN, ERROR, and FATAL logs are also printed (because they are higher severity than INFO).
- DEBUG and TRACE logs are not printed because they are lower in severity than INFO.
- For DEBUG: Set
logging.level.root=DEBUG
. This will printDEBUG
logs and all higher levels (INFO, WARN, ERROR, FATAL). - For TRACE: Set
logging.level.root=TRACE
. This will print the most detailed logs, includingTRACE
,DEBUG
, and everything above.
logging.level.com.myPackageName =DEBUG
By enabling a specific log level, you effectively control which messages are captured, allowing you to manage the verbosity of your logs. Your example of configuring levels in Spring Boot is spot on.
Application Properties
#Logging Configuration
#check logging trace or debug for clients package packagelogging.level.com.example.user.product_ready_features.product_ready_features.clients=TRACE
Output
Logging Level Hierarchy#
Logging frameworks follow a hierarchical system where each log level includes all levels that are more severe than it. Here's the typical order of log levels from least to most detailed:
- FATAL
- ERROR
- WARN
- INFO
- DEBUG
- TRACE
Key Concepts:#
- TRACE is the most detailed level and includes all levels below it (including
DEBUG
,INFO
,WARN
, etc.). - DEBUG is less detailed than
TRACE
. When you set the log level toDEBUG
, it includesDEBUG
,INFO
,WARN
,ERROR
, andFATAL
but notTRACE
.
Explanation of Your Observation:#
- When you configure TRACE:
- You are enabling TRACE logging.
- Since
TRACE
is the most detailed level, it will print everything, includingTRACE
,DEBUG
,INFO
,WARN
,ERROR
, andFATAL
logs.
- When you configure DEBUG:
- You are enabling DEBUG logging.
- Since
DEBUG
is less detailed thanTRACE
, it will print DEBUG logs and all more severe levels (INFO
,WARN
,ERROR
,FATAL
), but it won't printTRACE
logs. TRACE
is too detailed to be printed when the log level is set toDEBUG
.
Implementation in EmployeeClient class#
Code
To get the tracing information we need to configure the log levels explicitly.
- Output
- Successfully create new employee
- When Exception occurred
If we pass the wrong URI, specifically an incorrect endpoint, the entire code will enter the exception handling block. For example, if we use .uri("/employee") instead of .uri("/employees"), it will trigger an error.
- Successfully create new employee
Log Formatters#
The log messages can be formatted and customized according to our requirements by setting colors , message format , etc. logging.pattern.console= %d [%level] %c{2.} [%t] %m%n %d — date % level — log level %c — class path %t — thread executing %m — message %n — new line
Specifying the log file name and customizing the log pattern helps tailor the logging output to your needs. Your log pattern example provides a well-formatted way to include timestamps, log levels, class names, thread names, and messages.
- OutPut
Log Handlers#
1. Setting the Log File Name#
- Console Log Handling:
- If you want to set logs to display on the console, you use the default log handler.
- File Log Handling:
- If you want to write logs to a file, you would use a log handler that directs output to a file.
To specify the log file name, you use:
logging.file.name=error.log
After adding this configuration, if you run the test application, it will create a separate log file.
2. Setting the Log File Pattern#
To customize the log file's output format, you can define the pattern like this:
logging.pattern.file=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){green} [%level] %c{2.} [%t] %m%n
Breakdown of the Pattern#
%d{yyyy-MM-dd HH:mm:ss.SSS}
: Date and time in a specific format.%clr{...}{green}
: Colors the output (if supported).[%level]
: Displays the log level (e.g., INFO, WARN).%c{2.}
: Outputs the name of the logger, shortened to the last part.[%t]
: Shows the thread name.%m%n
: Displays the log message followed by a newline.
Logback Configuration XML Setup#
This is a one-time setup. To configure Logback, navigate to the resources
directory, create a new file named logback.xml
, and add the code below.
- Explanation
This Logback configuration sets up a rolling file logger that: - Writes logs to files in a
logs
directory. - Uses a specific log message format.
- Rolls over log files daily, creating new files when they exceed 10MB, and keeps logs for 30 days.
- Captures log messages at the DEBUG level and higher.
This setup is useful for applications where tracking detailed logs is important for debugging and monitoring, while also managing log file sizes and retention.
Configuration Element
This is the root element of the Logback configuration file. All Logback configurations are defined within this tag.
Properties
- LOG_PATTERN: This property defines the pattern for log messages. It uses:
%d{yyyy-MM-dd HH:mm:ss}
: The timestamp of the log message.%-5level
: The log level (e.g., DEBUG, INFO, ERROR) left-aligned and padded to 5 characters.%c{2.}
: The logger name (usually the class name) limited to the last two parts of the name (e.g.,com.example.ClassName
will be displayed asClassName
).%msg
: The actual log message.%n
: A newline character.
- LOG_PATH: This property specifies the directory where the log files will be stored. In this case, it is set to
logs
.
Appender
This defines an appender named ROLLING_FILE which is responsible for writing log messages to a file. The RollingFileAppender
allows log files to roll over based on time or size.
Rolling Policy
TimeBasedRollingPolicy: This rolling policy allows log files to be rolled over based on time.
- fileNamePattern: Specifies the pattern for naming the log files. It will create files like
application.2024-09-24.0.log
,application.2024-09-24.1.log
, etc., in thelogs
directory. - maxHistory: Sets the maximum number of days to keep log files. Here, it retains logs for 30 days.
- SizeAndTimeBasedFNATP: This triggers file rollover based on both size and time.
- maxFileSize: Specifies the maximum size for each log file. In this case, each log file will be capped at 10MB.
Encoder
The encoder defines how log messages are formatted before being written to the log file. Here, it uses the previously defined LOG_PATTERN
.
Root Logger
- root: This defines the root logger for the application.
- level: Sets the logging level for the root logger. In this case, it is set to DEBUG, meaning all logs at this level and higher (INFO, WARN, ERROR, FATAL) will be captured.
- appender-ref: This references the appender defined earlier (ROLLING_FILE), so all log messages at the root level will be sent to the rolling file appender.
To use this file, we need to tell Spring Boot to reference it. We can do this by configuring it in our application.properties
file like this:
logging.config=classpath:logback.xml
After running the application, a new log file is typically created in the logs
directory, depending on how your logback.xml
is configured.
In this article, we explored the fundamental concepts of logging in software development, emphasizing its importance in tracking application behavior and aiding in debugging. We discussed the various types of logs, log levels, and the role of logging frameworks, particularly SLF4J, in providing a flexible logging solution. The key elements of a logging framework—logger, formatter, and handler—were explained, along with best practices for effective logging. We also provided practical examples of logging implementation in a Spring Boot application, highlighting how to configure log levels and customize log outputs using patterns. Finally, we looked at how to manage log files and retention through Logback configuration, ensuring that logs are both informative and manageable for ongoing application maintenance.