• Labs icon Lab
  • Core Tech
Labs

Guided: Java Logging API

In this Guided Code Lab, you will gain hands-on experience with Java's logging features. You’ll dive into key logging concepts, such as different logging levels, configuration methods, and best practices for designing effective logging strategies that improve code maintainability and troubleshooting. Additionally, you will explore SLF4J for seamless integration across various logging systems. By the end of the lab, you’ll be equipped to implement efficient and robust logging in your Java applications.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 53m
Published
Clock icon Dec 16, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    Effective logging is crucial for debugging, monitoring, and maintaining Java applications. In this lab, you will dive into the fundamental concepts of Java's logging framework and its practical use in real-world applications.

    You'll gain hands-on experience configuring the logging system, creating custom handlers, and implementing best practices to ensure your logging is both efficient and scalable.


    Scenario

    You work in the IT department of Globomantics Retail, a company operating in the retail sector. You are responsible for managing the product catalog across stores. Currently, the company operates in 10 different regions, with plans for further expansion.

    Each day, you receive product catalog updates from these regions, which you update. Occasionally, product information contains typos or incorrect entries, which you must identify and correct.

    Given the anticipated increase in the number of stores and products, your company has tasked you with developing a mechanism to efficiently track and address such issues.

    To meet this need, you plan to integrate logging into your application. This will help you monitor problems and errors that occur during bulk product additions or deletions. Additionally, logging will enable you to generate detailed reports of problematic product entries, which you can share with the respective stores for correction.


    Project Files Overview

    A brief description of the initial files in this lab:

    • GlobomanticsRetailApp.java: Main application for managing products in Globomantics' retail system, leveraging Java logging for process tracking.

    • ProductService.java: Handles product catalog management by adding and deleting products while logging operations and errors.

    • ProductFactory.java: Generates a sample product list with both valid and invalid entries for testing purposes.

    • logging.properties: Defines Java logging settings, including console and file handlers, log levels, formatting, and output targets.

    --- Before you begin, here are some key points:

    • Your task involves implementing code in the Java project’s source files: GlobomanticsRetailApp.java , ProductService.java and logging.properties.
    • If you encounter any challenges along the way, feel free to consult the solution directory.
    • To help identify the required changes, comments are included in the code to guide you through each task.
  2. Challenge

    Getting Started with Java Logging

    In this step, you will begin implementing Java logging in your application.

    At the moment, the application uses System.out to log information to the console. To run the application, enter the following command in the Terminal:

    mvn clean install exec:java -q
    

    Now, it's time to kickstart the power of Java logging by importing the Java logging libraries! Alternatively, you could have imported specific classes individually. However, to simplify the code and avoid adding multiple import statements, all classes in the java.util.logging package are included using .*.

    Next, you will define a logger that will be used to log important messages, warnings, and errors. info> Why should you use final and static?

    The logger is declared static because it belongs to the class rather than any specific object, ensuring a single shared instance across the entire application. Also it is marked final to prevent accidental reassignment, ensuring the logger reference remains constant.


    Next, you will use this logger to log a message. The logger also provides a fine method for more detailed logging. You'll learn more about it in the next step.

    Now, you'll replace the remaining System.out.println statements with LOGGER.fine. ---

    Now, run the application by entering the following command in the Terminal:

    mvn clean install exec:java
    

    Alternatively, you can add the -q flag (quiet mode) to display only the application logs, excluding the build information:

    mvn clean install exec:java -q
    

    You should see an output similar to the following:

    Dec 14, 2024 12:54:39 PM com.pluralsight.logging.GlobomanticsRetailApp main
    INFO: ## Processing Started
    Product ID: 101 is being added.
    Product ID: 101 added successfully.
    Product ID: 102 is being added.
    Product ID: 102 added successfully.
    Product ID: -13 is being added.
    Product ID: -13 is invalid
    Product ID: 204 is being added.
    Product ID: 204 added successfully.
    Product ID: 205 is being added.
    Product ID: 205 added successfully.
    Product ID: 102 is being added.
    Product ID: 102 already exists.
    Product ID: 307 is being added.
    Product ID: 307 has invalid Qty: -2
    Product ID: 101 deleting..
    Product ID: 101 is deleted successfully.
    Product ID: 1001 deleting..
    Product ID: 1001 not found.
    

    Notice that the LOGGER.fine message did not appear because the default logging level in Java Logging is set to INFO.

    --- Excellent job!

    In this step, you initialized the logger and printed your first log message.

    In the next step, you'll learn about different logging levels, which will help you categorize and control the severity of the messages logged in your application. This allows for better organization and management of log data.

  3. Challenge

    Implementing Logging Levels

    Logging levels help categorize the importance or severity of messages. Understanding of levels is crucial for managing logs effectively, ensuring that appropriate information is logged at the right level.

    info> When you set a logging level, only messages at that level and those of higher severity will be printed. For example, if you set the logging level to WARNING, only WARNING and SEVERE messages will be logged.

    Similarly, if you set logging level to INFO, then only INFO, WARNING and SEVERE will be printed.

    ALL can be used if you want to print all logs.


    Logging Levels Explained

    | Logging Level | Description | |-------------------|---------------------------------------------------------------------------------------------------| | SEVERE | Indicates serious failures that may cause the application to stop or behave unexpectedly | | WARNING | Warns of potentially harmful situations that are non-critical but may cause problems later | | INFO | Used for general informational messages that highlight the progress of the application. | | CONFIG | Used for logging configuration or setting up details | | FINE | Provides detailed tracing information helpful for debugging the application's behavior | | FINER | More detailed than FINE, used for fine-grained tracing and deeper debugging | | FINEST | The most detailed level, useful for tracking every step in a process or algorithm |

    Example Use Cases

    | Logging Level | Example Use Case | | -------- | -------- | | SEVERE | LOGGER.severe("Database connection failed. Application will shut down.") | | WARNING | LOGGER.warning("Product ID not found.") | | INFO | LOGGER.info("User login successful.") | | CONFIG | LOGGER.config("Logging level set to INFO.") | | FINE | LOGGER.fine("Processing item 123...") | | FINER | LOGGER.finer("Method calculateTax() called with params: amount=100, taxRate=0.05") | | FINEST | LOGGER.finest("Entering loop iteration 3...") |

    Now, you'll update your application to use different logging levels. Great! Similarly, you will update the deleteProduct method and replace System.out with LOGGER. Awesome!

    Since System.out has been replaced with loggers, you can now control the log output using different logging levels. Run the application by typing the following command in the Terminal:

    mvn clean install exec:java -q
    

    You will see an output similar to the following:

    Dec 14, 2024 12:52:01 PM com.pluralsight.logging.GlobomanticsRetailApp main
    INFO: ## Processing Started
    Dec 14, 2024 12:52:01 PM com.pluralsight.logging.ProductService addProduct
    SEVERE: Product ID: -13 is invalid
    Dec 14, 2024 12:52:01 PM com.pluralsight.logging.ProductService addProduct
    WARNING: Product ID: 102 already exists.
    Dec 14, 2024 12:52:01 PM com.pluralsight.logging.ProductService addProduct
    SEVERE: Product ID: 307 has invalid Qty: -2
    Dec 14, 2024 12:52:01 PM com.pluralsight.logging.ProductService deleteProduct
    WARNING: Product ID: 1001 not found.
    
    

    By examining the output, you'll see that only logs related to issues are shown, making it simpler to review the logs.

    In the next step, you will improve the readability of the logs by configuring logging with logging.properties and exploring logging to files.

  4. Challenge

    Configuring Logging

    In this step, you'll learn how to setup logging configurations using logging.properties.


    The logging.properties File

    This file is Java's central logging configuration tool, allowing you to define logging levels, handlers, and formatters for flexible log management without changing the application code.


    Key Components of logging.properties:

    1. Loggers

    Loggers are the central point for issuing logging requests in your code. Each logger is associated with a fully-qualified class name or a named string that represents a component:

    com.example.MyClass=INFO
    

    2. Handlers

    Handlers are responsible where log messages are written (e.g., ConsoleHandler, FileHandler, and SocketHandler). The handlers property of a logger specifies which handlers it uses:

    handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
    

    3. Formatters

    Formatters control the layout of log messages when written by a Handler (e.g., SimpleFormatter and XMLFormatter):

    java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
    

    Since the logging configuration is being moved from the code to logging.properties, defining the log level in the ProductService.java file is no longer necessary, as it will be managed through the properties file. Next, you will add the logging config in logging.properties. The class or package-level configuration enables logs of the configured severity level to pass through. You can then specify which severity levels should be sent to the console and file.

    For example, you can direct all INFO and higher severity logs to the ConsoleHandler, while sending only WARNING and higher severity logs to the FileHandler. This approach keeps all critical errors organized in a single file for easy reference. --- You can pass the logging level externally to the application using a system property.

    Run the application using the following command:

    mvn clean install exec:java -Djava.util.logging.config.file=src/main/resources/logging.properties -q
    

    You will observe that only logs with a severity level up to WARNING are logged into the issueDetails.log file, while all logs up to the INFO level are displayed in the console.


    When you rerun the application multiple times, you'll notice that the log file is overwritten each time the application starts. To append logs to the same file instead of overwriting it, you can set the append property to true. Rerun the application using the following command:

    mvn clean install exec:java -Djava.util.logging.config.file=src/main/resources/logging.properties -q
    

    --- The log formatting can be enhanced further by removing extra details like the fully qualified class name and other non-essential information.

    Now, you will adjust the SimpleFormatter to show only the Date, Timestamp, and Log message on a single line. ### Custom Log Handler

    info> You can also create your own custom handler, such as DatabaseLoggingHandler, which redirects logs to a database, or QueueNotificationHandler, which redirects logs to a queue.

    To create your own custom logging handler in Java, extend the java.util.logging.Handler class, and implement the publish(), flush(), and close() methods to define how logs are handled, then configure it in the logging.properties file or add it programmatically to your logger.

    --- Rerun the application by running the below command in Terminal:

    mvn clean install exec:java -Djava.util.logging.config.file=src/main/resources/logging.properties -q
    

    You should see an output similar to the following in the console:

    [Sat Dec 14 14:45:20 UTC 2024] INFO: ## Processing Started 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 101 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 101 added successfully. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 102 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 102 added successfully. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: -13 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] SEVERE: Product ID: -13 is invalid 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 204 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 204 added successfully. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 205 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 205 added successfully. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 102 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] WARNING: Product ID: 102 already exists. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 307 is being added. 
    [Sat Dec 14 14:45:20 UTC 2024] SEVERE: Product ID: 307 has invalid Qty: -2 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 101 deleting.. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 101 is deleted successfully. 
    [Sat Dec 14 14:45:20 UTC 2024] INFO: Product ID: 1001 deleting.. 
    [Sat Dec 14 14:45:20 UTC 2024] WARNING: Product ID: 1001 not found. 
    

    Contents of issueDetails.log file:

    [Sat Dec 14 14:45:20 UTC 2024] SEVERE: Product ID: -13 is invalid 
    [Sat Dec 14 14:45:20 UTC 2024] WARNING: Product ID: 102 already exists. 
    [Sat Dec 14 14:45:20 UTC 2024] SEVERE: Product ID: 307 has invalid Qty: -2 
    [Sat Dec 14 14:45:20 UTC 2024] WARNING: Product ID: 1001 not found. 
    

    Now, each log appears on a single line, making it easier to read.


    Great! This simplifies how you view logs, providing exactly the errors you need in the log file, which can be used to report issues to your retail stores.

    In the next step, you'll look at logging best practices.

  5. Challenge

    Logging Best Practices

    Effective logging helps maintain, debug, and monitor applications. Here are some key best practices for logging:

    1. Log the Right Information

    • Log Critical Events: Record important events like application start/stop, errors, and major transactions.

    • Avoid Sensitive Data: Never log sensitive information, such as passwords or personal identification data, to ensure security and privacy

    • Use Contextual Information: Include request IDs, user IDs, or session details for traceability.

    Next, you will update the log to include unique identifier for traceability. Next, remove the sensitive information from the logs. ---

    2. Use Appropriate Log Levels

    • FINE/DEBUG: Detailed information for debugging.
    • INFO: General application events like service starts or configuration loads.
    • WARNING: Potential issues that may not require immediate attention.
    • ERROR/SEVERE: Critical issues that need urgent resolution.

    3. Manage Logging Storage Effectively

    Balancing log retention and storage management is essential. While logs are critical for auditing and troubleshooting, storing too many logs can overwhelm the storage and slow down applications.

    • Log Rotation: Set file size limits and use file rotation.

    • Retention Policies: Define policies for log retention and archival.

    • Persistent Logs: Keep critical audit logs that require long-term storage without rotation for compliance and traceability.

    • Filter Logs: Log only what is necessary for business and debugging purposes. ---

    4. Enable Logging Across Environments

    Enable logging across development, staging, and production environments, using appropriate log levels for each. In production, set the log level to WARNING or SEVERE to capture only critical issues while minimizing log volume.

    5. Log Exceptions with Stack Traces

    It's a good idea to have the full stack trace for easier debugging:

    try {
        // Some code
    } catch (Exception e) {
        LOGGER.error("Exception occurred while processing order ID: {}", orderId, e);
    }
    ``` ---
    ### 6. Avoid Logging in Tight Loops
    Prevent excessive logging in loops to avoid performance degradation.
    
    As the number of products may grow in the future, excessive logging can negatively impact performance. You will now remove unnecessary logs. In this step, you explored logging best practices for effective log management.  
    
    In the next step, you'll learn how to design logging strategies, enabling you to structure and organize logs for better monitoring, debugging, and system analysis.
  6. Challenge

    Designing Logging Strategies

    Developing a robust logging strategy is essential for maintaining application reliability, diagnosing issues, and ensuring compliance. Different applications, including microservices and enterprise systems, require tailored logging approaches based on their architecture and operational needs.


    Key Considerations for Designing Logging Strategies

    1. Log Categories and Levels:

    • Use appropriate log levels, such as DEBUG, INFO, WARNING, ERROR, and CRITICAL, to categorize log messages effectively.
    • Categorize logs by application modules or services for easier traceability.
    • User log information can go in userAccess.log.

    2. Centralized Logging:

    • Aggregate logs from microservices into a central logging system for monitoring and analysis.
    • Use tools like Elasticsearch, Logstash, and Kibana (ELK Stack) or cloud-based logging services.

    3. Log Format and Structure:

    • Standardize log formats using JSON or key-value pairs for easy parsing.
    • Include context information, such as timestamps, request IDs, and user IDs.

    info> JSON logging provides structured, machine-readable logs that enhance searchability, parsing, and integration with monitoring tools. It supports efficient log indexing, debugging, and troubleshooting by embedding key-value pairs for better context, making it ideal for distributed systems and real-time monitoring.

    4. Log Retention and Rotation:

    • Define retention policies to comply with regulatory requirements.
    • Use log rotation to prevent storage overflow while retaining critical data.

    You will now configure a 500 KB size limit per log file and set the maximum number of log files to 10. When a file reaches 500 KB, a new one is created. The system cycles through up to 10 files, overwriting the oldest when the limit is reached. This setup ensures recent logs remain accessible while maintaining a maximum total log size of 5 MB. 5. Security and Compliance:

    • Mask or remove sensitive data in logs to prevent data breaches.
    • Implement access controls for log management systems.

    6. Logging OSS Vulnerabilities:

    • Monitor and log vulnerabilities in open-source software (OSS) dependencies by integrating tools that scan for known vulnerabilities (e.g., OWASP Dependency-Check and Snyk).

    • Ensure that logs capture critical information related to OSS components, such as version numbers and vulnerability alerts, to track and address potential security risks effectively.

    7. Monitoring and Alerts:

    • Set up real-time monitoring and alerting based on log patterns or errors.
    • Integrate logs with incident management tools for automated responses.

    8. Application-specific Logging:

    • Design customized logging strategies based on the application's nature, such as:
      • Microservices: Include service-to-service communication logs.
      • Enterprise Systems: Focus on transactional logs and audit trails.
      • Serverless & Cloud Functions: Ensure logs capture execution context and service-specific details.

    By carefully designing your logging strategy with these considerations, you can ensure efficient and reliable logging that meets the unique demands of your application's architecture while supporting operational goals.

    --- In the next step, you'll learn about SLF4J, its use, and how it serves as a simple facade or abstraction for various logging frameworks.

  7. Challenge

    SLF4J for Logging

    Simple Logging Facade for Java (SLF4J) is a widely adopted logging abstraction that provides a consistent interface for various logging frameworks, allowing developers to switch between them without modifying the application's logging code.

    As a logging facade, SLF4J provides a standard API for logging and delegates the actual logging tasks to underlying frameworks, such as:

    • Logback: A flexible and robust logging framework
    • java.util.logging: The default logging framework in Java
    • Log4j: A widely recognized logging framework

    info> SLF4J enables seamless switching between logging frameworks without changing your application’s logging implementation.


    Here’s a table comparing the logging levels of SLF4J and Java Logging:

    | SLF4J Level | Java logging Level | |-----------------|-------------------------------| | TRACE | FINEST | | DEBUG | FINE | | INFO | INFO | | WARN | WARNING | | ERROR | SEVERE | | FATAL | No direct equivalent | | Not used in SLF4J | CONFIG | | Not used in SLF4J | No direct equivalent |

    Summary of Differences:

    • SLF4J has TRACE and DEBUG, which aligns with java.util.logging's FINEST and FINE levels, respectively.
    • java.util.logging has a CONFIG level, which does not have an equivalent in SLF4J.
    • java.util.logging's SEVERE level corresponds directly to SLF4J's ERROR level.
    • SLF4J includes FATAL, though this is not standard in java.util.logging.

    --- The code below is a simple example demonstrating how to use the SLF4J API in Java:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SLF4JExample {
        private static final Logger logger = LoggerFactory.getLogger(SLF4JExample.class);
    
        public static void main(String[] args) {
            // Log at different levels
            logger.debug("This is a debug message");
            logger.info("This is an info message");
            logger.warn("This is a warning message");
            logger.error("This is an error message");
    
            // Log with parameters
            String user = "John";
            logger.info("User {} has logged in", user);
        }
    }
    ``` In this step, you learned about SLF4J and how it offers a unified interface for various logging frameworks, enabling you to switch between them without modifying your application's logging code. This flexibility helps maintain a clean and adaptable logging strategy.
  8. Challenge

    Conclusion and Next Steps

    In this lab, you’ve gained a foundational understanding of Java Logging API, covering essential topics like logging levels, configuration, and best practices for designing an effective logging strategy. You’ve explored how to implement different logging levels, configure logging behavior, and follow best practices for scalable, secure, and efficient logging.

    Next Steps:

    1. Customizing Logs : You can try customizing logs by changing the format of SimpleFormatter. Refer java docs for more details.
    2. XML Formatter: Replace the SimpleFormatter with XMLFormatter and see how logs are being printed.
    3. Advanced Logging Techniques: Dive deeper into advanced logging configurations, such as integrating third-party logging frameworks like Logback or SLF4J.
    4. Log Monitoring and Analysis: Learn about log aggregation and real-time monitoring with tools like ELK Stack or cloud-based logging platforms.
    5. Optimizing Logs: Focus on optimizing log retention policies and ensuring compliance with security and privacy standards by masking sensitive data.
    6. Hands-On Projects: Apply your learning by implementing logging in real-world projects, such as developing logging strategies for microservices or enterprise-level applications.

    By continuing to explore these areas, you can enhance your ability to effectively monitor and debug applications, providing valuable insights into system performance and user behavior.


    Related Courses in Pluralsight's Library

    If you'd like to continue building your Java skills or explore related topics, check out these courses available on Pluralsight:

    Pluralsight Java Path

Amar Sonwani is a software architect with more than twelve years of experience. He has worked extensively in the financial industry and has expertise in building scalable applications.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.