How to configure slf4j-simple - java

api 1.7 and slf4j-simple as implementation. I just can't find how to configure the logging level with this combination.
Can anyone help out?

It's either through system property
-Dorg.slf4j.simpleLogger.defaultLogLevel=debug
or simplelogger.properties file on the classpath
see https://www.slf4j.org/api/org/slf4j/simple/SimpleLogger.html for details

This is a sample simplelogger.properties which you can place on the classpath (uncomment the properties you wish to use):
# SLF4J's SimpleLogger configuration file
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
# Default logging detail level for all instances of SimpleLogger.
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, defaults to "info".
#org.slf4j.simpleLogger.defaultLogLevel=info
# Logging detail level for a SimpleLogger instance named "xxxxx".
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, the default logging detail level is used.
#org.slf4j.simpleLogger.log.xxxxx=
# Set to true if you want the current date and time to be included in output messages.
# Default is false, and will output the number of milliseconds elapsed since startup.
#org.slf4j.simpleLogger.showDateTime=false
# The date and time format to be used in the output messages.
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
# If the format is not specified or is invalid, the default format is used.
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
# Set to true if you want to output the current thread name.
# Defaults to true.
#org.slf4j.simpleLogger.showThreadName=true
# Set to true if you want the Logger instance name to be included in output messages.
# Defaults to true.
#org.slf4j.simpleLogger.showLogName=true
# Set to true if you want the last component of the name to be included in output messages.
# Defaults to false.
#org.slf4j.simpleLogger.showShortLogName=false
In a Maven or Gradle project, a convenient place "on the classpath" is src/main/resources/simplelogger.properties.

You can programatically change it by setting the system property:
public class App {
public static void main(String[] args) {
// for the code below to work, it must be executed before the
​// logger is created. see note below
System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE");
​org.slf4j.Logger log = LoggerFactory.getLogger(App.class);
​
​log.trace("trace");
​log.debug("debug");
​log.info("info");
​log.warn("warning");
​log.error("error");
​}
​}
The log levels are ERROR > WARN > INFO > DEBUG > TRACE.
Please note that once the logger is created the log level can't be changed. If you need to dynamically change the logging level you might want to use log4j with SLF4J.

I noticed that Eemuli said that you can't change the log level after they are created - and while that might be the design, it isn't entirely true.
I ran into a situation where I was using a library that logged to slf4j - and I was using the library while writing a maven mojo plugin.
Maven uses a (hacked) version of the slf4j SimpleLogger, and I was unable to get my plugin code to reroute its logging to something like log4j, which I could control.
And I can't change the maven logging config.
So, to quiet down some noisy info messages, I found I could use reflection like this, to futz with the SimpleLogger at runtime.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;
try
{
Logger l = LoggerFactory.getLogger("full.classname.of.noisy.logger"); //This is actually a MavenSimpleLogger, but due to various classloader issues, can't work with the directly.
Field f = l.getClass().getSuperclass().getDeclaredField("currentLogLevel");
f.setAccessible(true);
f.set(l, LocationAwareLogger.WARN_INT);
}
catch (Exception e)
{
getLog().warn("Failed to reset the log level of " + loggerName + ", it will continue being noisy.", e);
}
Of course, note, this isn't a very stable / reliable solution... as it will break the next time the maven folks change their logger.

I don't know why. I use simplelogger.properties and org.slf4j.simpleLogger.showDatetime, it's not working.
I lookup the SimpleLogger class source code and got this part of the code
static {
// Add props from the resource simplelogger.properties
InputStream in = (InputStream)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
ClassLoader threadCL = Thread.currentThread().getContextClassLoader();
if (threadCL != null) {
return threadCL.getResourceAsStream(CONFIGURATION_FILE);
} else {
return ClassLoader.getSystemResourceAsStream(CONFIGURATION_FILE);
}
}
});
if(null != in) {
try {
simpleLoggerProps.load(in);
in.close();
} catch(java.io.IOException e) {
// ignored
}
}
showLogName = getBooleanProperty(systemPrefix + "showlogname", showLogName);
showShortName = getBooleanProperty(systemPrefix + "showShortLogname", showShortName);
showDateTime = getBooleanProperty(systemPrefix + "showdatetime", showDateTime);
showThreadName = getBooleanProperty(systemPrefix + "showthreadname", showThreadName);
dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat", dateTimeFormat);
if(showDateTime) {
try {
dateFormatter = new SimpleDateFormat(dateTimeFormat);
} catch(IllegalArgumentException e) {
Util.report("Bad date format in " + CONFIGURATION_FILE + "; reverting to default", e);
// If the format pattern is invalid - use the default format
dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
dateFormatter = new SimpleDateFormat(dateTimeFormat);
}
}
}
systemPrefix + "showdatetime" is org.slf4j.simplelogger.showdatetime
When I try write org.slf4j.simplelogger.showdatetime=true to simplelogger.properties, It works normally. I hope it can help some people.

