Vibe monitoring with Last9 MCP: Ask your agent to fix production issues! Setup →
Last9 Last9

Apr 14th, ‘25 / 18 min read

Troubleshooting LoggerFactory Logging Issues

Running into LoggerFactory.getLogger errors in Java? Here’s how to fix common logging issues and get your logs flowing again—fast.

Troubleshooting LoggerFactory Logging Issues

If you've ever run into issues with a Java application not logging properly, you're not alone. The LoggerFactory.getLogger error is a common blocker that can bring development to a halt. This guide covers the root causes of this issue and offers practical solutions to get your logging back on track.

What is LoggerFactory.getLogger?

LoggerFactory.getLogger is a static method in SLF4J (Simple Logging Facade for Java) that returns a logger instance for a specific class. It's essentially your entry point to the logging world in Java applications.

This method serves as the cornerstone of the SLF4J logging framework, providing a standardized way to obtain logger instances regardless of which logging implementation (Logback, Log4j2, JUL, etc.) is used under the hood. When you call LoggerFactory.getLogger(), you're interacting with SLF4J's abstraction layer, not directly with the underlying logging implementation.

The typical usage looks like this:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {
    private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
    
    public void doSomething() {
        logger.info("Method execution started");
        // Method logic here
        logger.debug("Operation completed successfully");
    }
}

This code demonstrates the standard logger initialization pattern. First, we import the necessary SLF4J classes. Then, we create a private static final Logger instance by calling LoggerFactory.getLogger() with the current class as a parameter.

This approach allows the logging framework to automatically track which class generated each log message. Inside methods, we use different log levels (info, debug) to provide appropriate context about the application's execution flow.

This pattern is the foundation of logging in countless Java applications, making it a critical component to understand for any DevOps engineer.

💡
If you're choosing between logging frameworks, this SLF4J vs Log4j guide breaks down the key differences to help you decide.

Common Causes of LoggerFactory.getLogger Errors

When you encounter the "cannot be resolved to a type" error with LoggerFactory.getLogger, several issues might be at play:

1. Missing Dependencies

The most frequent cause is simply missing the right dependencies in your project. SLF4J requires specific JARs to function properly. At minimum, you need the SLF4J API JAR (slf4j-api), but you'll also need an implementation JAR like Logback (logback-classic) or a binding to another logging framework.

The error message "LoggerFactory cannot be resolved to a type" specifically indicates that your project cannot find the SLF4J API classes at compile time. This is different from runtime binding errors (like "No SLF4J providers were found"), which occur when the API is present but no implementation is available.

2. Conflicting Versions

Multiple versions of logging libraries can create conflicts that prevent proper resolution. This is especially common in larger projects with many dependencies, where different libraries might pull in different versions of SLF4J or its implementations. Modern build tools try to resolve these conflicts automatically, but sometimes manual intervention is needed.

3. Incorrect Import Statements

Sometimes it's as simple as using the wrong import statements in your code. For example, importing java.util.logging.Logger instead of org.slf4j.Logger, or forgetting to import org.slf4j.LoggerFactory altogether. The IDE autocomplete might sometimes select the wrong import if multiple logging libraries are available.

4. Build Tool Configuration Issues

Maven or Gradle might not be pulling in the dependencies correctly due to configuration problems. This could be due to misconfigured repositories, dependency scopes that are too restrictive (like 'test' instead of 'implementation'), or exclusions that accidentally remove needed dependencies.

5. IDE-Specific Problems

Sometimes the issue exists only in your IDE but not during actual builds. IDEs maintain their understanding of the project structure and dependencies, which can sometimes get out of sync with the actual build configuration. This is why "clean and rebuild" or "refresh dependencies" often help resolve these issues.

💡
If you're comparing logging frameworks, this Log4j vs Log4j2 guide highlights the key differences to consider for your project.

How to Fix LoggerFactory.getLogger Resolution Issues

Let's tackle each potential cause with clear, actionable solutions. These techniques have been tested across hundreds of Java projects and will help you systematically resolve SLF4J configuration issues.

Adding the Correct Dependencies

The first step is ensuring you have the right dependencies in your project.

For Maven Projects:

Add these dependencies to your pom.xml:

