I'm learning Java logging recently, and in the javadoc, it says the SimpleFormatter can be configured using property "java.util.logging.SimpleFormatter.format".
In below code, I tried to "set the format" twice with System.setProperty(), but it seems won't work in the second attempt, the "formatterB" in below code will still use the format defined in "formatterA".
What's the reason for this, thanks.
public class Test {
public static void main(String[] args) {
try {
Logger loggerA = Logger.getLogger("A");
System.setProperty("java.util.logging.SimpleFormatter.format", "A: %1$tc %2$s%n%4$s: %5$s%6$s%n"); // first attempt
Handler handlerA = new FileHandler("A.log", 0, 1, true);
SimpleFormatter formatterA = new SimpleFormatter();
handlerA.setFormatter(formatterA);
loggerA.addHandler(handlerA);
loggerA.info("Logger A info message");
Logger loggerB = Logger.getLogger("B");
System.setProperty("java.util.logging.SimpleFormatter.format", "B: %1$tc %2$s%n%4$s: %5$s%6$s%n"); // second attempt
Handler handlerB = new FileHandler("B.log", 0, 1, true);
SimpleFormatter formatterB = new SimpleFormatter();
handlerB.setFormatter(formatterB);
loggerB.addHandler(handlerB);
loggerB.info("Logger B info message");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
The SimpleFormatter stores the format in a static field that is stored once on class load. The format is used for all instances of the SimpleFormatter class.
You'll have to roll your own formatter class or classes to support multiple formats.
Related
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.
I have a program in which I need to set the logger formatting, but since there are several entry points (I don't control all of them) I want to place the System.setProperty() call in the constructor of the class where all of the entry points converge.
Main class
public static void main(String[] args) throws Exception {
String foo = "bar";
String baz = "boo";
static final String FORMATTER_CONFIG = "%1$tb %1$td, %1$tY %1$tr %4$s: %5$s%n";
SomeClass sc = new SomeClass();
sc.method1(foo);
sc.method2(baz);
try {
SomeOtherClass soc = SomeOtherClass.newInstance();
} catch (Exception e) {;
}
// Next line will update the property of the logging formatter for this instance
System.setProperty("java.util.logging.SimpleFormatter.format", FORMATTER_CONFIG);
MyThirdClass mtc = MyThirdClass.getStaticMethod(foo, baz);
Logger logger = Logger.getLogger("myProject.main");
Handler h = new FileHandler("LogHere.txt");
h.setFormatter(new SimpleFormatter());
logger.addHandler(h);
logger.setLevel(Level.INFO);
logger.info("Info level log");
logger.fine("Fine level log");
logger.finer("Finer level log");
logger.finest("Finest level log");
}
Constructor of MyThirdClass:
public MyThirdClass() throws SecurityException {
this.classStaticVar = EntirelyDifferentClass.getVar();
logger = Logger.getLogger(this.getClass().getName());
Handler h = null;
try {
h = new FileHandler("MTC_LogHere.txt");
} catch (IOException ex) {
logger.warning("Failed to initialize custom FileHandler for MTC_LogHere.txt");
}
h.setFormatter(new SimpleFormatter());
logger.addHandler(h);
logger.setLevel(Level.INFO);
}
I want to put the call to System.setProperty as the first line of the constructor in MyThirdClass (before the call to EntirelyDifferentClass) but when I do the logging is not formatted according to the custom rules. If I leave it right where it is, the line before the call to MyThirdClass in the main method, it works as intended. Note that I've also tried putting the code block for System.setProperty in the getStaticMethod() method.
I understand that the system.properties are all static variables, so I have to believe that whatever is happening in the JVM during the method call to MyThirdClass.getStaticMethod is locking in the static properties before I can change it.
Am I understanding what is happening in the JVM correctly?
Since I don't control all entry points in the actual production
version of this program, and I also don't control the compile
settings nor can I issue a -Djava line command to set the properties
that way (which I've also verified will work) I need to be able to
do this programmatically in MyThirdClass. What am I
missing/overlooking, or am I just out of luck?
This answer was originally edited into the question above by the OP Bryan, I have posted this here and requested him to do so himself:
For anyone wanting to know the answer, I added a static block at the
class level of MyThirdClass:
protected static Logger logger = null;
static {
System.setProperty("java.util.logging.SimpleFormatter.format", FORMATTER_CONFIG);
logger = Logger.getLogger("myProject.MyThirdClass");
Handler h = null;
try {
h = new FileHandler("LogHere.txt");
}
catch (Exception ex) {
System.out.println("Exception");
}
h.setFormatter(new SimpleFormatter());
logger.addHandler(h);
logger.setLevel(Constants.LOGGING_LEVEL);
}
When you call a static method, such as getStaticMethod() in your case, an instance of the class is not created, and therefore the constructor is not called.
Try putting System.setProperty() in the static method instead of in the constructor.
For example:
import java.util.logging.*;
public class Main {
public static void main(String[] args) {
SomeClass.staticMethod();
Logger logger = Logger.getLogger(Main.class.getName());
logger.setLevel(Level.INFO);
logger.info("Info level log");
}
}
public class SomeClass {
public static void staticMethod() {
final String FORMATTER_CONFIG = "%1$tb %1$td, %1$tY %1$tr %4$s: %5$s%n";
System.setProperty("java.util.logging.SimpleFormatter.format", FORMATTER_CONFIG);
}
}
I have made a custom formatter for the java.util logger, implemented as below
logger = Logger.getAnonymousLogger();
logger.setUseParentHandlers(false);
sb = new StringBuffer();
try {
Handler handler = new FileHandler("xx.log");
handler.setFormatter(new CustomFormatter());
logger.addHandler(handler);
} catch (IOException e) {
e.printStackTrace();
}
private class CustomFormatter extends Formatter {
#Override
public String format(LogRecord record) {
String msg = record.getMessage();
sb.append(msg);
System.out.print(sb.toString());
return sb.toString();
}
}
Running the following code:
logger.finest(msg);
logger.finer(msg);
logger.fine(msg);
logger.config(msg);
logger.info(msg);
logger.warning(msg);
logger.severe(msg);
logger.log(new LogRecord(Level.FINE, msg));
Only info, warning, and severe work. the other methods run but return nothing to console, and write nothing to the log file. I need to implement at least 4 logging levels, but only the 3 work.
What is happening to log,config,fine,finer, finest? How do I get them to use my formatter? Or how do I pass the level to the formatter?
You may set the Level of logging with setlevel(Level)
Set the log level specifying which message levels will be logged by
this logger. Message levels lower than this value will be discarded.
In your case as you are interested in all levels, it would be :
logger.setLevel(Level.ALL);
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 want to make multiple logging files (For each day), the code I have is this:
public class LoggingInkrement {
static final Logger logger = Logger.getLogger(LoggingInkrement.class.getName());
public static void main(String[] args) {
LogManager manager = LogManager.getLogManager();
try {
FileHandler fhandler = new FileHandler("C:/Users/Administrator/Desktop/Logging%g.txt", 1024*1024,10, true);
SimpleFormatter sformatter = new SimpleFormatter();
fhandler.setFormatter(sformatter);
logger.addHandler(fhandler);
} catch (IOException | SecurityException ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
try {
((Object) null).toString();
}
catch ( Exception e ) {
logger.log( Level.SEVERE, "oh oh", e );
}
logger.info( "Hat funktioniert" );
}
}
my problem is that:
First run: logging0.txt is created
Second run: nothing happens
the changes are unnoticed (it stays on "Hat funktioniert") regardless of the changes i made in logger.info
but my desired outcome is:
You can make logging files with a set size
the files append and dont overwrite till they're full limit
The files are automatically deleted when outdated
logging0.txt
logging1.txt
logging2.txt
and so on
but I have no idea how I could do it
The FileHandler doesn't support daily file rotation. However, you can always trigger a rotation by creating a throw away FileHandler with the limit set to zero and append set to false.
if (isNewDay()) { //then rotate and close.
new FileHandler("C:/Users/Administrator/Desktop/Logging%g.txt",0,5, false).close();
}
//Open the log file.
FileHandler fhandler = new FileHandler("C:/Users/Administrator/Desktop/Logging%g.txt", 1024*1024,10, true);