Related

How can I read different log4j.properties file depending on an argument in Spring?

With the same code, I want to run it both as a real mode and a dev mode.
So I added a service-mode argument, and it decides the port, database name, etc.
I also want to make a log file for a dev mode.
But using log4j, it seems that configuration about logging is decided when app is started.
Is there a way to change the log file path depending on a given argument?
I expected something like:
// Main.java
if (args.serviceMode is real) {
setLogging(log4j.properties)
}
else {
setLogging(log4j.properties.dev)
}
or
// log4j.properties
log4j.appender.file.File=/path/to/real/log
log4jdev.appender.file.File=/path/to/dev/log
// Main.java
if (args.serviceMode is real) {
setLogPath(log4j.appender.file.File)
}
else {
setLogPath(log4jdev.appender.file.File)
}
Any link or comment appreciated.
You can add spring.profiles in your application.yml and set new log-name
spring.profiles: dev
logging.file: new-app.log
More information you can find get here

Flogger [google] how to config log format and log file

I wanted to log exception into log file instead of console.
How to configure Flogger logging.
package renameform;
import com.google.common.flogger.FluentLogger;
public class TestFlogger {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
public static void main(String[] args) {
try {
int a=2/0;
}catch(Exception exception)
{
logger.atInfo().withCause(exception).log("Log message with: %s", 200);
}
}
}
output:
May 30, 2019 2:16:00 PM renameform.TestFlogger main
INFO: Log message with: 200
java.lang.ArithmeticException: / by zero
at renameform.TestFlogger.main(TestFlogger.java:8)
need so info about logs into text file & how to format.
From the output it looks like flogger is using SimpleFormatter from JUL. The format is controlled by setting the system property or define the key in the logging.properties. The formatter arguments are described in SimpleFormatter::format method. Keep in mind that the arguments in the documentation are off by one so the date parameter is actually %1.
The syntax of the date formatting is described in java.util.Formatter.
You can reference Java Logging - how to redirect output to a custom log file for a logger? as an example on configuring a FileHandler. The configuration file is explained in Java Logging Overview.

Where does the java.util.logging log file or output go?