<dependencies>
    <!-- SLF4J API -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.36</version>
    </dependency>
    
    <!-- SLF4J Implementation (choose one) -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.11</version>
    </dependency>
</dependencies>

This Maven dependency configuration does two essential things: First, it adds the SLF4J API (slf4j-api) which provides the interfaces including LoggerFactory and Logger. Second, it adds Logback Classic, which is the actual implementation that makes logging work.

The version numbers are important - 1.7.36 for SLF4J and 1.2.11 for Logback are stable versions that work well together. Without these dependencies, Java won't be able to resolve the LoggerFactory class at compile time.

For Gradle Projects:

Add these to your build.gradle:

dependencies {
    implementation 'org.slf4j:slf4j-api:1.7.36'
    implementation 'ch.qos.logback:logback-classic:1.2.11'
}

This Gradle dependency block serves the same purpose as the Maven example above but uses Gradle's more concise syntax. The implementation configuration makes these dependencies available during compilation and runtime.

It adds both the SLF4J API and the Logback implementation to your project. With these dependencies in place, your code should be able to resolve the LoggerFactory class and create loggers successfully.

💡
Fix Java production log issues instantly—right from your IDE, with AI and Last9 MCP.

Resolving Dependency Conflicts

If adding the dependencies doesn't solve the issue, you might have conflicting versions. Here's how to check and fix them:

For Maven:

Generate a dependency tree to spot conflicts:

mvn dependency:tree

Look for multiple versions of SLF4J or logging implementations. You can exclude problematic dependencies using:

<dependency>
    <groupId>some.group</groupId>
    <artifactId>some-artifact</artifactId>
    <version>1.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

This Maven configuration demonstrates how to exclude a conflicting logging dependency. In this example, we're excluding the slf4j-log4j12 adapter that might come bundled with a third-party library (represented here as "some.group:some-artifact"). The exclusions element allows you to prevent specific transitive dependencies from being pulled into your project.

This technique is crucial for resolving "multiple bindings" errors that occur when more than one SLF4J implementation is present on the classpath.

For Gradle:

Check dependencies with:

gradle dependencies

Force a specific version if needed:

configurations.all {
    resolutionStrategy {
        force 'org.slf4j:slf4j-api:1.7.36'
    }
}

This Gradle configuration enforces a specific version of the SLF4J API across your entire project. The resolutionStrategy with the force directive ensures that version 1.7.36 of slf4j-api will be used regardless of what versions might be requested by various dependencies.

This is a powerful way to resolve version conflicts without having to track down and exclude every problematic dependency. It forces Gradle to use exactly the version you specify, overriding any other version that might be declared elsewhere.

💡
To improve how you handle logs, check out this guide to log shippers for tips on collecting and forwarding logs efficiently.

Fixing Import Statements

Make sure you're using the correct imports:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Not:

import java.util.logging.Logger; // Wrong import for SLF4J

Resolving IDE-Specific Issues

If the error only appears in your IDE:

  1. Refresh dependencies: Most IDEs have the option to refresh or reload project dependencies
  2. Clear caches: IDEs like IntelliJ IDEA have "File > Invalidate Caches / Restart"
  3. Rebuild project: Try a clean rebuild of your project
  4. Check project settings: Verify that your IDE project settings match your build tool configuration

Choosing the Right SLF4J Implementation

SLF4J is just a facade - you need an actual implementation. Here's a comparison of popular options:

Implementation Pros Cons Best For
Logback Fast, flexible configuration, native SLF4J implementation More complex setup for advanced features Production environments, complex logging requirements
Log4j2 + SLF4J Bridge High performance, async logging Requires bridge adapter High-throughput applications
SLF4J Simple Minimal setup, no configuration files Limited features, console-only output Development, testing, simple applications
Last9 Excellent observability integration, modern features Learning curve for new users Production systems that need advanced monitoring

Detailed Implementation Comparison

Logback

Logback was created by the same developer who created Log4j and SLF4J, making it the native and most seamlessly integrated implementation. It offers automatic reloading of configuration files, conditional processing in configurations, and a powerful filter mechanism. Its status page shows its internal state, which is invaluable for debugging logging issues. Logback's automatic compression and archiving of log files make it suitable for long-running production applications.

Last9

