How to Set Up Java Logging Using a Properties File? (Java.Util.Logging)

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:

  1. You forgot to include '.level' when setting the level of a logger.
  2. You misspelled 'SimpleForwardApplicaiton'. Does that match the logger name?
  3. 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 to java.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



Leave a reply



Submit