Update
I've made a mistake that I overlooked throughout. My logging.properties file had a trailing space in the filename that I was not aware of. I've no clue how it got in there, but once I deleted that space everything worked. My problem was that I was providing the wrong name i.e. the filename without the trailing space.
I don’t understand how java.util.logging works. I’m trying to replicate the sample code provided at:
Java Practices -> Logging messages
I first created an empty Java project in Eclipse. I created a class SimpleLogger.java in the package myapp.business. Under resources, I put logging.properties. I don’t have any compilation problems and I can step through the code, but I cannot figure out where does the output go?
SimpleLogger.java looks like:
package myapp.business;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class SimpleLogger {
public static void main(String... args) {
SimpleLogger thing = new SimpleLogger();
thing.doSomething();
}
public void doSomething() {
// Log messages, one for each level
// The actual logging output depends on the configured
// level for this package. Calls to "inapplicable"
// messages are inexpensive.
fLogger.finest("this is finest");
fLogger.finer("this is finer");
fLogger.fine("this is fine");
fLogger.config("this is config");
fLogger.info("this is info");
fLogger.warning("this is a warning");
fLogger.severe("this is severe");
// In the above style, the name of the class and
// method which has generated a message is placed
// in the output on a best-efforts basis only.
// To ensure that this information is always
// included, use the following "precise log"
// style instead :
fLogger.logp(Level.INFO, this.getClass().toString(), "doSomething", "blah");
// For the very common task of logging exceptions, there is a
// method which takes a Throwable :
Throwable ex = new IllegalArgumentException("Some exception text");
fLogger.log(Level.SEVERE, "Some message", ex);
// There are convenience methods for exiting and
// entering a method, which are at Level.FINER :
fLogger.exiting(this.getClass().toString(), "doSomething");
// Display user.home directory, if desired.
// (This is the directory where the log files are generated.)
// System.out.println("user.home dir: " +
// System.getProperty("user.home") );
}
// PRIVATE
// This style has no hard-coded literals, and requires the logger
// to be non-static.
private final Logger fLogger = Logger.getLogger(this.getClass().getPackage().getName());
// This style lets the logger be static, but hard-codes a class literal.
// private static final Logger fLogger =
// Logger.getLogger(SimpleLogger.class.getPackage().getName())
// ;
// This style uses a hard-coded literal and should likely be avoided:
// private static final Logger fLogger = Logger.getLogger("myapp.business");
}
My logging.properties which is in the resources directory looks like:
# Properties file which configures the operation of the JDK
# logging facility.
# The system will look for this config file, first using
# a System property specified at startup:
#
# >java -Djava.util.logging.config.file=myLoggingConfigFilePath
#
# If this property is not specified, then the config file is
# retrieved from its default location at:
#
# JDK_HOME/jre/lib/logging.properties
# Global logging properties.
# ------------------------------------------
# The set of handlers to be loaded upon startup.
# Comma-separated list of class names.
# (? LogManager docs say no comma here, but JDK example has comma.)
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# Loggers and Handlers may override this level
.level=INFO
# Loggers
# ------------------------------------------
# Loggers are usually attached to packages.
# Here, the level for each package is specified.
# The global level is used by default, so levels
# specified here simply act as an override.
myapp.ui.level=ALL
myapp.business.level=CONFIG
myapp.data.level=SEVERE
# Handlers
# -----------------------------------------
# --- ConsoleHandler ---
# Override of global logging level
java.util.logging.ConsoleHandler.level=SEVERE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
# --- FileHandler ---
# Override of global logging level
java.util.logging.FileHandler.level=ALL
# Naming style for the output file:
# (The output file is placed in the directory
# defined by the "user.home" System property.)
java.util.logging.FileHandler.pattern=%h/java%u.log
# Limiting size of output file in bytes:
java.util.logging.FileHandler.limit=50000
# Number of output files to cycle through, by appending an
# integer to the base file name:
java.util.logging.FileHandler.count=1
# Style of output (Simple or XML):
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
In my run configuration in Eclipse, I have my Main class as myapp.business.SimpleLogger and my VM arguments as -Djava.util.logging.config.file=resources/logging.properties
I don't see anything on the console nor can I locate any *.log file. I'm running this on Ubuntu 16.10 if that helps.
Edit: In response to pvg
I've attempted to change the VM argument in Eclipse to: -Djava.util.logging.config.file=/home/myusername/EclipseWorkspace/Temp/resources/logging.properties
I've also tried to call it via the command line in the bin directory:
java -Djava.util.logging.config.file=/home/myusername/EclipseWorkspace/Temp/resources/logging.properties -cp . myapp.business.SimpleLogger
This too does not work i.e. I don't see any output, nor do I see a *.log file anywhere.
For me, it works only if I put the whole path in Eclipse VM arguments:
-Djava.util.logging.config.file=/whole/path/of/logging.properties
Then, the output file will be created according to what's configured in logging.properties file. In this case:
# Naming style for the output file:
# (The output file is placed in the directory
# defined by the "user.home" System property.)
java.util.logging.FileHandler.pattern=%h/java%u.log
The output file will be created in your user's home directory. In my case, the filename created was java0.log - %u means "unique number to resolve conflicts" (a.k.a. an auto-generated number to avoid having files with the same name; in my case, it was 0).
...but I cannot figure out where does the output go?
Use the following code to get the working directory and list the environment which can tell you the home directory. This example also tries to create a file handler using the LogManager settings.
public static void main(String[] args) throws IOException {
System.out.println("Working directory=" + new File(".").getCanonicalPath());
for (Map.Entry<String, String> e : System.getenv().entrySet()) {
System.out.println(e);
}
new FileHandler().close();
}

