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.
Related
I use JRuby and have a Rake task that calls a Java function. This Rake task uses ActiveSupport::Logger to log messages.
log = ActiveSupport::Logger.new('log/my_log.log')
log.info 'A message for the ruby logger'
Later I call a Java function.
obj = JavaThing.new
results = obj.callJavaFunction
The callJavaFunction() method then does some logging of its own.
public class JavaThing {
private static final Logger log = Logger.getLogger('com.stuff.thing');
public void callJavaFunction() {
// do stuff
log.info('A message for the Java logger');
}
}
'A message for the ruby logger' is output to my_log.log.
'INFO: A message for the Java logger' is output to the console when I run the Rake task.
I cannot modify the Java code. How do I save the message that comes from the Java function to a file?
I've tried rake my:task > java_log.log but this only catches console output generated by Rails.
I am using JRuby 1.7.16 and Rails 4.1.4.
I'm unsure if there will be any effect on my code due to the fact that Ruby is involved (no experience in that), but you could give the following a try. Do note that I originally wrote it as part of a JUnit test for logging (with #Before), so you will need to do some adjustments to work for your case.
Basically, what it is doing is to also direct the logging to the txt file (Logging.txt in this case) from the console. It will still print to the console.
private final static Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
public void loggerSetup() {
try {
fileTxt = new FileHandler("Logging.txt");
} catch (SecurityException | IOException e) {
logger.warning("Filehandler not functional");
}
logger.addHandler(fileTxt);
SimpleFormatter formatterTxt = new SimpleFormatter();
fileTxt.setFormatter(formatterTxt);
}
If you want to remove the console printing as well, something similar to the below might work. All of the logging will then be saved in the file only, as the console printing is overwritten and sent to the file.
Logger rootLogger = Logger.getLogger("");
Handler[] handlers = rootLogger.getHandlers();
if (handlers[0] instanceof ConsoleHandler) {
rootLogger.removeHandler(handlers[0]);
}
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”);
I'm using the SimpleLogger binding for SLF4J 1.7.5. As per the docs I can use the org.slf4j.simpleLogger.logFile property in my simplelogger.properties file to specify a log file OR System.out OR System.err.
However I want to send log messages to BOTH System.out AND a log file. Does anyone know how to achieve this using SimpleLogger please? (I'm using Windows so cannot use tail -f simply to follow the log file in a console window; nor do I want to get a third party utility which emulates 'tail -f' in Windows.)
Short Answer You can't do that with SimipleLogger.
More AnswerGive up on SimpleLogger and move on to something else. You have options:
Instead of using slf4j-simple-1.x.x.jar get logback (logback-classic.jar and logback-core.jar). With logback you can define two appenders; one for the file output and one for console (also-known-as System.out) output.
Instead of using slf4j-simple.1.x.x.jar get xxx (substitute any logging system supported by slf4j) and blah blah blah (do the same as in 1 obove).
SLF4j is open source; derive your own logger (lets call it TeeLogger) that logs to System.out and a file.
Create a logging class that that sits in front of SLF4j (in your application). Have it take a Logger and a messasge then have it write the message to System.out and the Logger.
Something that I have not though about.
Here is a (super simplistic) example of #4 above:
import org.slf4j.Logger;
public class LoggyLoo
{
public static void logZoreInfo(
final Logger logger,
final String message)
{
System.out.println(message);
logger.info(message);
}
}
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.
i Wrote a map reduce code that i want to debug.
in order to do so i cant use standard output, because the Hadoop platform doesn't print it to the screen unless an error occurs.
instead i tried to use logger, in order to create log file.
i split it to two files using a handler, unfortunately the "severe" log file comes out empty and the general log file only logs things that happens in the main thread and not in the map reduce functions.
the question is as follows:
is there an issue with hadoop and log files or is it a problem with my configuration of the logger? if so how to correct it.
the log configuration code:
i use the one logger for the entire application (this time root logger)
public static Logger configureLogging()
{
try
{
logger=Logger.getLogger("");
//FileSystem hdfs=FileSystem.get(URI.create(Misc.S3FS),getConfiguration());
logger.setLevel(Level.ALL);
//StreamHandler handler=new StreamHandler(hdfs.create(new Path(Misc.LOGS_PATH+"mylog.log")),new SimpleFormatter());
FileHandler handler=new FileHandler(Misc.LOGS_PATH+"mylog.xml",true);
FileHandler severeHandler=new FileHandler(Misc.LOGS_PATH+"mylogSevere.xml",true);
severeHandler.setLevel(Level.INFO);
logger.addHandler(handler);
logger.addHandler(severeHandler);
}
catch (Exception e)
{
e.printStackTrace();
}
return logger;
}
Hadoop comes with preconfigured log4j. All you have to do is import two classes:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
And now you can define logger inside your mappers, reducers and wherever you want:
private static final Log LOG = LogFactory.getLog(MyClass.class);
And log what you need:
LOG.info("My message");
The messages will show up during job execution. You can tweak log4j configuration with
conf/log4j.properties