Last9 offers an integrated observability solution with strong SLF4J integration. It excels at collecting, analyzing, and visualizing log data in real time. It provides automated anomaly detection and sophisticated alerting based on log patterns. The correlation between logs, metrics, and traces makes Last9 particularly valuable for microservice architectures. Its built-in dashboard templates for common applications reduce setup time for new monitoring environments.

Log4j2

Apache Log4j2 represents a complete rewrite of Log4j with significant performance improvements. It provides asynchronous loggers based on the LMAX Disruptor, which can be 10x faster than other logging frameworks. Log4j2's garbage-free logging is perfect for latency-sensitive applications. Although it requires a bridge to work with SLF4J, it offers a "lambda API" for extremely efficient lazy logging and supports a plugin architecture for custom appenders and layouts.

SLF4J Simple

This bare-bones implementation is included with the SLF4J distribution and requires no additional dependencies. It outputs all logs to System.err with minimal formatting options. You can control its behavior through system properties, but it lacks file output capabilities, log rotation, pattern layouts, and most advanced features. It's ideal for quick prototypes or simple applications where sophisticated logging isn't needed.

Setting Up LoggerFactory in Spring Boot

Spring Boot makes using LoggerFactory.getLogger especially easy with its auto-configuration:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    private static final Logger logger = LoggerFactory.getLogger(MyController.class);
    
    // Controller methods using logger
}

This code shows how to integrate SLF4J logging into a Spring Boot controller. The @RestController annotation marks this class as a REST endpoint controller in Spring. We create a standard SLF4J logger instance using LoggerFactory.getLogger(), passing in the controller class itself.

The beauty of Spring Boot is that it comes with SLF4J and Logback pre-configured, so this code will work without any additional dependencies in a standard Spring Boot application. This makes it incredibly easy to add proper logging to your Spring microservices.

Spring Boot includes SLF4J and Logback by default, so no additional dependencies are needed unless you want to switch implementations.

💡
If you're troubleshooting tricky issues, understanding trace-level logging can help you see what’s really going on under the hood.

Advanced LoggerFactory Configuration

Once you've fixed the "cannot be resolved" error, you might want to customize your logging setup.

Creating a Logback Configuration File

Create a logback.xml file in your src/main/resources directory:

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>
    
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

This Logback XML configuration sets up two different logging destinations (appenders):

  1. A CONSOLE appender that outputs logs to the standard console with a specific format showing the time (HH:mm:ss.SSS), thread name, log level, logger name, and the actual message.
  2. A FILE appender that writes logs to a file at "logs/application.log" with a slightly different pattern that includes the full date, level, thread, a shortened logger name, source file, line number, and message.

The <root> element sets the base log level to "info" (meaning INFO, WARN, and ERROR messages will be logged, but DEBUG and TRACE will be filtered out) and attach both appenders to it. This configuration enables logging to both the console and a file simultaneously, giving you both immediate visibility and persistent log storage.

Using MDC for Enhanced Logging

SLF4J offers Mapped Diagnostic Context (MDC) for adding context to logs:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserService.class);
    
    public void processRequest(String userId, String requestId) {
        MDC.put("userId", userId);
        MDC.put("requestId", requestId);
        
        try {
            logger.info("Processing user request");
            // Business logic
        } finally {
            MDC.clear();
        }
    }
}

This code demonstrates how to use SLF4J's Mapped Diagnostic Context (MDC) to add contextual information to logs. The MDC is like a thread-local map that attaches additional metadata to all log messages emitted within its scope:

  1. First, we add two pieces of context using MDC.put() - the user ID and request ID
  2. These values will automatically be included in every log message within this thread
  3. The try-finally block ensures that we always clear the MDC even if an exception occurs
  4. MDC.clear() removes all MDC values, preventing context leakage between different requests

This technique is extremely valuable in distributed systems because it lets you trace a request's journey through multiple services by including the same request ID in logs across all services.

Then update your logback pattern:

<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [userId=%X{userId}, requestId=%X{requestId}] - %msg%n</pattern>

This Logback pattern configuration shows how to incorporate MDC values into your log format. The key part is %X{userId} and %X{requestId}, which retrieve values from the MDC map by their keys. When a log is generated:

  1. %d{HH:mm:ss.SSS} adds a timestamp in hours, minutes, seconds, and milliseconds
  2. [%thread] adds the thread name in square brackets
  3. %-5level adds the log level, left-justified with 5 characters
  4. %logger{36} adds the logger name, shortened to 36 characters
  5. [userId=%X{userId}, requestId=%X{requestId}] adds MDC values in a readable format
  6. %msg%n adds the actual log message followed by a newline

