How to set up java logging using a properties file? (java.util.logging)
Okay, first intuition is here:
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level = ALL
The Java prop file parser isn't all that smart, I'm not sure it'll handle this. But I'll go look at the docs again....
In the mean time, try:
handlers = java.util.logging.FileHandler
java.util.logging.ConsoleHandler.level = ALL
Update
No, duh, needed more coffee. Nevermind.
While I think more, note that you can use the methods in Properties to load and print a prop-file: it might be worth writing a minimal program to see what java thinks it reads in that file.
Another update
This line:
FileInputStream configFile = new FileInputStream("/path/to/app.properties"));
has an extra end-paren. It won't compile. Make sure you're working with the class file you think you are.
Java logging.properties file only print specific logger
Looks like:
- You forgot to include '.level' when setting the level of a logger.
- You misspelled 'SimpleForwardApplicaiton'. Does that match the logger name?
- You didn't turn off all of the other loggers. This only works for loggers that have been created by code.
Try setting the root logger to OFF and only turning on logger you want to see
handlers= java.util.logging.FileHandler
java.util.logging.FileHandler.pattern = /opt/log/Proxy_%u_%g.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
.level=OFF
au.id.czapski.hl7.SimpleForwardApplicaiton.level = ALL
au.id.czapski.hl7.SimpleForwardApplication.level = ALL
How to use a logging.properties file from disk as a java.util.logging.properties file
You could try this:
String yourFilePath = "./yourLogProperties.properties";
LogManager.getLogManager().readConfiguration(new FileInputStream(yourFilePath);
Properties will be loaded from a file stored in the same folder which your app is executed.
Update:
I was searching a little bit how to pass properties thru command line and there's a pretty good explanation here. So, in your case you'll need something like this:
java -jar -Djava.util.logging.config.file="./yourLogProperties.properties" YourApp.jar
Also you can test if it works making a simple test:
public class Tests {
public static void main(String[] args) {
System.out.println(System.getProperty("java.util.logging.config.file"));
}
}
Running this from command line you should get the answer ./yourLogProperties.properties
How to configure java.util.logging via properties to use standard output?
Derive a new handler from java.util.logging.StreamHandler
and use its
fully-qualified name with a <logger>.handlers property.
(If Apache Maven is used, be aware of the surefire plugin using stdout
as a means of IPC with its forked children, so expect corruption warnings during testing, see here.)
For example (Java 9+)...
Layout directories:
mkdir -p /tmp/logger/{src/org.foo/{{classes,tests}/org/foo/logging{,/internal},resources},{build/modules/org.foo,dist}}
Verify layout:
cd /tmp/logger && gio tree --hidden
file:///tmp/logger
|-- build
| `-- modules
| `-- org.foo
|-- dist
`-- src
`-- org.foo
|-- classes
| `-- org
| `-- foo
| `-- logging
| `-- internal
|-- resources
`-- tests
`-- org
`-- foo
`-- logging
`-- internal
Write classes under the src/org.foo/classes
branch.
A handler.
package org.foo.logging.internal;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.util.Objects;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
public class StandardOutConsoleHandler extends StreamHandler
{
public StandardOutConsoleHandler(Formatter formatter)
{
super(new FileOutputStream(FileDescriptor.out),
Objects.requireNonNull(formatter, "formatter"));
}
public StandardOutConsoleHandler() { this(new SimpleFormatter()); }
/* Taken from java.logging/java.util.logging.ConsoleHandler. */
@Override
public void publish(LogRecord record)
{
super.publish(record);
flush();
}
/* Taken from java.logging/java.util.logging.ConsoleHandler. */
@Override
public void close() { flush(); }
}
A filter (optionally).
package org.foo.logging.internal;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.Objects;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
public class WallClockTimeFilter implements Filter
{
private static final TemporalQuery<Boolean> BUSINESS_HOURS
= new BusinessHours();
static class BusinessHours implements TemporalQuery<Boolean>
{
private static final LocalTime FROM = LocalTime.of(9, 0);
private static final LocalTime TO = LocalTime.of(17, 0);
@Override
public Boolean queryFrom(TemporalAccessor temporal)
{
final LocalTime now = LocalTime.from(temporal);
return (now.isAfter(FROM) && now.isBefore(TO));
}
}
@Override
public boolean isLoggable(LogRecord record)
{
Objects.requireNonNull(record, "record");
final LocalTime now = LocalTime.ofInstant(record.getInstant(),
ZoneId.systemDefault());
return now.query(BUSINESS_HOURS);
}
}
A properties configurer.
package org.foo.logging.internal;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.LogManager;
/*
* This class could be referenced on the command-line as follows
*
* -Djava.util.logging.config.class=org.foo.logging.internal.LoggingPropertiesConfigurer
*
* See java.logging/java.util.logging.LogManager#readConfiguration().
*/
public class LoggingPropertiesConfigurer
{
private static final String RESOURCE = "/logging.properties";
public LoggingPropertiesConfigurer() throws IOException
{
try (final InputStream is = getClass().getResourceAsStream(
RESOURCE)) {
if (is == null)
throw new IllegalStateException(
String.format("Unavailable resource: '%s'",
RESOURCE));
/* Prefer new non-null values over old values. */
LogManager.getLogManager().updateConfiguration(is,
property ->
((oldValue, newValue) -> {
return (oldValue == null && newValue == null)
? null /* Discard the property. */
: (newValue == null)
? oldValue
: newValue;
}));
}
}
}
A dummy.
package org.foo.logging;
import java.io.IOException;
import java.util.Arrays;
import java.util.Optional;
import java.util.logging.Logger;
import org.foo.logging.internal.LoggingPropertiesConfigurer;
public class Dummy
{
static {
try {
final String fileName = System.getProperty(
"java.util.logging.config.file");
final String klassName = System.getProperty(
"java.util.logging.config.class");
if (klassName == null && fileName == null)
new LoggingPropertiesConfigurer();
} catch (final IOException e) {
throw new ExceptionInInitializerError(e);
}
}
static Optional<Logger> getLogger()
{
/*
* Note that for any org.foo.Bar.Baz.Quux member class
* Class::getName returns an org.foo.Bar$Baz$Quux string,
* therefore name accordingly these loggers, if any, in
* the properties files, e.g.
* org.foo.Bar$Baz$Quux.level = WARNING
*/
return Optional.ofNullable(Logger.getLogger(
Dummy.class.getName()));
}
public static void main(String[] args)
{
/*
* A weakly-reachable logger.
*
* See java.base/java.lang.ref.Reference#reachabilityFence(Object)
*/
Dummy.getLogger().ifPresent(logger -> logger.warning(() ->
Arrays.toString(args)));
}
}
Write a module declaration as src/org.foo/classes/module-info.java
.
module org.foo {
requires transitive java.logging;
exports org.foo.logging;
exports org.foo.logging.internal to
java.logging;
}
Compile classes:
javac -Xlint -d build/modules --module-source-path src/\*/classes/ $(find src/*/classes/ -type f -name \*.java)
Describe a module:
java --describe-module org.foo --module-path build/modules
Write a properties file as src/org.foo/resources/logging.properties
.
## From [java.home]/conf/logging.properties:
# handlers = java.util.logging.ConsoleHandler
handlers = org.foo.logging.internal.StandardOutConsoleHandler
java.util.logging.SimpleFormatter.format = %1$tY-%<tm-%<td %<tH:%<tM:%<tS %4$s %2$s %5$s%6$s%n
## See the Javadoc of java.logging/java.util.logging.StreamHandler.
org.foo.logging.internal.StandardOutConsoleHandler.level = ALL
# org.foo.logging.internal.StandardOutConsoleHandler.filter = org.foo.logging.internal.WallClockTimeFilter
org.foo.logging.internal.StandardOutConsoleHandler.formatter = java.util.logging.SimpleFormatter
org.foo.logging.internal.StandardOutConsoleHandler.encoding = ISO-8859-1
Make a copy of it for packaging:
cp -t build/modules/org.foo src/org.foo/resources/logging.properties
Package classes and copied resources (observe the . at the end):
jar --create --module-version 0.0.1 --file dist/logger-0.0.1.jar --main-class org.foo.logging.Dummy -C build/modules/org.foo/ .
Try running with redirected stdout
, stderr
.
Stdout
logging. When local time permits, uncomment the time-related filter line in logging.properties
:
java -Xdiag --module-path dist/logger-0.0.1.jar --module org.foo raison d\'être 2>/dev/null
Stderr
logging. Substitute the real path to the Java installation directory for /path/to/jdk:
java -enablesystemassertions -Xdiag -Djava.util.logging.config.file=/path/to/jdk/conf/logging.properties --module-path dist/logger-0.0.1.jar --module org.foo raison d\'être 2>/dev/null
What is the simplest way to configure `java.util.logging`
All I want to do is to run this application with all available log messages spitting to stdout
Don't do this in production but it is the fast, easy, hacky way:
Edit the logging.properties file located in java/conf
. E.G. /usr/lib/jvm/default-java/conf/logging.properties
That file is setup to attach a ConsoleHandler to the root logger which is what you want to do this. You just need to adjust the levels to see the output. This is a global change so be aware.
Edit that file and:
- Change
.level= INFO
->.level=ALL
- Change
java.util.logging.ConsoleHandler.level = INFO
tojava.util.logging.ConsoleHandler.level = ALL
- Save the changes and restart your app.
The recommended way:
Most JVMs are not in your control (production/dev server) so you can instead copy that file to a location you own and use the java.util.logging.config.file
system property.
E.G. -Djava.util.logging.config.file=/home/myuser/myapp/logging.properties
That way you are free to make changes that are local to your program and not global to the machine.
Load java.util.logging.config.file for default initialization
Java logging doesn't search your whole hard disk for a file; there are very simple rules how files are looked up. You want Java to see that the two files belong to each other but you didn't say so anywhere. Since Java sees no connection between the properties file and your class other than that they are in the same folder on your disk, it can't find the file.
-Djava.util.logging.config.file=log.properties
only works if the file log.properties
is in the current directory of the Java process (which can be pretty random). So you should use an absolute path here.
An alternate solution would be to move the file logging.properties
into $JAVA_HOME/lib/
(or edit the file which should be there). In that case, you don't need to set a System property.
Setting java.util.logging.config.file at runtime
Probably a problem with your logging properties. I noticed that I had to use both level specifications in the config (root and console) to get the result.
Maybe your root logger level is below FINEST
, e.g. INFO
(.level=INFO
).
Or not set at all, in which case I suppose it to be INFO
.
I ran your code with the following logging.properties:
handlers=java.util.logging.ConsoleHandler
.level=FINEST
java.util.logging.ConsoleHandler.level=FINEST
Without specifying the -Djava.util.logging.config.file=/tmp/logging.properties
output was:
--- start
09.11.2012 14:25:49 testing.Scribble main
SCHWERWIEGEND: SEVERE 1
09.11.2012 14:25:49 testing.Scribble main
SCHWERWIEGEND: SEVERE 2
09.11.2012 14:25:49 testing.Scribble main
SCHWERWIEGEND: SEVERE 3
09.11.2012 14:25:49 testing.Scribble main
AM FEINSTEN: FINEST 3
--- end
Looks correct!
(My test class is called testing.Scribble, thats the only difference)
Using -Djava.util.logging.config.file=/tmp/logging.properties
output is:
--- start
09.11.2012 14:31:06 testing.Scribble main
SCHWERWIEGEND: SEVERE 1
09.11.2012 14:31:06 testing.Scribble main
AM FEINSTEN: FINEST 1
09.11.2012 14:31:06 testing.Scribble main
SCHWERWIEGEND: SEVERE 2
09.11.2012 14:31:06 testing.Scribble main
AM FEINSTEN: FINEST 2
09.11.2012 14:31:06 testing.Scribble main
SCHWERWIEGEND: SEVERE 3
09.11.2012 14:31:06 testing.Scribble main
AM FEINSTEN: FINEST 3
--- end
Looks also correct!
Related Topics
How to Call a Method in Another Class of the Same Package
Does the Sequence of the Values Matter in a JSON Object
How to Add a Utf-8 Bom in Java
Java Sax Parser Split Calls to Characters()
How to Define Multiple Jbutton Actions from a Different Class
Java Regex: Repeating Capturing Groups
How to Avoid a Lot of If Else Conditions
Singleton Design Pattern: Pitfalls
Java Singleton and Synchronization
Javamail API to Imail -- Java.Net.Socketexception: Permission Denied: Connect
Getting an Attribute Value in Xml Element
Create a Jtds Connection String
Compare One String with Multiple Values in One Expression
Is There a Method for String Conversion to Title Case
Converting an Int to a Binary String Representation in Java
Using Setvalueat to Recreate Mutually Exclusive Check Boxes
JPA Query Selecting Only Specific Columns Without Using Criteria Query