How to customize the default java logging? - java

I need to have custom log levels(other than java.util.logging.Level), and custom functions in the java util logger to log messages of these levels.
Custom levels:
1. DEBUG
2. ERROR
3. FATAL
So I created XYZLevel extended from Level as follows:
public class OKILevel extends Level {
public OKILevel(String name, int value) {
super(name, value);
}
/* OKI Log Levels */
public static final Level FATAL = new OKILevel("FATAL",
Level.SEVERE.intValue() + 100);
public static final Level ERROR = new OKILevel("ERROR",
Level.SEVERE.intValue());
public static final Level DEBUG = new OKILevel("DEBUG",
Level.FINE.intValue());
}
Custom functions required:
.debug(), .severe() etc similar to .info in logger.
For logger I do:
static final Logger logger = Logger.getLogger(ABC.class.getName());
I am unable to figure out:
static final XYZLogger logger = XYZLogger.getLogger(ABC.class.getName());
extending the Logger doesn't help.
Also, for this application the logging.properties need to be passed in.
How do I use these new levels in .level of logging.properties?

If you are creating log wrapper then you should leverage some of the standard frameworks before inventing something new.
If you want your application to use a new logger implementation then you have to implement and install a custom LogManager.
Also, for this application the logging.properties need to be passed in. How do I use these new levels in .level of logging.properties?
All of the .level parsing performed via the
Level.parse method. Per the docs:
The argument string may consist of either a level name or an integer value.
For example:
"SEVERE"
"1000"
So you should be able to write:
#Level.SEVERE + 100 = FATAL
some.logger.name.level = 1100
That said there are some known issues with finding the correct level value by int in some releases of Java.
Another option if you just want the rendered output of a level to be different then you should have a look at Best way to override java.util.logging Level class to change the level strings.

Related

Append column to QuickFix/J Logs database (Custom QuickFix/J Logger)

QuickFix/J provides functionality to store its logs in database.
Is it possible to append another column (business ID) to one of its table in such a way that it does not cause problems in QuickFix/J's internal message logging?
If it is possible kindly mention the procedure to do it too.
The solution is to create your own Logger and LoggerFactory similar to the ones provided by QuickFix/J.
You can create a Logger by implementing the "quickfix.Log" interface, and a LoggerFactory by implementing the "quickfix.LogFactory" interface.
The easiest approach would be to use the private AbstractLog from QuickFix/J.
Creating the Log class:
Copy the AbstractLog class as it is from QuickFix/J's source and include it in your project.
Create a class which extends the AbstractLog class and implement all the abstract methods.
Create member variables for any extra field you want to append to the logs (e.g. business ID), and provide a constructor which takes is
as an argument and sets its value.
The "logIncoming" and "logOutgoing" methods take a String parameter. This is the data you want to log. At this point you can
append your own fields (added in point 3) to the logs. You can format
the log as you wish and you are free to use any method of output, i.e.
Console, database etc. as you will have to implement it yourself.
Creating the LoggerFactory:
Create a LoggerFactory that implements the quickfix.LogFactory interface.
In the "create" method, create and return the instance of the Logger you created before using the constructor you require.
The values that you need to be passed to the constructor can be kept as member variables of the LoggerFactory and set in
LoggerFactory's constructor.
You have a custom Logger now and can use it as QuickFix/J's own loggers are used, and QuickFix/J will automatically log using your logger.
ApplicationAdapter application = new FixInitiator();
SessionSettings settings = new SessionSettings("./config/initiator.cfg");
CustomLogFactory customLogFactory = new CustomLogFactory(settings, myCustomID);
DefaultMessageFactory messageFactory = new DefaultMessageFactory();
FileStoreFactory fileStoreFactory = new FileStoreFactory(settings);
socketInitiator = new SocketInitiator(application, fileStoreFactory, settings, customLogFactory, messageFactory);
socketInitiator.start();
Taking a look at QuickFix/J's own Logger and LoggerFactory implementations for help would be a good idea.
e.g. The Logger that Logs on Console: ScreenLog, ScreenLogFactory
QuickFix/J source:
https://github.com/quickfix-j/quickfixj

Add a static prefix to everylogged message with slf4j

Is there a way to add a static (not context dynamic) prefix to all logged messages when using slf4j without altering the formatting of the underlying logging framework? To be clear, that means that using MDC is not an option because this would need to be reflected in the formatting configuration of the underlying framework.
Is there another option than creating a custom wrapper for the slf4j logger and using it wherever I would normally simply initialize a slf4j logger?
public class CustomLogger {
private final String prefix = "custom-prefix";
private final Logger logger;
public CustomLogger(Class clazz) {
logger = LoggerFactory.getLogger(clazz);
}
public void info(String info) {
logger.info (prefix + info);
}
// other methods...
}
If some context is needed: I am working in an environment where multiple plugins run on a core application. Within such a plugin I would like to add the plugin's name as a prefix to logged messages.
Wrap your calls in another method that does a String.format(...) on the passed in String. Your formatter will have your static string, and will place the logging string somewhere before, within, or after that, before passing it onto the actual logger method.

how to set LogManager.getLogManager().readConfiguration once for whole project using java util logger?

