I wrote a simple Custom Formatter for my logging that prints a DateTime in the specified format. Everything works fine, but the datetime doesn't get printed in my log file. Below is my CustomFormatter.java:
CustomFormatter.java:
public class CustomFormatter extends Formatter {
SimpleDateFormat sdf;
public CustomFormatter() {
sdf = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
}
public String format(LogRecord rec) {
StringBuffer buf = new StringBuffer(1000);
buf.append(formatMessage(rec));
return buf.toString();
}
public String getHead(Handler h) {
return (sdf.format(new java.util.Date()) + ": \t");
}
public String getTail(Handler h) {
return "\n";
}
}
Im my main class, I initialize my logger as:
Main.java:
private static Logger logger = Logger.getLogger("org.somecompany.someproject");
public static void main(String[] args){
try{
String _pattern = "myLogger.log.%g";
int numLogFiles = 10;
int fileSize = 1000000;
boolean appendToFile = true;
FileHandler fh = new FileHandler(pattern, fileSize, numLogFiles, appendToFile);
fh.setFormatter(new CustomFormatter());
logger.addHandler(fh);
logger.setLevel(Level.ALL);
} catch(IOException i) { System.out.println("Unable to init logger");}
logger.info("Begin");
logger.info("Line 1");
logger.info("Line 2");
logger.info("End");
fh.close();
fh = null;
}
The log file should have a datetime printed at the beginning of each line and it isn't. Any help is appreciated.
I think you misunderstand the purpose of getHead() and getTail().
Those methods are not called per log entry - getHead() is called once before the Handler (FileHandler) logs the first entry and getTail() is called once before the Handler (FileHandler) closes the log stream.
This is used for example in the XMLFormatter to create a valid XML file (where there must be an XML start tag before the first log entry and an XML end tag after the last log entry to be valid XML).
If you look closely at the created log file this is exactly what happens: the log file creates a timestamp at the start and ends with a newline.
Note that adding time stamps to your log entries doesn't require writing a CustomFormatter. Properly configuring a SimpleFormatter is enough for your purpose.
Related
I want to change the format of the log but after I overrided the formatter, it still outputs in the old way.
private void initializeLogger() {
logger = Logger.getLogger("gameLogger");
try {
Handler handler = new FileHandler("/home/bobby/IdeaProjects/GoFishBobby/src/logs/log1.txt");
MyFormatter myFormatter = new MyFormatter();
handler.setFormatter(myFormatter);
logger.addHandler(handler);
for (Handler parentHandler : logger.getParent().getHandlers())
logger.removeHandler(parentHandler);
}catch(IOException e){
System.out.println("IO exception");
}
logger.info("Game starting : ");
}
I overrided the default loggerFormatter
public class MyFormatter extends Formatter{
public String format(LogRecord record){
return record.getMessage();
}
}
and the output still contains the info line with the information I dont need
SEVERE: NativePlayer : 0 Scored A Book of rank 3
Mar 05, 2017 1:15:44 PM Game logAfterPlay
INFO: The transfer hand is:
4D 4H 4S
Edit
I just found out the log in the file is correct, but why its still like this on the console? how do I get rid of it on the console. I already removed all the parent logger.
You can locate all handlers by using the following method to walk all currently created loggers.
public static void printLoggerTree() {
final LogManager manager = LogManager.getLogManager();
synchronized (manager) {
final Enumeration<String> e = manager.getLoggerNames();
while (e.hasMoreElements()) {
final Logger l = manager.getLogger(e.nextElement());
if (l != null) {
for (Handler h : l.getHandlers()) {
System.out.println(l.getName() + "=" + h);
}
}
}
}
}
The logger tree changes over time when different parts of your code requests new loggers. So it matters when you call this method.
A better practice is to setup your own logging.properties file and configure your project to use that on startup. You also don't need to create your own formatter as you can change the format pattern of the SimpleFormater on the command line by using the following:
-Djava.util.logging.SimpleFormatter.format="%5$s%n"
I am trying to create a logs file in a Java swings application that will contain all the messages generated by the code. But unfortunately it does not create 1 single log file but creates a structure as shown. I need 1 single log file.
My code:
//get the logger object
logger = Logger.getLogger("MyLog");
try {
// This block configure the logger with handler and formatter
loggerFH = new FileHandler(System.getProperty("user.dir") + "\\resources\\logs\\logs.txt",true);
logger.addHandler(loggerFH);
SimpleFormatter formatter = new SimpleFormatter();
loggerFH.setFormatter(formatter);
} catch (IOException | SecurityException ex) {
logger.severe(ex.getMessage());
outputArea.append(ex.getMessage());
}
Your files are being rotated.
Did you try solution from this:
Java FileHandler disable log rotation
FileHandler fh = new FileHandler( "path" , 0, 1, false);
I realized my Logger file was used by several instances at a time. So when 1 instance of filehandler locked the access to the file a new file was getting created. So I created a Synchronized class to handle all logging. And it worked great.
public class SynchronizedLogger {
//Logger to put error logs and messages in the log file
public static Logger logger = Logger.getLogger("MyLog");
//Logger Filehandler
private static FileHandler loggerFH;
public SynchronizedLogger() {
}
public static synchronized void writeLog(String message) {
logger.info(message);
}
public SynchronizedLogger(int i) {
try {
synchronized (this) {
// This block configures the logger with handler and formatter
loggerFH = new FileHandler(System.getProperty("user.dir") + "\\resources\\logs\\logs.txt", 0, 1, true);
logger.setUseParentHandlers(false);
logger.addHandler(loggerFH);
SimpleFormatter formatter = new SimpleFormatter();
loggerFH.setFormatter(formatter);
}
} catch (IOException | SecurityException ex) {
writeLog(ex.getMessage());
outputArea.append("\n\n" + ex.getMessage());
}
}
}
I have this GUI program where I'm trying to basically copy windows CMD. Since I have lots of features in this program, I decided to put parts of the code in different classes. But it doesn't respond.
if(command.size()<2 && command.size()>0) {
switch(command.get(0)) {
case "dt":
getDateTime a = new getDateTime();
a.Start();
break;
// other case(s) down below
}
}
Here is the geDateTime class
public class getDateTime {
public static void Start() {
Terminal t = new Terminal();
try {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = new Date();
String s = dateFormat.format(date).toString();
t.print(s);
}catch(Exception e){ e.printStackTrace(); }
}
}
Here is the print(); void in the main class...
public static void print(String s) {
Color c = Color.WHITE; // prints white text to JFrame
Style style = output.addStyle("Style", null);
StyleConstants.setForeground(style, c);
try{
document.insertString(document.getLength(), s, style);
}catch(Exception e){e.printStackTrace();}
}
Now when I enter the command for accessing the getDateTime class, the program freezes and I can't input anything. HOWEVER, if I just put the getDateTime class into a void inside the main class it works fine; but this would be a problem to just put everything into the main class since some function(s) could have hundreds of line of code.
No errors are produced when the program freezes.
In the code snippet that you have earlier, the code was trying to create a new Terminal rather than using the existing one.
Try this:
private static void print() {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = new Date();
String s = dateFormat.format(date).toString();
print(s);
}
In the access method:
case "dt":
print();
break;
Update: On a side note, try to avoid static if at all possible. Generally speaking, it's bad practice. See https://stackoverflow.com/a/7026563/1216965
I want to create and store log files in a particular folder in every hour. How to approach?
Any example will be helpful.
No extra effort required. Use DailyRollingFileAppender where set Datepattern - '.'yyyy-MM-dd-HH - Rollover at the top of every hour.
Example -
log4j.appender.LOGFILE = org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOGFILE.DatePattern = '.'yyyy-MM-dd-HH
...
Reference - DailyRollingFileAppender
Note : Do not use the colon ":" character in anywhere in the DatePattern option. The text before the colon is interpeted as the protocol specificaion of a URL which is probably not what you want.
You can use logger API(log4j) for generating the log files in every hour.
Something like that :
public void run(){
while(true){
synchronize(this){
if(timeLap==1hr)
file.writeLine();
}
else
Thread.sleep(1hour);
}
}
or you can use the API http://www.vogella.com/articles/Logging/article.html
You can create a custom FileAppender, somthing like
public class TestFileAppender extends WriterAppender {
String pattern;
public void setFile(String file) {
this.pattern = file;
}
public synchronized void update() {
try {
closeWriter();
String folder = new SimpleDateFormat("yyyyMMddHH").format(new Date());
File file = new File(String.format(pattern, folder));
file.getParentFile().mkdirs();
setWriter(new BufferedWriter(new FileWriter(file, true)));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
use it it log4j config
log4j.appender.file = test.TestFileAppender
log4j.appender.file.file = xxx/%s/1.log
log4j.appender.file.layout = org.apache.log4j.SimpleLayout
and run a FolderNameChanger once an hour
class FolderNameChanger extends TimerTask {
FolderNameChanger() {
run();
}
public void run() {
Enumeration<Appender> e = Logger.getRootLogger().getAllAppenders();
while (e.hasMoreElements()) {
Appender a = e.nextElement();
if (a instanceof TestFileAppender) {
((TestFileAppender) a).update();
}
}
}
}
this task finds all TestFileAppenders and changes their paths
Is there a way to create a log4j Logger at runtime that will gather logging messages into a buffer?
I currently have a class that logs a number of events. For a remote application that needs to monitor the logged events, I'd like to just swap in a logger that logs to a buffer and then retrieve the buffer, rather than refactor the class. E.g. given something like:
Class Foo{
Logger log = ....;
public void doSomething(){
log.debug(...
.. actual code
log.debug(...
}
}
//what I'd like to do from some outside code:
String showFooLog(){
Foo f = new Foo();
f.log=new Logger(...
f.doSomething();
return f.log.contents();
}
Is this possible?
Edit: Found a shorter solution, pointed to from Jared's posting( although it's still not threadsafe). Thanks for the help.
Logger l = Logger.getLogger( ... );
StringWriter writer = new StringWriter();
WriterAppender appender = new WriterAppender( new HTMLLayout(), writer );
l.addAppender( appender );
... run code here
writer.flush();
l.removeAppender( appender );
return writer.toString()
It's absolutely possible - although you're probably going to need to create your own Appender. This is really easy to do, though. Here's a rough-out of an example (need to think out thread-safety...this isn't threadsafe....and I'm not sure I like the statics...but this should be good enough to push you in the right direction):
public class BufferAppender extends org.apache.log4j.AppenderSkeleton {
private static Map<String, StringBuffer> buffers = new HashMap<String, StringBuffer>();
#Override
protected void append(LoggingEvent evt) {
String toAppend = this.layout.format(evt);
StringBuffer sb = getBuffer(evt.getLoggerName());
buffer.append(toAppend);
}
public static String getBufferContents(String loggerName) {
StringBuffer sb = buffers.get(sb);
if(sb == null) {
return null;
} else {
return sb.toString();
}
}
public static void clearBuffer(String loggerName) {
createBuffer(loggerName);
}
private static StringBuffer getBuffer(String loggerName) {
StringBuffer sb = buffers.get(loggerName);
if(sb == null) {
sb = createBuffer(loggerName);
}
return sb;
}
private static StringBuffer createBuffer(String loggerName) {
StringBuffer sb = new StringBuffer();
buffers.put(loggerName, sb);
return sb;
}
}
You could subclass org.apache.log4j.WriterAppender and provide it a ByteArrayOutputStream to store any messages. See the other subclasses of WriterAppender for inspriation. Then you can provide an instance of that object to your logger for appending via addAppender.