Log4j writes to application log file instead of own log file - java

Log4j writes to application log file instead of my own log file.
I tried to find a solution without editing the log4j.properties. Do I have to edit the config file? Why the lg file is not been created.
The app runs as a tomcat web app.
import org.apache.log4j.Logger;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.SimpleLayout;
public class ArchiveJanitor extends SecureResource {
private static final Logger logger = org.apache.log4j.Logger.getRootLogger();
public ArchiveJanitor(Context context, Request request, Response response) {
super(context, request, response);
try {
SimpleLayout layout = new SimpleLayout();
FileAppender fileAppender = new FileAppender( layout, "logs/Janitor.log", false );
logger.addAppender(fileAppender);
logger.setLevel((Level) Level.ALL);
}catch (IOException e){
logger.error(e.toString());
}
}
public void doSmth(){
logger.error("error ....")
}
}

Instead of private static final Logger logger = org.apache.log4j.Logger.getRootLogger(); try to use public static final Logger logger = LogManager.getLogger(ArchiveJanitor.class);
But probably its better to config it all in .properties file

Related

How to make a log file with only one line which is overwritten every time?

I'm using log4j2 (version 2.5) in Java 8.
I need a log file with only one line. Therefore for each writing, the previous line if it exists must be overwritten by the new line.
log4j.properties:
name=testLoggerOneLine
appenders=console, logFile
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=[%-5level] %d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}
[%t] %c{1} - %msg%n
appender.logFile.type=File
appender.logFile.name=LOGFILE
appender.logFile.fileName=C:/Users/mggl/workspace/Test/logs/Test.log
#appender.logFile.immediateFlush=true
#appender.logFile.append=false
#appender.logFile.createOnDemand=false
appender.logFile.layout.type=PatternLayout
appender.logFile.layout.pattern=%msg%n
loggers=logFile
logger.logFile.name=Test
logger.logFile.level=debug
logger.logFile.appenderRefs=logFile
logger.logFile.appenderRef.logFile.ref=LOGFILE
logger.logFile.additivity=false
rootLogger.level=debug
rootLogger.appenderRefs=stdout
rootLogger.appenderRef.stdout.ref=STDOUT
Dummy code:
package Test.loggingTest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class OneLineLog
{
public static void main( String[] args )
{
Logger logger = LogManager.getLogger("testLoggerOneLine");
logger.info("first writing");
logger.info("second writing");
logger.info("third writing");
}
}
In Test.log there must be written only the last logging info.
The option append with value false does the job for a bunch of logging information at each application start. I want to do the same for each line without restarting the application.
Any clue or suggestion is appreciated. Thanks in advance.
I solved the problem using append and immediateFlush options (set to false and true respectively) in log4j.properties and forcing the rollover on the appender associated with the logger. I used the snippet written by rgoers in this discussion:
How to rotate a log4j log manually
log4j.properties:
name=Test
appenders=console, logFile
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} - %msg%n
appender.logFile.type=RollingFile
appender.logFile.name=LOGFILE
appender.logFile.fileName=.../logs/Test.log
appender.logFile.filePattern=.../logs/%d{yyyyMMdd'T'HH:mm:ss.SSSZ}-Test.log.gz
appender.logFile.layout.type=PatternLayout
appender.logFile.layout.pattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}: %m%n
appender.logFile.policies.type=Policies
appender.logFile.policies.time.type=TimeBasedTriggeringPolicy
appender.logFile.policies.time.interval=1
appender.logFile.policies.time.modulate=true
appender.logFile.policies.size.type=SizeBasedTriggeringPolicy
appender.logFile.policies.size.size=500MB
appender.logFile.strategy.type=DefaultRolloverStrategy
appender.logFile.strategy.max=10
appender.logFile.append=false
appender.logFile.immediateFlush=true
loggers=logFile
logger.logFile.name=Test
logger.logFile.level=debug
logger.logFile.appenderRefs=logFile
logger.logFile.appenderRef.logFile.ref=LOGFILE
logger.logFile.additivity=false
rootLogger.level=debug
rootLogger.appenderRefs=stdout
rootLogger.appenderRef.stdout.ref=STDOUT
Code:
package Test.loggingTest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.config.AbstractConfiguration;
public class OneLineLog {
public static void main(String[] args) {
Logger logger = LogManager.getLogger("Test");
try {
logger.info("first writing");
LoggerContext loggerContext = (LoggerContext) LogManager.getContext();
AbstractConfiguration logConfig = (AbstractConfiguration) loggerContext.getConfiguration();
Appender logAppender = logConfig.getAppender("LOGFILE");
if (logAppender instanceof RollingFileAppender) {
RollingFileAppender rollingFileAppender = (RollingFileAppender) logAppender;
rollingFileAppender.getManager().rollover();
}
Thread.sleep(5000);
logger.info("second writing");
} catch (Exception e) {
System.out.println("Exception: " + e);
}
}
}