In my project for every class having log messages like
Logger.getLogger("LoggingExample.class").info("Logging an INFO-level message");
how to specify common LogManager.getLogManager().readConfiguration at
one place instead of writing configuration for every file.
For java util logger it is default logging.properties taking from
java home directory i don't want to maintain properties file in java home directory i
want to maintain it with in project folder how to do this in java util logger
You do not need to create a logger every time. As java.util.Logger is thread safe, it is feasible to declare it only once and use it every time. Below is an example:
private static final Logger myLog = Logger.getLogger("loggerName");
myLog .warn("Text");
Best practice is to use one logger per class. And if it does not involve more efforts then, I would advise to use log4j framework.
You'll want to hold a strong reference to a logger so you don't lose your configuration changes. Here is a modified example taken from the Java Logging Overview:
public class Nose {
// Obtain a suitable logger.
private static final String CLASS_NAME = Nose.class.getName();
private static final Logger logger = Logger.getLogger(CLASS_NAME);
public static void main(String argv[]) {
// Log a FINE tracing message
logger.fine("doing stuff");
try{
Wombat.sneeze();
} catch (Exception ex) {
// Log the exception
logger.log(Level.WARNING, "trouble sneezing", ex);
}
logger.fine("done");
}
}
If you want to use a custom configuration file you can specify the 'java.util.logging.config.file' system property to point to path of your properties file. This is explained in detail in the LogManager documentation.

Custom Log Level

In my existing application "org.apache.log4j" API's have been used in java code.
Requirement :
I have to log some statement(say xyz) in log file in any case and should not dependent of log levels.For example : if my log level is error then also xyz should print, if my log level is debug then also xyz should print.
I cannot make log statement of xyz is debug because if i do this, other log statements apart from xyz will also start printing.
For this, I believe, I have to add some custom log level.Please help how to do it and how to set its level ordering so that in any case it should print.
Thanks in advance.
Best Regards
What you could do is create a different Logger for those statements (you are not restricted to use classes names when defining a logger)
// Standard logger
private static Logger log = Logger.getLogger(MyClass.class)
// XYZ logger
private static Logger logXYZ = Logger.getLogger("logs.xyz");
You can access the same logger from several class, you just have to pass the same label.
Then, in the configuration file, you can define a different log level for that category, and even output these logs in a different appender (different file, processing, etc.)
You could "hijack" the protected method Logger#forcedLog() to always print to the log.
You must place the hijacker class in the same package as Logger.
package org.apache.log4j;
/**
* #author maba, 2012-08-23
*/
public class LogOverride {
public static void print(Logger logger, String message) {
logger.forcedLog(logger.getName(), Priority.INFO, message, null);
}
}
And from your calling code
log.setLevel(Level.OFF); // Make sure logging is turned off
log.info("Normal logging"); // Will not be seen anywhere
LogOverride.print(log, "Overriding logger"); // Will still make it to your appender
This is what the log4j FAQ says about custom levels:
How do I add a custom level?
It is possible, but rarely appropriate. The request is commonly for a level named something like "audit" that doesn't obviously fit in the progression "trace", "debug", "info", "warn", "error" and "fatal". In that case, the request for a level is really a request for a mechanism to specify a different audience. The appropriate mechanism is to use a distinct logger name (or tree) for "audit" related messages.
So if you want to go with that suggestion then you should look at the answer from SJuan76.
If you do decide to go with the idea of creating a custom, you would need to create a subclass of Level to do this, because the Level constructor is protected.
/**
* Instantiate a Level object.
*/
protected Level(int level, String levelStr, int syslogEquivalent) {
super(level, levelStr, syslogEquivalent);
}
It looks like you should then chain to the Level constructor, passing it a suitable level value. Note that the larger the level number the higher the priority is. So for a Level that won't be blocked at any of the existing named levels, you want a value that is greater than Priority.FATAL_INT which is 50000.
(However, I'm not convinced that this is the right approach. For a start, you probably won't be able to refer to your custom level by name in a logging config file.)

Accessing a logger in a Java application

I have a question regarding logging in a Java application. I want to log the main user actions and possible errors with user friendly messages. Therefore, I have two appenders for the logger: one shows errors (level = error) in dialogs and the other writes the logs of the current user session into an html-file so that the user could send this file back if something goes wrong.
To avoid having the logger creation in every class (private Logger logger = …) I have a static reference of the configured logger in a class App which has also the methods for accessing the logger:
public class App {
private static Logger logger = Logger.getLogger("logger name");
…
public static void logError(String message, Throwable cause) {
…
}
public static void logInfo(String message) {
…
}
}
The logging is mainly done in the UI classes:
class UIWidget extends UIFrameworkWidget {
void aMethod() {
try {
someBusinessLogic();
} catch (Exception e) {
App.logError(“log message”, e);
}
}
}
Is this a good practice? (Note that the widgets are created by the framework.)
Thanks in advance for answers, comments, or hints on this
Better would be to use a single static Logger instance but allow each class to create a private instance which is initialized with the name of the class (and maybe other info). This private instance then uses the static instance to actually perform its logging but can be omitted if necessary and reduces references to external classes.
This is how slf4j does it, which is a logging framework you should consider using - however you could roll your own in the same manner.
Note, however I don't know how to get your error messages to be displayed within a dialog box - that may need to be explicitly added.
It seems you're just one step away of subclassing the JDK Logger. Having only one static instance prevents you from targeting specific classes at runtime. If you subclass the Logger, then you can still have has many loggers as logged classes and yet keep your appender's peculiarities.
You can also craft your own layout (and, in log4j at least, even add placeholders - geronimo has an example of this).

Categories

Resources