SimpleFormatter ignoring the java.util.logging.SimpleFormatter.format property

I'm using java.util.logging on GlassFish 4.
I'm defining my own class to initialize the LogManager by defining the System property:
-Djava.util.logging.config.class.
My class loads the logging.properties file, merges it with some other property file and does some custom replacement.
The following is the relevant part of my logging.properties file:
java.util.logging.FileHandler.pattern=C:/Work/server/glassfish/domains/domain1/logs/JMSFileHandler%g.log
java.util.logging.FileHandler.limit=2000000
java.util.logging.FileHandler.count=20
java.util.logging.FileHandler.append=true
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tY:%1$tm:%1$td %1$tH:%1$tM:%1$tS|%4$s: %2$s%n%5$s%n%6$s%n
I'm using the standard FileHandler and configuring it to use the SimpleFormatter as the formatter.
But the java.util.logging.SimpleFormatter.format String is being totally ignored. Instead SimpleFormatter uses its default format.
Where did I go wrong?
From the SimpleFormatter docs you have to test for the following conditions:
If this property is not defined or the given format string is illegal, the default format is implementation-specific.
If this property is set in both the logging properties and system properties, the format string specified in the system property will be used.
This property can be defined in the logging properties configuration file.
Here is a sample test case that you can convert and run under GlassFish.
public static void main(String[] args) throws Exception {
final String format = "%1$tY:%1$tm:%1$td %1$tH:%1$tM:%1$tS|%4$s: %2$s%n%5$s%n%6$s%n";
final String key = "java.util.logging.SimpleFormatter.format";
test(format);
test(System.getProperty(key, format));
test(LogManager.getLogManager().getProperty(key));
FileHandler f = new FileHandler();
System.out.println(f.getFormatter());
f.close();
}
private static void test(String format) {
LogRecord record = new LogRecord(Level.INFO, "");
System.out.println(String.format(format,
new java.util.Date(record.getMillis()),
record.getSourceClassName(),
record.getLoggerName(),
record.getLevel().getLocalizedName(),
record.getMessage(),
String.valueOf(record.getThrown())));
}
You also need to check if GlassFish replaced your SimpleFormatter with the 'com.sun.enterprise.server.logging.UniformLogFormatter'.
private static void findFormatters() {
final ArrayList<Handler> handlers = new ArrayList<>();
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) {
Collections.addAll(handlers, l.getHandlers());
}
}
}
for (Handler h : handlers) {
Formatter f = h.getFormatter();
System.out.println(h.getClass().getName() + "=" + (f == null ? "" : f.getClass().getName()));
}
}
If you need to check access when the system properties are set you can install a security manager with the -Djava.security.debug=access,stack options to trace when the property is set.
I was assuming that the System Property java.util.logging.config.file is set by GF from the beginning. This is not the case.
After some investigation I realized that the LogManager is initialized two times. In the first time that property doesn't exist, the second time it does.
I was getting an error on the first initialization because I was counting on that property, therefore I didn't initialize the LogManager properly, causing the SimpleFormatter to use the default format.
I fixed this by changing my code and no longer counting on that System property. This solved the issue.
GF still sets the System property java.util.logging.config.file later.
I had a similar problem, but it is fixed. I was running my code from an Ant build.xml, and my
java.util.logging.FileHandler.formatter.format property was not being applied from my myLogging.properties file, although other properties were read and applied.
Are you using a JRE version < 1.6.32? Java Bug 55052 indicates that the java.util.logging.FileHandler.formatter.format property is not properly read from the properties file and applied for earlier versions of the JRE.
See: https://issues.apache.org/bugzilla/show_bug.cgi?id=55052
I still compile that project with JDK 1.6.24, but run it with JDK 1.7.0.6, and the formatting is properly read and applied to my logger.
As I can see this post is very old, but I had the same problem and I made some discovery regarding this issue.
SimpleFormatter class stores the format property in a static field, so it initialized only once while calling log(…) method. If you call log(…) method before read the configuration, SimpleFormatter class format field is initialized with default values.
The code below works fine:
LogManager.getLogManager().readConfiguration(configurationStream);
Logger.getLogger(“logger name”).info(“message”);
But code below uses a default formatting (ignores the configuration):
Logger.getLogger(“logger name”).info(“message”);
LogManager.getLogManager().readConfiguration(configurationStream);
Logger.getLogger(“logger name”).info(“message”);
Logger.getLogger(“logger name”).info(“message”);

