Java Util Logging integration is provided as part of the artifact:

<dependency>
  <groupId>io.yupiik.logging</groupId>
  <artifactId>yupiik-logging-jul</artifactId>
  <version>${yupiik-logging.version}</version>
</dependency>

Use globally

java .... -Djava.util.logging.manager=io.yupiik.logging.jul.YupiikLogManager ...

Configuration

Configuration is close to default JUL one with small differences:

  1. handlers don’t need to configure themselves in their constructor or so for common properties (formatter, level, …​), the framework does it automatically

  2. InlineFormatter and JsonFormatter support aliases (reflection free instantiation) with inline and json you can use in the configuration

Standard handler

io.yupiik.logging.jul.handler.StandardHandler enables to log on stdout and stderr. For all level from finest/debug to info it will go on stdout and others (warnings, errors/severes) will go on stderr.

It can be configured with the std or standard alias too.

There is also its companion stdout or io.yupiik.logging.jul.handler.StdoutHandler which only outputs on stdout.

File Handler

A io.yupiik.logging.jul.handler.LocalFileHandler is also provided to be able to log in a file and rotate the log file. Indeed you can use JVM FileHandler but this one is a bit more powerful in practise if you don’t run in a container and can’t use a docker logging driver or equivalent.

Here is its configuration - all are prefixed with io.yupiik.logging.jul.handler.LocalFileHandler. and the standard configuration (encoding, level, …​) is still supported even if not listed.

Name Default Value Description

filenamePattern

${application.base}/logs/logs.%s.%03d.log

where log files are created, it uses String.format() and gives you the date and file number - in this order. If you replace %s by %sH you will append the hour in the filename. %sHm adds the minutes (a more precise pattern is not needed nor recommended).

noRotation

false

if true, once a log file is opened, it is kept for the life of the process.

overwrite

false

if true, existing files are reused.

truncateIfExists

false

if true, opening a file is not in append mode (previous content is erased).

limit

10 Megabytes

limit size indicating the file should be rotated - in long format

dateCheckInterval

5 seconds

how often the date should be computed to rotate the file (don’t do it each time for performances reason, means you can get few records of next day in a file name with current day). In java Duration format (ex: PT5S).

bufferSize

-1

if positive the in memory buffer used to store data before flushing them to the disk (in bytes)

archiveDirectory

${application.base}/logs/archives/

where compressed logs are put.

archiveFormat

gzip

zip or gzip.

archiveOlderThan

-1

how many days files are kept before being compressed

purgeOlderThan

-1

how many days files are kept before being deleted, note: it applies on archives and not log files so 2 days of archiving and 3 days of purge makes it deleted after 5 days.

compressionLevel

-1

In case of zip archiving the zip compression level (-1 for off or 0-9).

maxArchives

-1

Max number of archives (zip/gzip) to keep, ignored if negative (you can review io.yupiik.logging.jul.handler.LocalFileHandlerTest.purgeMaxArchive for some sample configuration).

Pattern formatter

The library also provides a pattern formatter. It does not use String.format as SimpleFormatter does and can be configured either with io.yupiik.logging.jul.formatter.PatternFormatter.pattern property or passing the pattern to the formatter alias (reflection free mode): pattern(<pattern to use>). Its syntax uses % to mark elements of the log record. Here is the list:

Name Description

%%

Escapes % character.

%n

End of line.

%l or %level

Log record level.

%m or %message

Log record message.

%c or %logger

Logger name.

%C or %class

Class name if exists or empty.

%M or %method

Method name if exists or empty.

%d or %date

The instant value. Note it can be followed by a date time formatter pattern between braces.

%x or %exception

The exception. It will be preceeded by a new line if existing to ensure it integrates well in log output.

%T or %threadId

Thread ID.

%t or %thread or %threadName

Thread name - only works in synchronous mode.

%r

Duration (in ms) since the startup of the application (creating of the pattern formatter actually).

%uuid

Random UUID.

Pattern example value: %d [%l][%c][%C][%M] %m%x%n, it will output lines like 1970-01-01T00:00:00Z [INFO][the.logger][the.source][the.method] test message\n.

JSON formatter

JSON formatter relies on JSON-B until 1.0.2, JSON-P starting with 1.0.3 and no dependency starting with 1.0.8 so ensure to add the related dependencies. It can be done with this list for example:

<dependency>
  <groupId>org.apache.geronimo.specs</groupId>
  <artifactId>geronimo-json_1.1_spec</artifactId>
  <version>1.5</version>
</dependency>
<dependency>
  <groupId>org.apache.johnzon</groupId>
  <artifactId>johnzon-core</artifactId>
  <version>1.2.19</version>
</dependency>
Tip
the JSON formatter can be configured passing json(useUUID=[false|true],formatMessage=[true|false],customEntriesMapper=<fqn of a Function<LogRecord, Map<String, String>>>) value instead of just json. All configuration being optional. formatMessage enables to skip the message formatting when your application does not rely on it - faster and uses less the CPU, useUUID enables to force an unique ID in the record. customEntriesMapper enables to pass a function taking the log record and converting it to a map of data to append to the json object (must be String key/values).

Sample Configuration Files

As with native JUL LogManager, you can configure the runtime logging with the following system property: -Djava.util.logging.config.file=<path to config file>.

Note
don’t forget -Djava.util.logging.manager=io.yupiik.logging.jul.YupiikLogManager too.

Here is a sample configuration switching to JSON logging:

.handlers = io.yupiik.logging.jul.handler.StandardHandler
io.yupiik.logging.jul.handler.StandardHandler.formatter = json

The same configuration for a standard inline logging (text style) but tuning the log level:

.handlers = io.yupiik.logging.jul.handler.StandardHandler
io.yupiik.logging.jul.handler.StandardHandler.level = FINEST
com.app.level = FINEST

Here is a configuration using a pattern:

.handlers = standard
standard.formatter = pattern(%d [%l][%c][%C][%M] %m%x%n)

And finally a configuration using file output instead of standard one:

.handlers = file
file.formatter = inline
Tip
you can set all properties as system properties and also environment variables (in uppercase and dots replaced by underscores).