Loading Log4j.properties from outside of the war without spring framework [duplicate]

I want to put all my config files in a /config subfolder of my application directory. Log4j is expecting the log4j.properties file in the root folder of my application. Is there a way to tell log4j where to look for the properties file?
Yes, define log4j.configuration property
java -Dlog4j.configuration=file:/path/to/log4j.properties myApp
Note, that property value must be a URL.
For more read section 'Default Initialization Procedure' in Log4j manual.
You can use PropertyConfigurator to load your log4j.properties wherever it is located in the disk.
Example:
Logger logger = Logger.getLogger(this.getClass());
String log4JPropertyFile = "C:/this/is/my/config/path/log4j.properties";
Properties p = new Properties();
try {
p.load(new FileInputStream(log4JPropertyFile));
PropertyConfigurator.configure(p);
logger.info("Wow! I'm configured!");
} catch (IOException e) {
//DAMN! I'm not....
}
If you have an XML Log4J configuration, use DOMConfigurator instead.
Use the PropertyConfigurator: PropertyConfigurator.configure(configFileUrl);
Refer to this example taken from -
http://www.dzone.com/tutorials/java/log4j/sample-log4j-properties-file-configuration-1.html
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class HelloWorld {
static final Logger logger = Logger.getLogger(HelloWorld.class);
static final String path = "src/resources/log4j.properties";
public static void main(String[] args) {
PropertyConfigurator.configure(path);
logger.debug("Sample debug message");
logger.info("Sample info message");
logger.warn("Sample warn message");
logger.error("Sample error message");
logger.fatal("Sample fatal message");
}
}
To change the logger levels - Logger.getRootLogger().setLevel(Level.INFO);
In Eclipse you can set a VM argument to:
-Dlog4j.configuration=file:///${workspace_loc:/MyProject/log4j-full-debug.properties}
This is my class : Path is fine and properties is loaded.
package com.fiserv.dl.idp.logging;
import java.io.File;
import java.io.FileInputStream;
import java.util.MissingResourceException;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class LoggingCapsule {
private static Logger logger = Logger.getLogger(LoggingCapsule.class);
public static void info(String message) {
try {
String configDir = System.getProperty("config.path");
if (configDir == null) {
throw new MissingResourceException("System property: config.path not set", "", "");
}
Properties properties = new Properties();
properties.load(new FileInputStream(configDir + File.separator + "log4j" + ".properties"));
PropertyConfigurator.configure(properties);
} catch (Exception e) {
e.printStackTrace();
}
logger.info(message);
}
public static void error(String message){
System.out.println(message);
}
}
You must use log4j.configuration property like this:
java -Dlog4j.configuration=file:/path/to/log4j.properties myApp
If the file is under the class-path (inside ./src/main/resources/ folder), you can omit the file:// protocol:
java -Dlog4j.configuration=path/to/log4j.properties myApp