With this pattern, every log message will automatically include the user ID and request ID that was set in the MDC, making it much easier to filter and correlate logs for specific users or requests.

💡
For tips on making sense of messy logs, this log file analysis guide walks through practical ways to extract useful insights.

Integrating LoggerFactory with Monitoring Tools

To get the most from your logging setup, connect it with observability tools.

Last9 Integration

Last9 offers excellent integration with SLF4J. To set it up:

  1. Add the Last9 appender dependency to your project
  2. Configure the appender in your logback.xml file
  3. Set your API key and configuration options

Here's a sample Logback configuration for Last9 integration:

<appender name="LAST9" class="io.last9.logging.logback.Last9Appender">
    <apiKey>your-last9-api-key</apiKey>
    <source>your-application-name</source>
    <environment>production</environment>
    <batchSize>100</batchSize>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

<root level="info">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="LAST9" />
</root>

This configuration creates a Last9 appender that sends logs to the Last9 platform with your API key. The source and environment tags help organize logs in the Last9 dashboard. The batchSize the parameter controls how many log events are batched together before sending, optimizing network usage. The pattern encoder formats the logs before they're sent to Last9.

With this integration, you'll get:

  • Centralized log storage and management
  • Real-time log analysis and visualization
  • Automated anomaly detection
  • Advanced search capabilities
  • Integration with metrics and distributed tracing
  • Customizable alerting based on log patterns
Tool Integration Complexity Features Best Suited For
Last9 Easy Real-time monitoring, alerts, dashboards, anomaly detection Teams needing integrated observability and dealing with high-cardinality
ELK Stack Medium Full-text search, visualization, analytics, open-source Companies wanting full control over logging infrastructure
Datadog Medium APM, infrastructure monitoring, log correlation Organizations using microservices architectures
Splunk Complex Enterprise-grade analysis, security features, ML-powered insights Large enterprises with security and compliance needs
New Relic Medium Performance monitoring, error tracking, distributed tracing Teams focused on application performance
Grafana Loki Medium Horizontally scalable, cost-efficient log aggregation Kubernetes environments and cloud-native applications
Google Cloud Logging Easy Integration with GCP services, log-based metrics Applications running on Google Cloud Platform
AWS CloudWatch Logs Easy Integration with AWS services, real-time monitoring Applications running on AWS

Integration Patterns

When connecting SLF4J with these monitoring tools, you typically have three integration patterns:

  1. Direct Appender Integration: Tools like Last9 provide custom Logback/Log4j appenders that send logs directly to their service. This is the simplest approach and typically requires just adding a dependency and a few configuration lines.
  2. Log Shipper Pattern: For tools like ELK Stack, you often configure your logging framework to write to files, then use a separate agent (like Filebeat or Fluentd) to ship those logs to the central system. This adds complexity but provides better reliability and failure handling.
  3. API Integration: Some systems expose APIs that you can call directly from custom appenders. This gives you maximum flexibility but requires more development effort.

The right choice depends on your operational requirements, infrastructure constraints, and team expertise.

💡
This intro to log data explains what logs are, why they matter, and how to use them effectively in your observability workflow.

Best Practices for Using LoggerFactory.getLogger

Follow these guidelines to make the most of your logging setup:

Choose appropriate log levels:

Proper log levels are crucial for managing log volume and focus. ERROR should be used sparingly for genuine problems that require human intervention.

WARN indicates potential issues that don't prevent operation but might need attention.

INFO provides a high-level narrative of application behavior. DEBUG offers implementation details for troubleshooting. TRACE exposes the minutest details of execution flow.

    • ERROR: For errors that need immediate attention
    • WARN: For potentially harmful situations
    • INFO: For general information about application progress
    • DEBUG: For detailed information useful during development
    • TRACE: For very detailed diagnostic information

Add context to logs:

