Problem Statement: Logback is printing in console properly but not in log.txt file. There are many solutions given in other pages but apparently none worked. Could someone help me in this regard?
Java:-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Log {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger("Example App");
logger.info("'sup? I'm your info logger");
logger.debug("hey HEY hey! I'm your debug logger");
}
}
Config:- logback-fileAppender.xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${project.basedir}/Log.txt</file>
<append>true</append>
<!-- set immediateFlush to false for much higher logging throughput -->
<immediateFlush>true</immediateFlush>
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
Expected:- The logs should be printed in log.txt
Actual:- The logs is not printed in log.txt
Note: I am using my customized directory structure in maven not the default provided by maven "src/main/resources".
Related
I wrote a simple program in which I am using Logback. My intention was to use ASYNS which internally will use STDOUT.
Here is the Java code listing:
package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogBackMainApp {
private static final Logger LOGGER =
LoggerFactory.getLogger(LogBackMainApp.class);
public static void main(String[] args) throws InterruptedException {
LOGGER.info("Hello world");
LOGGER.info("Hello world again");
Thread.sleep(5000);
}
}
The below is the configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" >
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- %d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger{0}:%L
If you required class name ,enable %logger{0}:%L -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level - %msg
%n</pattern>
</encoder>
</appender>
<appender name="ASYNC-STDOUT" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1</queueSize>
<discardingThreshold>20</discardingThreshold>
<neverBlock>true</neverBlock>
<appender-ref ref="STDOUT" />
</appender>
<root level="INFO">
<appender-ref ref="ASYNC-STDOUT" />
</root>
I am defining root logger which would cater to my com.example package, and it refers to ASYNC-STDOUT, which internally uses ch.qos.logback.core.ConsoleAppender.
As per my current understanding, it should be able to log to console. However, nothing is coming. Is there something wrong in my code or configuration OR do i miss to understand the concept altogether.
If you use maven have a look: Dependency management for SLF4J and Logback. Maybe you're missing a required dependency. Sl4j is only an abstraction for you're real logger implementation which has to be added as dependency.
I am using slf4j and logback for logging in my java web application. I need the info logs from a specific class (MyClass in the example below) to be sent in an email. I configured an email appender in logback. The rest of it can go wherever the root logger is set to. But the email doesn't go out with my current set up. See below...
Set Up:
Here's the relevant information about jar versions and other setup for this:
jars in the classpath:
activation-1.1.jar
jcl-over-slf4j-1.7.25.jar
logback-classic-1.2.3.jar
logback-core-1.2.3.jar
logback-ext-spring-0.1.4.jar
logstash-logback-encoder-4.11.jar
mail-1.4.jar
slf4j-api-1.7.25.jar
logback.xml from classpath:
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d [%thread] %-5level %logger{5}:%L - %msg%n</pattern>
</encoder>
</appender>
<appender name="email" class="ch.qos.logback.classic.net.SMTPAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<smtpHost>smtp.server</smtpHost>
<to>code4kix#email.com</to>
<from>do-not-reply#email.com</from>
<subject>code4kix - ${HOSTNAME}: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d [%thread] %-5level %logger{5}:%L - %msg%n</pattern>
</layout>
<!-- <STARTTLS>true</STARTTLS> -->
<!-- <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker"> -->
<!-- <bufferSize>1</bufferSize> -->
<!-- </cyclicBufferTracker> -->
<!-- <asynchronousSending>false</asynchronousSending> -->
</appender>
<root level="error">
<appender-ref ref="console" />
</root>
<logger name="mypackage.MyClass" level="info" additivity="true">
<appender-ref ref="email"/>
</logger>
The Issue:
The email seems to go out fine if I have logger.error statements in MyClass.java, but if they have just logger.info, the email doesn't go out... despite configuring the threshold to info!
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass
{
private static Logger logger = LoggerFactory.getLogger(MyClass.class);
public void myMethod()
{
logger.error("using this sends the email out");
logger.info("using this doesn't");
}
}
I do get this in the console log, but the email never goes out. What could possibly be wrong?
SystemOut O 13:18:00,012 |-INFO in ch.qos.logback.classic.net.SMTPAppender[email] - SMTPAppender [email] is tracking [1] buffers
From my recent reading of the logback it sounds as though only under ERROR will an email be sent out. Chapter 4: Appenders
Thanks to Elijah for pointing me in the right direction. As mentioned in the documentation in SMTP Appender:
by default, the email transmission is triggered by a logging event of
level ERROR
There are multiple ways to solve this. The simplest way for me was to implement my own EventEvaluator like so, and use it in the smtp appender config (shown further below). Alternatively, you can explore using Markers to solve this issue.
public class OnInfoEvaluator extends EventEvaluatorBase<ILoggingEvent> {
#Override
public boolean evaluate(ILoggingEvent loggingEvent) throws NullPointerException, EvaluationException {
if(loggingEvent.getLevel().toInt() >= Level.INFO_INT)
{
return true;
}
else
{
return false;
}
}
}
In the config:
<appender name="email" class="ch.qos.logback.classic.net.SMTPAppender">
<evaluator class="mypackage.OnInfoEvaluator" />
...
</appender>
my problem is : My application maintains three buildings, and each building has a different process.
So, using logback, I want to create a log which has a specification :
each building will have a specific folder, and inside that specific folder of each building, there will be many log files, with each log file indicates a process.
My logback.xml right now is :
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="logAppender" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<key>processName</key>
<defaultValue>unknown</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${processName}"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/${distributor}/${processName}.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</pattern>
</layout>
<rollingPolicy
class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>logs/${distributor}/${processName}.%i.log</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
<!-- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5KB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> -->
</rollingPolicy>
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
</appender>
</sift>
</appender>
<logger name="processLog" level="debug" additivity="false">
<appender-ref ref="logAppender" />
<appender-ref ref="stdout" />
</logger>
<root level="debug">
<appender-ref ref="stdout" />
<appender-ref ref="logAppender" />
</root>
</configuration>
And my java servlet code is :
public class DistributorServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger processLog = LoggerFactory.getLogger("processLog");
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String office = req.getParameter("office");
MDC.put("distributor", office);
String process = req.getParameter("process");
MDC.put("process", process);
processLog.debug("Processing");
}
}
However, a log file is not generated.
Can anyone help me?
Thank you very much
1. Make the below change
private static Logger processLog = LoggerFactory.getLogger("processLog");
to
private static Logger processLog = LoggerFactory.getLogger(DistributorServlet .class);
2. Add additional discriminator for distributor
From the logback.xml it appears that only one discriminator has been added. Did you try adding another one for distributor
3. Do not forget
To add MDC.remove("keyName"); after its usage.
4. In case if you observe issue with multiple MDC keys
I faced an issue with the MDC.put in trying to add multiple keys into it. (I wondered why no putAll has been defined)
Although the underlying implementation is that of a HashMap<Key k, Value v> that should allow adding multiple keys, I was only able to see that the last key you put into MDC would be applied to logback.xml
While for the other keys I observed _IS_UNDEFINED value that gets appended instead.
Of course then again you can refer to the other various links and although this may not be a best idea, here is what I have done in my Java code,
System.setProperty("distributor", req.getParameter("office"));
System.setProperty("process", req.getParameter("process"));
Modify the logback.xml by removing discriminator. Well, alternatively you can remove one of the above properties and have the MDC.put for that property.
However please do refer to the links System.setProperty is safe in java?
Alternatively I suggest https://stackoverflow.com/a/32615172/3838328
I use logback in the following case
package ninja.template;
public class TemplateEngineManagerImpl implements TemplateEngineManager {
private final Logger logger = LoggerFactory.getLogger(TemplateEngineManagerImpl.class);
...
logger.info("Registered response template engines");
...
and I want to hide all the INFO output of this TemplateEngineManagerImpl class (or all the output - the class only logs at INFO level) but this class only.
Unfortunately, the following configuration doesn't work as I can still see "Registered response template engines" in my console output.
<configuration>
<appender name="STDOUT_TERSE" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern> | %msg%n</pattern>
</encoder>
</appender>
<logger name="ninja.template.TemplateEngineManagerImpl" level="OFF"/>
<root level="info">
<appender-ref ref="STDOUT_TERSE" />
</root>
</configuration>
note I tried also the following without results
<logger name="ninja.template.TemplateEngineManagerImpl" level="WARN"/>
and
<logger name="ninja.template" level="WARN"/>
and
<logger name="TemplateEngineManagerImpl" level="WARN"/>
The provided logback configuration works
<logger name="ninja.bodyparser.BodyParserEngineManagerImpl" level="WARN" additive="false"/>
The error I had that the string was logged in two different places.
So by displaying the full logger name with the following configuration:
<appender name="STDOUT_TERSE" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern> | %logger | %msg%n</pattern>
</encoder>
I was able to copy and paste the string that should be used as the logger name!
i use slf4j+logback
Here is logback.xml with 3 appenders (1 - console, 2 different files)
`
<configuration>
<property name="LOG_HOME" value="D:/logs" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- <file>D:/logs/all/all_log.txt</file>-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${LOG_HOME}/all/all_log.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="CONNECT_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--<file>D:/logs/connect/connect_log.txt</file>-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${LOG_HOME}/connect/connect_log.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<!--<logger name="connect" level="info" additivity="false">
<appender-ref ref="CONNECT_FILE"/>
</logger>-->
<logger name = "com" level="info">
<appender-ref ref="FILE"/>
</logger>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
`
and simple class:
package com.gitHub.xMIFx.Servlets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by bukatinvv on 25.05.2015.
*/
#WebServlet("/main.do")
public class MainController extends HttpServlet{
private static final String PAGE_OK = "pages/main.jsp";
private static final Logger lOGGER = LoggerFactory.getLogger(MainController.class.getName());
private static final Logger CONNECT_FILE_lOGGER = LoggerFactory.getLogger("connect");
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp){
req.setAttribute("User","Vlad");
try {
lOGGER.info("logger: forwarding");
CONNECT_FILE_lOGGER.info("Connect-logger: forwarding");
// if(true){throw new IOException("blad");}
req.getRequestDispatcher(PAGE_OK).forward(req,resp);
} catch (ServletException e) {
lOGGER.error("Exception", e);
} catch (IOException e) {
lOGGER.error("Exception", e);
}
}
}
lOGGER & CONNECT_FILE_lOGGER write info in the same file, so they are the same loggers.
Why when we calling LoggerFactory.getLogger("connect"); we get logger with name "com", even when logger with name "connect" is not commented.
I try this, but had the same situation.
logs from file all_log.2015-05-28.log:
4968 [http-nio-8081-exec-5] INFO c.g.xMIFx.Servlets.MainController - logger: forwarding
4968 [http-nio-8081-exec-5] INFO connect - Connect-logger: forwarding
Interestingly, logback will create a logger even if you have no logger declared with the name you pass to LoggerFactory. Therefore:
When 'connect' was commented out CONNECT_FILE_lOGGER was a ROOT child logger which also logged to the console.
By uncommenting 'connect' you created a logger which appended to the desired file. As the additivity flag is false, any message logged to it is not propagated to its parents.
Sorry, I don't know what was that. But when I added additivity="false" to the logger with name "com" it works. Then I returned it back and uncommented "connect" - now it all works fine.