How do I set log4j level on the command line?

I want to add some log.debug statements to a class I'm working on, and I'd like to see that in output when running the test. I'd like to override the log4j properties on the command line, with something like this:
-Dlog4j.logger.com.mypackage.Thingie=DEBUG
I do this kind of thing frequently. I am specifically only interested in a way to pass this on the command line. I know how to do it with a config file, and that doesn't suit my workflow.
As part of your jvm arguments you can set -Dlog4j.configuration=file:"<FILE_PATH>". Where FILE_PATH is the path of your log4j.properties file.
Please note that as of log4j2, the new system variable to use is log4j.configurationFile and you put in the actual path to the file (i.e. without the file: prefix) and it will automatically load the factory based on the extension of the configuration file:
-Dlog4j.configurationFile=/path/to/log4jconfig.{ext}
These answers actually dissuaded me from trying the simplest possible thing! Simply specify a threshold for an appender (say, "console") in your log4j.configuration like so:
log4j.appender.console.threshold=${my.logging.threshold}
Then, on the command line, include the system property -Dlog4j.info -Dmy.logging.threshold=INFO. I assume that any other property can be parameterized in this way, but this is the easiest way to raise or lower the logging level globally.
With Log4j2, this can be achieved using the following utility method added to your code.
private static void setLogLevel() {
if (Boolean.getBoolean("log4j.debug")) {
Configurator.setLevel(System.getProperty("log4j.logger"), Level.DEBUG);
}
}
You need these imports
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
Now invoke the setLogLevel method in your main() or whereever appropriate and pass command line params -Dlog4j.logger=com.mypackage.Thingie and -Dlog4j.debug=true.
log4j does not support this directly.
As you do not want a configuration file, you most likely use programmatic configuration. I would suggest that you look into scanning all the system properties, and explicitly program what you want based on this.
Based on Thorbjørn Ravn Andersens suggestion I wrote some code that makes this work
Add the following early in the main method and it is now possible to set the log level from the comand line. This have been tested in a project of mine but I'm new to log4j and might have made some mistake. If so please correct me.
Logger.getRootLogger().setLevel(Level.WARN);
HashMap<String,Level> logLevels=new HashMap<String,Level>();
logLevels.put("ALL",Level.ALL);
logLevels.put("TRACE",Level.TRACE);
logLevels.put("DEBUG",Level.DEBUG);
logLevels.put("INFO",Level.INFO);
logLevels.put("WARN",Level.WARN);
logLevels.put("ERROR",Level.ERROR);
logLevels.put("FATAL",Level.FATAL);
logLevels.put("OFF",Level.OFF);
for(String name:System.getProperties().stringPropertyNames()){
String logger="log4j.logger.";
if(name.startsWith(logger)){
String loggerName=name.substring(logger.length());
String loggerValue=System.getProperty(name);
if(logLevels.containsKey(loggerValue))
Logger.getLogger(loggerName).setLevel(logLevels.get(loggerValue));
else
Logger.getRootLogger().warn("unknown log4j logg level on comand line: "+loggerValue);
}
}
In my pretty standard setup I've been seeing the following work well when passed in as VM Option (commandline before class in Java, or VM Option in an IDE):
-Droot.log.level=TRACE
Based on #lijat, here is a simplified implementation. In my spring-based application I simply load this as a bean.
public static void configureLog4jFromSystemProperties()
{
final String LOGGER_PREFIX = "log4j.logger.";
for(String propertyName : System.getProperties().stringPropertyNames())
{
if (propertyName.startsWith(LOGGER_PREFIX)) {
String loggerName = propertyName.substring(LOGGER_PREFIX.length());
String levelName = System.getProperty(propertyName, "");
Level level = Level.toLevel(levelName); // defaults to DEBUG
if (!"".equals(levelName) && !levelName.toUpperCase().equals(level.toString())) {
logger.error("Skipping unrecognized log4j log level " + levelName + ": -D" + propertyName + "=" + levelName);
continue;
}
logger.info("Setting " + loggerName + " => " + level.toString());
Logger.getLogger(loggerName).setLevel(level);
}
}
}

Categories

Resources