I know how to create log messages in Java that appear in the console:
java.util.logging.Logger.getLogger(<CLASSNAME>.class.getName())
.log(Level.INFO, "LOG MESSAGE");
However, I am currently working on a web app (in netbeans IDE). In a web app, it is unfortunately not possible to have the logger output to the console.
Hence, I want to direct output to a file.
A few things I tried, didn't work. For example, I tried the following:
How to write logs in text file when using java.util.logging.Logger
https://examples.javacodegeeks.com/core-java/util/logging/java-util-logging-example/
...and many others, but nothing seems to work.
How can it be so difficult to direct output to a text file? Does anybody know how to do a direct output of the java default logger to a file?
Try this. It will create a text file in project folder.
Please make sure to do a refresh to see the file.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class Test {
static Handler fileHandler = null;
private static final Logger LOGGER = Logger.getLogger(Test.class
.getClass().getName());
public static void setup() {
try {
fileHandler = new FileHandler("./logfile.log");//file
SimpleFormatter simple = new SimpleFormatter();
fileHandler.setFormatter(simple);
LOGGER.addHandler(fileHandler);//adding Handler for file
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
public static void main(String[] args) {
setup();//calling to the file content
LOGGER.info("------------------START--------------------");
//here the Information or Contents that in file
}
}
I want to be able to do in my Java Netbeans application the same thing as in a normal application: writing print statements to the console or some file for debugging purposes.
I tested this with Netbeans creating a brand new web project running Tomcat 8 with new servlet. I modified the servlet to include:
Logger.getLogger("foo").info("This is a test message.");
And the result is printed to the Tomcat console by default with no changes to Tomcat, no changes to the project, and no logger.properties in the project.
In a web app, it is unfortunately not possible to have the logger output to the console.
You should have multiple tabs at the bottom of Netbeans. One is the console output from the Netbeans ANT task that runs the compiler and launches Tomcat. You should then have another tab that is the output from the Tomcat instance. Under that tab, you should see the logger messages. The logging in Tomcat points out that System.err/out are remapped to files:
When running Tomcat on unixes, the console output is usually redirected to the file named catalina.out. When running as a service on Windows, the console output is also caught and redirected, but the file names are different.
Default locations are in the Tomcat or domain home under a folder called logs. The default configuration should already be writing logger output to a file because of the installed console handler and System.err being remapped to a file. It just may not be the location you want.
Even though System.err/out are remapped you can write to the JVM console by creating your own custom handler that writes to a java.io.FileDescriptor.
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
public class FileDescriptorHandler extends StreamHandler {
public FileDescriptorHandler() {
super(new FileOutputStream(FileDescriptor.out), new SimpleFormatter());
}
#Override
public synchronized void publish(LogRecord record) {
super.publish(record);
super.flush();
}
#Override
public void close() {
flush();
}
}
By default Netbeans will capture and display this console output. Same is true if you just write code that prints to the console.
How can it be so difficult to direct output to a text file?
Does anybody know how to do direct output of the java default logger to a file?
This is also covered in the Tomcat documentation:
Example logging.properties for the servlet-examples web application to be placed in WEB-INF/classes inside the web application:
handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
.handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
org.apache.juli.FileHandler.level = FINE
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = ${classloader.webappName}.
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
Be aware that for Tomcat you have to declare the handlers that can be used unlike the standard LogManager.
If you can't get the log configuration files working then add a servlet context listener to your project and manually install the file handler.
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
import javax.servlet.ServletContextListener;
#WebListener
public class HandlerInstaller implements ServletContextListener {
private static final Logger logger = Logger.getLogger("");
private Handler target;
#Override
public synchronized void contextInitialized(ServletContextEvent sce) {
try {
target = new FileHandler();
logger.addHandler(target);
} catch (IOException | RuntimeException ex) {
sce.getServletContext().log(sce.toString(), ex);
}
}
#Override
public synchronized void contextDestroyed(ServletContextEvent sce) {
logger.removeHandler(target);
target.close();
target = null;
}
}
You should strongly consider using java.nio.file.Path;
This works for me; Put the file wherever you want !
final Logger LOGGER = Logger.getLogger(logIntextfile.class
.getClass().getName());
public void WriteToLog() {
Path path = Paths.get("c:", "myFiles", "logfile.log");
try {
FileHandler file = new FileHandler(path.toString());
SimpleFormatter simple = new SimpleFormatter();
file.setFormatter(simple);
LOGGER.addHandler(file);
} catch (IOException e) {
System.err.println ("Try another day");
}
This also work on mac os
Path path = Paths.get("/Users/",System.getProperty("user.name"),"myFiles", "logfile.log");
You can provide your own logging file on the classpath of your project directory
Netbeans logging : http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/doc-files/logging.html
Java Util logging with logging properties file sample : http://www.javapractices.com/topic/TopicAction.do?Id=143
Related
I wanted to try and test the FileAppender on my local machine after reading the documentation online. When i create the object by calling the build method i get errors.
I will be upgrading the log4j version in an application and was learning about file appenders when i failed to create and test one locally.I tried looking on the internet and found some code on how to create it. When i try the same i get errors show below in the stack trace. I am using a windows machine and running the code on netbeans.
package logtest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.appender.FileAppender;
class Test
{
public void appendLogs(String logEvent)
{
LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
FileAppender.Builder b = FileAppender.newBuilder();
b.withFileName("TestFile");
b.withAppend(true);
b.build();
FileAppender fa = b.build();
System.out.println(fa.toString());
fa.start();
fa.error("Error message");
}
}
public class LogTest {
private static final Logger LOG = LogManager.getLogger(LogTest.class);
public static void main(String[] args) {
Test t = new Test();
t.appendLogs("Test log");
System.out.println(t.toString());
t.appendLogs("This is an error in a file");
LOG.debug("This Will Be Printed On Debug");
LOG.info("This Will Be Printed On Info");
LOG.warn("This Will Be Printed On Warn");
LOG.error("This Will Be Printed On Error");
LOG.fatal("This Will Be Printed On Fatal");
LOG.info("Appending string: {}.", "Hello, World");
}
}
I get the error during the call to build() method.
Exception in thread "main" java.lang.NullPointerException: name
at java.util.Objects.requireNonNull(Objects.java:228)
at org.apache.logging.log4j.core.appender.AbstractAppender.<init>(AbstractAppender.java:205)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.<init>(AbstractOutputStreamAppender.java:120)
at org.apache.logging.log4j.core.appender.FileAppender.<init>(FileAppender.java:259)
at org.apache.logging.log4j.core.appender.FileAppender.<init>(FileAppender.java:42)
at org.apache.logging.log4j.core.appender.FileAppender$Builder.build(FileAppender.java:104)
at logtest.Test.appendLogs(LogTest.java:17)
at logtest.LogTest.main(LogTest.java:31)
Java Result: 1
I dont understand why i get the null exception.
You need to set a name for the appender.
FileAppender.Builder b = FileAppender.newBuilder();
b.withFileName("TestFile");
b.withAppend(true);
b.setName("my-appender");
b.build();
FileAppender fa = b.build();
I am working with Jetty embedded server, building a REST api out of a legacy jar, which has a lot of critically useful calls to println (I run its classes and it prints stuff in console). I am trying now to have these printlns in a file, along with the requests status, but the NCSARequestLog only logs in the file date and code of the responses. Is there a way to log everything in a file then? I'm pretty sure it is possible because before we were wrapping the legacy jar in a war file deployed into Glassfish, and all prints used to show up in the server log.
Thanks
In the jetty-util-<ver>.jar there is a class called RolloverFileOutputStream which can be instantiated and then set to take over the roll of System.out and System.err
An example of this:
package demo;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.TimeZone;
import org.eclipse.jetty.util.RolloverFileOutputStream;
public class ConsoleCaptureDemo
{
public static void main(String[] args) throws IOException
{
File loggingDir = new File("logs");
if (!loggingDir.exists())
{
if (!loggingDir.mkdirs())
{
throw new RuntimeException("Unable to create directory: " + loggingDir);
}
}
String loggingFile = new File(loggingDir, "yyyy_mm_dd.jetty.log").getAbsolutePath();
boolean append = false;
int retainDays = 90;
TimeZone zone = TimeZone.getTimeZone("GMT");
RolloverFileOutputStream logStream = new RolloverFileOutputStream(loggingFile,
append, retainDays, zone);
System.out.println("Look at " + logStream.getFilename());
PrintStream logWriter = new PrintStream(logStream);
System.setOut(logWriter);
System.setErr(logWriter);
System.out.println("From System.out - hi there");
System.err.println("From System.err - hello again");
}
}
I am getting a stream of data from a server (in binary format). This data is serialised using Google protocol buffers. I'm attempting to do a daily rollover (i.e. if next day occurs write to new file containing the new Date with the compressed data inside).
I've attempted to do this via log4j, however, log4j doesn't account for binary (as far as I know I can only get text via it). When log4j writes the files, it doesn't write them in binary, but in text (human readable) format.
I went over this question to create a custom binary appender in log4j How to Create Binary Log File in Java using Log4J
However, I only started with log4j a couple of days ago and I'm not too sure how to go about doing this.
Is there any other way to do the rollover for binary data? I'm not even sure if log4j is the best solution. I'm more than happy to try any solution you can come up with!
I want log4j to write the data in Binary not Text.
Is there any way to do a daily rollover for binary files in java?
I don't think log4j is necessary here. If you need just file rollover small stream wrapper would be enough.
Jetty project has implementation of such FileOuputStream in it's util classes RolloverFileRotator which I think fits perfectly here.
You can extend the default log4j DailyRollingFileAppender and include it in your classpath
package test.com;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;
public class BinaryRollingFileAppender extends DailyRollingFileAppender {
FileOutputStream fout;
public BinaryRollingFileAppender(){
}
#Override
public void setFile(String file) {
super.setFile(file);
try {
fout = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
#Override
public void append(LoggingEvent le) {
try {
fout.write((byte[])le.getMessage());
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
public void close() {
try {
fout.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
then configure the appender via log4j properties file
log4j.appender.app=test.com.BinaryRollingFileAppender
log4j.appender.app.File=/tmp/binary.bin
log4j.appender.app.DatePattern='.'yyyy-MM-dd
log4j.logger.app.com=DEBUG, app
and test it
package test.com;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.log4j.Logger;
public class TestBinary {
private static final Logger LOGGER = Logger.getLogger(TestBinary.class);
public static void main(String[] args) {
Path path = Paths.get("c://tmp/binary-example-file.bin");
try {
LOGGER.debug(Files.readAllBytes(path));
} catch (Exception e) {
e.printStackTrace();
}
}
}
I don't know if this is what you want, but is a good start point, hope this helps you.
You can use RotatingFileOutputStream with DailyRotationPolicy provided by rotating-fos Java library.
Now I am learner to log4j , please guide me how to create and the run simple example step by step.
From Log4J Java - A simple Log4J example
package com.devdaily.log4jdemo;
import org.apache.log4j.Category;
import org.apache.log4j.PropertyConfigurator;
import java.util.Properties;
import java.io.FileInputStream;
import java.io.IOException;
/**
* A simple Java Log4j example class.
* #author alvin alexander, devdaily.com
*/
public class Log4JExample
{
// our log4j category reference
static final Category log = Category.getInstance(Log4JDemo.class);
static final String LOG_PROPERTIES_FILE = "lib/Log4J.properties";
public static void main(String[] args)
{
// call our constructor
new Log4JExample();
// Log4J is now loaded; try it
log.info("leaving the main method of Log4JDemo");
}
public Log4JExample()
{
initializeLogger();
log.info( "Log4JExample - leaving the constructor ..." );
}
private void initializeLogger()
{
Properties logProperties = new Properties();
try
{
// load our log4j properties / configuration file
logProperties.load(new FileInputStream(LOG_PROPERTIES_FILE));
PropertyConfigurator.configure(logProperties);
log.info("Logging initialized.");
}
catch(IOException e)
{
throw new RuntimeException("Unable to load logging property " +
LOG_PROPERTIES_FILE);
}
}
}
Log4J Manual...
Basics and Intermediate Example for log4j
http://aayushtuladhar.wordpress.com/2012/12/01/testtt/
Best Doc for log4j
http://logging.apache.org/log4j/1.2/manual.html
Hi I am trying to implement the java logging in my application. I want to use two handlers.
A file handler and my own console handler. Both of my handlers work fine. My logging is send to a file and to the console .
My logging is also sent to the default console handler, which i do not want. If you run my code you will see extra two line sent to the console. I don't want to use the default console handler. Does anyone know how to disable the default console handler.
I only want to use the two handlers I have created.
Handler fh = new FileHandler("test.txt");
fh.setFormatter(formatter);
logger.addHandler(fh);
Handler ch = new ConsoleHandler();
ch.setFormatter(formatter);
logger.addHandler(ch);
import java.util.Date;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class LoggingExample {
private static Logger logger = Logger.getLogger("test");
static {
try {
logger.setLevel(Level.INFO);
Formatter formatter = new Formatter() {
#Override
public String format(LogRecord arg0) {
StringBuilder b = new StringBuilder();
b.append(new Date());
b.append(" ");
b.append(arg0.getSourceClassName());
b.append(" ");
b.append(arg0.getSourceMethodName());
b.append(" ");
b.append(arg0.getLevel());
b.append(" ");
b.append(arg0.getMessage());
b.append(System.getProperty("line.separator"));
return b.toString();
}
};
Handler fh = new FileHandler("test.txt");
fh.setFormatter(formatter);
logger.addHandler(fh);
Handler ch = new ConsoleHandler();
ch.setFormatter(formatter);
logger.addHandler(ch);
LogManager lm = LogManager.getLogManager();
lm.addLogger(logger);
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
logger.info("why does my test application use the standard console logger ?\n" + " I want only my console handler (Handler ch)\n " + "how can i turn the standard logger to the console off. ??");
}
}
Just do
LogManager.getLogManager().reset();
The default console handler is attached to the root logger, which is a parent of all other loggers including yours. So I see two ways to solve your problem:
If this is only affects this particular class of yours, the simplest solution would be to disable passing the logs up to the parent logger:
logger.setUseParentHandlers(false);
If you want to change this behaviour for your whole app, you could remove the default console handler from the root logger altogether before adding your own handlers:
Logger globalLogger = Logger.getLogger("global");
Handler[] handlers = globalLogger.getHandlers();
for(Handler handler : handlers) {
globalLogger.removeHandler(handler);
}
Note: if you want to use the same log handlers in other classes too, the best way is to move the log configuration into a config file in the long run.
This is strange but Logger.getLogger("global") does not work in my setup (as well as Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)).
However Logger.getLogger("") does the job well.
Hope this info also helps somebody...
Do a reset of the configuration and set the root level to OFF
LogManager.getLogManager().reset();
Logger globalLogger = Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME);
globalLogger.setLevel(java.util.logging.Level.OFF);
You must instruct your logger not to send its messages on up to its parent logger:
...
import java.util.logging.*;
...
Logger logger = Logger.getLogger(this.getClass().getName());
logger.setUseParentHandlers(false);
...
However, this should be done before adding any more handlers to logger.