Context is what transforms individual log messages into a coherent story. By adding contextual information like user IDs, session IDs, or request IDs to every log message, you make it possible to trace the entire lifecycle of a transaction across multiple components. The MDC approach is particularly powerful because it automatically attaches this context to all logs within the current thread without cluttering your method signatures with extra parameters.

    • Use MDC for request-scoped data
    • Include relevant identifiers (user IDs, request IDs, etc.)
    • Use conditional logging for verbose operations

Avoid excessive logging:

if (logger.isDebugEnabled()) {
    logger.debug("Expensive operation result: {}", calculateExpensiveValue());
}

This code demonstrates how to avoid performance penalties when logging expensive operations. The isDebugEnabled() check prevents executing calculateExpensiveValue() when debug logs are disabled.

While SLF4J's parameterized logging is already efficient for simple variables, this pattern becomes important when the values to be logged require significant computation or resource usage. It's particularly valuable for logging large collections, serializing objects, or performing database queries just for logging purposes.

Structure log messages for parsing:

// Bad
logger.info("User logged in: " + username + ", time: " + loginTime);

// Good
logger.info("User login event username={}, loginTime={}", username, loginTime);

The second approach offers multiple advantages. First, it's more efficient because string concatenation is only performed if the log level is enabled. Second, it creates a consistent format that's easier to parse with log analysis tools.

The key-value format key={} creates structured logs that can be automatically processed to extract fields. This approach also prevents errors when logging objects that might be null.

Use class-specific loggers: Always pass the current class to getLogger() for better log filtering:

private static final Logger logger = LoggerFactory.getLogger(ThisClass.class);

This code creates a logger instance specific to the current class. Using the class as a parameter instead of a string literal (like "com.myapp.ThisClass") ensures the logger name stays in sync if you refactor the class name or package.

It also enables more accurate log filtering and hierarchical configurations based on package structure. The static final declaration makes the logger efficiently reusable across all instance methods.

💡
And if you're setting up logging for long-term sanity, these logging best practices are worth keeping in your toolkit.

Performance Considerations with LoggerFactory

Logging is essential, but if you're not careful, it can slow your application down. Here’s how to keep things fast and efficient.

1. Use the Right Log Levels

Verbose logging like DEBUG or TRACE is useful—but not in production. These levels can generate 10–100x more log events than INFO, impacting:

  • CPU and memory usage
  • Storage costs
  • Log shipping and processing

Tip: Use different log levels for different packages. Keep most at INFO, and turn on DEBUG only where you’re troubleshooting.

2. Watch Your Disk I/O

Logging into a single, ever-growing file creates trouble:

  • Slower write performance
  • Higher file system cache usage
  • Risk of running out of disk space

Solution: Use rolling file strategies. You can roll logs:

  • By time – daily/hourly
  • By size – e.g., 100MB per file
  • Both – time + size

Most tools also support compression and auto-deletion of old logs.

3. Buffer and Batch Logs

In high-throughput environments, writing logs line by line is inefficient.

Instead:

  • Use buffering and batching to reduce network and CPU overhead
  • Tune buffer size and set up time-based flush intervals
  • Many Logback appenders support batching out of the box

4. Sample High-Frequency Events

Not every event needs to be logged. Especially routine ones that occur thousands of times a second.

Use sampling:

  • Log only a small percentage (e.g., 1%) of routine events
  • Always log 100% of errors and unusual behavior

This keeps your logs lean while still offering a good overview of system behavior.

5. Use Async Logging

Asynchronous logging can massively boost performance under load. It decouples app threads from I/O.

Here’s an example using Logback’s AsyncAppender:

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILE" />
    <queueSize>512</queueSize>
    <discardingThreshold>0</discardingThreshold>
</appender>
  • queueSize sets the buffer size
  • discardingThreshold defines what happens when the queue is full

Result: Up to 5–10x better throughput during peak loads.

6. Use Parameterized Logging

Avoid this:

logger.debug("Processing item " + itemId + " with value " + value);

Why? Even if DEBUG is off, the string gets built.

Do this instead:

logger.debug("Processing item {} with value {}", itemId, value);

SLF4J handles the string substitution only if the log level is enabled. That saves CPU and reduces memory churn—especially important for high-volume apps.

Conclusion

Proper logging isn't just about troubleshooting - it's a cornerstone of observability that helps you understand system behavior, track user interactions, monitor performance, and detect security incidents.