Java Logger wont log

Was able to print some stuff in the logfile by studying and modifying some sample codes but while running the package nothing is being printed to the logfile.
Main Class (Client.java)
public class Client {
static Logger LOGGER = Logger.getLogger(Client.class.getName());
public static void main(String[] args) {
Client logger = new Client();
try {
LogSetup.setup();
emsSession = logger.Initialise();
logger.getAllMEInfo();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Problems with creating the log files");
}
}
private void getAllMEInfo() {
LOGGER.setLevel(Level.INFO);
LOGGER.severe("Info Log");
LOGGER.warning("Info Log");
LOGGER.info("Info Log");
LOGGER.finest("Really not important");
// Some codes for the method
}
}
LogSetup.java
import java.io.IOException;
import java.text.ParseException;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LogSetup {
static private FileHandler fileTxt;
static private LogWriter formatterTxt;
static public void setup() throws IOException, ParseException {
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
Logger rootLogger = Logger.getLogger("");
Handler[] handlers = rootLogger.getHandlers();
if (handlers[0] instanceof ConsoleHandler) {
logger.removeHandler(handlers[0]);
}
logger.setLevel(Level.SEVERE);
fileTxt = new FileHandler(LogFile.txt");
// create a TXT formatter
formatterTxt = new LogWriter();
fileTxt.setFormatter(formatterTxt);
logger.addHandler(fileTxt);
}
}
LogWriter.java
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
class LogWriter extends Formatter {
public String format(LogRecord rec) {
System.out.println("RECORDING..............");
StringBuffer buf = new StringBuffer(1000);
buf.append(rec.getLevel());
buf.append(calcDate(rec.getMillis()));
buf.append(formatMessage(rec));
return buf.toString();
}
private String calcDate(long millisecs) {
SimpleDateFormat date_format = new SimpleDateFormat("MMM dd,yyyy HH:mm\n");
Date resultdate = new Date(millisecs);
return date_format.format(resultdate);
}
public String getHead(Handler h) {
return ("START " + new Date()) + "\n";
}
public String getTail(Handler h) {
return "END " + new Date() + "\n";
}
}
Log prints the START and END but doesn't even enter in the buff ""RECORDING.............."" so basically nothing is being logged. Any idea???
Please put include statements in your examples so others can try your code.
If you are using java.util.logging, try moving to logback. Logback logging will log properly with no configuration. If you are using java.util.logging then you'll need to find a tutorial on how to configure it, as if it's not configured it doesn't log like you would expect.
The logging framework use a configuration file, where u can set "where and what" to output, for java.util.logging the configuration file is under the folder lib of ure current jvm "/jdk1.x.x/jre/lib/logging.properties" I share my link the problem is in spanish config logging
In short words search the next line and change INFO -> ALL
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.level=ALL
In your code u only need to log message u want, ex:
public class TestLog {
private static final Logger log = Logger.getLogger(TestLog.class.getName());
public static void doLog() {
log.info("info log");
log.fine("fine log");
log.finer("finer log");
.....
log.severe("severe log");
}
}
Always try to use fine, finer or finest for ure debug message, don't use INFO because always print on default config and can slow ure application

Change location of log4j.properties

I want to put all my config files in a /config subfolder of my application directory. Log4j is expecting the log4j.properties file in the root folder of my application. Is there a way to tell log4j where to look for the properties file?
Yes, define log4j.configuration property
java -Dlog4j.configuration=file:/path/to/log4j.properties myApp
Note, that property value must be a URL.
For more read section 'Default Initialization Procedure' in Log4j manual.
You can use PropertyConfigurator to load your log4j.properties wherever it is located in the disk.
Example:
Logger logger = Logger.getLogger(this.getClass());
String log4JPropertyFile = "C:/this/is/my/config/path/log4j.properties";
Properties p = new Properties();
try {
p.load(new FileInputStream(log4JPropertyFile));
PropertyConfigurator.configure(p);
logger.info("Wow! I'm configured!");
} catch (IOException e) {
//DAMN! I'm not....
}
If you have an XML Log4J configuration, use DOMConfigurator instead.
Use the PropertyConfigurator: PropertyConfigurator.configure(configFileUrl);
Refer to this example taken from -
http://www.dzone.com/tutorials/java/log4j/sample-log4j-properties-file-configuration-1.html
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class HelloWorld {
static final Logger logger = Logger.getLogger(HelloWorld.class);
static final String path = "src/resources/log4j.properties";
public static void main(String[] args) {
PropertyConfigurator.configure(path);
logger.debug("Sample debug message");
logger.info("Sample info message");
logger.warn("Sample warn message");
logger.error("Sample error message");
logger.fatal("Sample fatal message");
}
}
To change the logger levels - Logger.getRootLogger().setLevel(Level.INFO);
In Eclipse you can set a VM argument to:
-Dlog4j.configuration=file:///${workspace_loc:/MyProject/log4j-full-debug.properties}
This is my class : Path is fine and properties is loaded.
package com.fiserv.dl.idp.logging;
import java.io.File;
import java.io.FileInputStream;
import java.util.MissingResourceException;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class LoggingCapsule {
private static Logger logger = Logger.getLogger(LoggingCapsule.class);
public static void info(String message) {
try {
String configDir = System.getProperty("config.path");
if (configDir == null) {
throw new MissingResourceException("System property: config.path not set", "", "");
}
Properties properties = new Properties();
properties.load(new FileInputStream(configDir + File.separator + "log4j" + ".properties"));
PropertyConfigurator.configure(properties);
} catch (Exception e) {
e.printStackTrace();
}
logger.info(message);
}
public static void error(String message){
System.out.println(message);
}
}
You must use log4j.configuration property like this:
java -Dlog4j.configuration=file:/path/to/log4j.properties myApp
If the file is under the class-path (inside ./src/main/resources/ folder), you can omit the file:// protocol:
java -Dlog4j.configuration=path/to/log4j.properties myApp

Redirect slf4j to string

How can I configure slf4j to redirect all logged information to a Java string?
This is sometimes useful in unit tests, e.g. to test no warnings are printed when loading a servlet, or to make sure a forbidden SQL table is never used.
A bit late, but still...
As logging configurations should be easy to replace when unit testing, you could just configure to log over stdout and then capture that prior to executing the logging subject.
Then set the logger to be silent for all but the subject under test.
#Test
public void test()
{
String log = captureStdOut(() -> {
// ... invoke method that shouldn't log
});
assertThat(log, is(emptyString()));
}
public static String captureStdOut(Runnable r)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream out = System.out;
try {
System.setOut(new PrintStream(baos, true, StandardCharsets.UTF_8.name()));
r.run();
return new String(baos.toByteArray(), StandardCharsets.UTF_8);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("End of the world, Java doesn't recognise UTF-8");
} finally {
System.setOut(out);
}
}
And if using slf4j over log4j in tests, a simple log4j.properties:
log4j.rootLogger=OFF, out
log4j.category.com.acme.YourServlet=INFO, out
log4j.appender.out=org.apache.log4j.ConsoleAppender
log4j.appender.out.layout=org.apache.log4j.PatternLayout
log4j.appender.out.layout.ConversionPattern=%-5p %c{1}:%L - %m%n
Or if you loath configuration as an external dependencies in unit tests, then programmatically configure log4j:
//...
static final String CONSOLE_APPENDER_NAME = "console.appender";
private String pattern = "%d [%p|%c|%C{1}] %m%n";
private Level threshold = Level.ALL;
private Level defaultLevel = Level.OFF;
//...
public void configure()
{
configureRootLogger();
configureConsoleAppender();
configureCustomLevels();
}
private void configureConsoleAppender()
{
ConsoleAppender console = new ConsoleAppender();
console.setName(CONSOLE_APPENDER_NAME);
console.setLayout(new PatternLayout(pattern));
console.setThreshold(threshold);
console.activateOptions();
Logger.getRootLogger().addAppender(console);
}
private void configureRootLogger()
{
Logger.getRootLogger().getLoggerRepository().resetConfiguration();
Logger.getRootLogger().setLevel(defaultLevel);
}
As I see it you have two options.
First you could implement a custom Appender (depending on which slf4j implementation you're using) which simply appends each logged statement to a StringBuffer. In this case you probably have to hold a static reference to your StringBuffer so your test classes can access it.
Second you could write your own implementation of ILoggerFactory and Logger. Again your Logger would just append all the messages to internal StringBuffers, although in this case you'd probably have multiple buffers, one for each log level. If you did it this way you'd have an easy way of retrieving the Logger instances since you'd own the factory that was distributing them.
Shouldn't make sense to redirect all the logs to watch to a separate log file? That way you have the control you want (you can delete the log file before running the test and checking if the file has been create at any moment) without losing the benefits of logging (redirecting your output to a String can cause memory leaks and is less performant)
This is a simple way to log to the console:
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.BasicConfigurator;
import ch.qos.logback.classic.LoggerContext;
private void LogToConsole() {
BasicConfigurator bc = new BasicConfigurator();
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.reset();
bc.configure(lc);
}
Not quite exactly what you're doing, but I've written a LogInterceptingTestHarness which enables assertion of specific log statements. You could similarly use it (or something like it) to assert nothing has been logged at a certain level.
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.List;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.junit.After;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import lombok.Getter;
/**
* Use this class to intercept logs for the purposes of unit testing log output.
* <p>
* On {#link Before} of the unit test, call {#link #initHarness(Class, Level)} or {#link #initHarness(Class, Level, String)} to get a new harness and hold onto reference to it in a class-level
* variable of your unit test
* <p>
* On {#link After} of the unit test, you MUST call {#link #teardown()} in order to remove the mocked {#link #appender}
*
* #author jeff.nelson
*
*/
#Getter
public class LogInterceptingTestHarness {
private final Appender appender;
private final ArgumentCaptor<LogEvent> logEventCaptor;
private final Logger itsLogger;
private LogInterceptingTestHarness(Class<?> classInterceptLogsFor, Level logLevel, String appenderName) {
logEventCaptor = ArgumentCaptor.forClass(LogEvent.class);
appender = mock(Appender.class);
doReturn("testAppender").when(appender).getName();
doReturn(true).when(appender).isStarted();
itsLogger = (Logger) LogManager.getLogger(classInterceptLogsFor);
itsLogger.addAppender(appender);
itsLogger.setLevel(logLevel);
}
public void teardown() {
itsLogger.removeAppender(appender);
}
public List<LogEvent> verifyNumLogEvents(int numEvents) {
verify(appender, times(numEvents)).append(logEventCaptor.capture());
return logEventCaptor.getAllValues();
}
public LogEvent verifyOneLogEvent() {
return verifyNumLogEvents(1).get(0);
}
public void assertLoggedMessage(String message) {
assertLogMessage(message, logEventCaptor.getValue());
}
public void assertLoggedMessage(String message, int messageIndex) {
assertLogMessage(message, logEventCaptor.getAllValues().get(messageIndex));
}
public static void assertLogMessage(String message, LogEvent event) {
assertEquals(message, event.getMessage().getFormattedMessage());
}
public static LogInterceptingTestHarness initHarness(Class<?> classInterceptLogsFor, Level logLevel) {
return initHarness(classInterceptLogsFor, logLevel, "testAppender");
}
public static LogInterceptingTestHarness initHarness(Class<?> classInterceptLogsFor, Level logLevel, String appenderName) {
return new LogInterceptingTestHarness(classInterceptLogsFor, logLevel, appenderName);
}
}

Categories

Resources