💡
And if you’d rather talk it through, hop into our Discord. There’s a dedicated channel where developers share use cases, questions, and solutions.

FAQs

How do I fix "LoggerFactory.getLogger cannot be resolved to a type"?

The most common fix is adding the SLF4J API dependency to your project. For Maven:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>

This Maven dependency declaration adds the core SLF4J API to your project. This is the minimal dependency required to use LoggerFactory.getLogger() in your code. It includes only the interfaces and factory methods, not the actual logging implementation.

The version 1.7.36 is a stable release that's widely used. Adding just this dependency will allow your code to compile but will output warnings during runtime if no implementation is provided, as SLF4J requires an actual logging framework to perform the logging operations.

What's the difference between SLF4J and Logback?

SLF4J is a facade or abstraction that allows you to plug in different logging implementations. Logback is one such implementation. SLF4J provides the API (LoggerFactory.getLogger), while Logback provides the actual logging functionality.

Can I use LoggerFactory.getLogger with Log4j2?

Yes, but you need the SLF4J-to-Log4j2 bridge:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.2</version>
</dependency>

This Maven dependency adds the Log4j2 bridge for SLF4J. It serves as an adapter that allows SLF4J API calls (like LoggerFactory.getLogger()) to be routed to Log4j2 as the actual logging implementation.

The log4j-slf4j-impl artifact contains the necessary glue code to connect these two frameworks. Version 2.17.2 is particularly important as it contains security fixes for the Log4Shell vulnerability discovered in late 2021.

By adding this dependency, you're telling your application to use Log4j2 as the backend for all SLF4J logging calls.

How do I set different log levels for different packages?

In your logback.xml:

<logger name="com.myapp.service" level="DEBUG" />
<logger name="com.myapp.repository" level="INFO" />
<root level="WARN">
    <appender-ref ref="CONSOLE" />
</root>

This Logback configuration demonstrates hierarchical log level configuration, a powerful feature for fine-tuning your logging output:

  1. <logger name="com.myapp.service" level="DEBUG" /> sets the DEBUG level for all loggers in the "com.myapp.service" package. This means DEBUG, INFO, WARN, and ERROR messages from service classes will all be logged.
  2. <logger name="com.myapp.repository" level="INFO" /> sets the INFO level for all loggers in the "com.myapp.repository" package. This allows only INFO, WARN, and ERROR messages from repository classes, while filtering out DEBUG messages.
  3. <root level="WARN"> sets the default logging level for everything else to WARN. Any logger not explicitly configured will use this level, meaning only WARN and ERROR messages will be logged.

This configuration lets you see more detailed logs from your service layer (DEBUG level), moderate detail from your repository layer (INFO level), and only warnings and errors from everything else.

This pattern is extremely useful for troubleshooting specific parts of your application without being overwhelmed by debug messages from the entire codebase.

Why am I seeing multiple logging frameworks in my application?

Many Java libraries include their logging dependencies. Use tools mvn dependency:tree to identify and exclude conflicting implementations.

How can I log in to multiple destinations?

Configure multiple appenders in your logback.xml and reference them from your loggers:

<root level="info">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="FILE" />
    <appender-ref ref="SYSLOG" />
</root>

This Logback configuration sets up multi-destination logging by connecting multiple appenders to the root logger:

  1. <root level="info"> establishes INFO as the default log level for all loggers in the application, meaning INFO, WARN, and ERROR logs will be processed.
  2. <appender-ref ref="CONSOLE" /> attaches the CONSOLE appender, directing logs to standard output (typically your terminal or IDE console).
  3. <appender-ref ref="FILE" /> attaches the FILE appender, sending the same logs to a file (defined elsewhere in the configuration).
  4. <appender-ref ref="SYSLOG" /> attaches the SYSLOG appender, which forwards logs to a syslog server (often used in enterprise environments for centralized logging).

With this configuration, every log message at the INFO level or higher will simultaneously go to three different destinations without any additional code changes. This provides both immediate visibility (console), persistent storage (file), and centralized monitoring (syslog) for your application's logs.

The beauty of this approach is that you can add or remove destinations simply by changing the configuration without touching your application code.

Contents


Newsletter

Stay updated on the latest from Last9.

Authors
Preeti Dewani

Preeti Dewani

Technical Product Manager at Last9

X