SLF4J logging, different Levels - java

In SLF4J (Logging) how levels are different in characteristic. i.e. How ERROR message is different than DEBUG message.
import org.apache.log4j.Logger;
public class LogClass {
private static org.apache.log4j.Logger log = Logger.getLogger(LogClass.class);
public static void main(String[] args) {
log.trace("Trace Message!")
log.debug("Debug Message!");
log.info("Info Message!");
log.warn("Warn Message!");
log.error("Error Message!");
log.fatal("Fatal Message!");
}
}
The Output is same regardless of Level, is there any difference in implementation:
Debug Message!
Info Message!
Warn Message!
Error Message!
Fatal Message!
If these levels are producing the same kind of messages then why the implementation didn't have only one method with parameter as level.
Something like:
log("Level","msg");

Starting from the bottom, there's no real benefit to have a log(level, msg) method if you already have all the different methods for all the possible levels. Only if you'd need to log the same message in different levels, but that's a bad practice, since that message should clearly fall into one specific category. And you can always choose how much logging you get out by specifying the level globally or at the package/class.
The message are exactly the same on each level, the only difference is if that message is gonna make to the logging output or not, based on your configuration, and what purpose do you give to each level.

The key purpose to name them levels is to enable you to debug at various levels. Say for example,
INFO level can used to log high level information on the progress of the application during execution.
DEBUG level logged is meant to be even deeper than just high level information. At DEBUG level, you can have more information logged that can include information of what is happening at a module level or component level.
TRACE level is even more granular. You can log message like entering and exiting a method and what information is being returned by each method.
ERROR level is to purely meant to log only errors and exception
You need to be mindful of what kind of message can be logged into their respective level.
To answer your question, these levels can be controlled in log4j.properties or log4j.xml. You can specify at what level the application can debug. If everything goes well in application, I would leave it at INFO level. If something goes wrong and I wanted to dig in deepeur in terms of debugging, I would try to turn on at DEBUG level or TRACE level.
Also, understand that when you run the debugging at DEBUG level, even the INFO level logs will be printed. If you turn on the debugged at TRACE level, even the DEBUG and INFO level logs will be printed. If you turn on debugging at INFO level, only INFO level logs will be printed.
I hope you got some clarify.

Because it is easier to use for you as a user. As the implementation, it might have that very code.

Related

Differences between error methods in log4j 1.x

In the logging part of the project I working for, I try to optimize the error messages that are shown in log management. Logging error messages is coded like this:
String errorMessage =" Problem with server "+"\n"+t.getMessage();
_logger.fatal(errorMessage);
Where t is a Throwable object and _logger is a Logger object, which is related to the log4j framework.
What I wonder is, what changes if I use _logger.fatal(errorMessage, t); instead of _logger.fatal(errorMessage);? If there is a major difference between them, Which one will be better to use?
Edit: I've just realised I copied "fatal" example instead of "error". However my question is same for fatal, too.
Practically all Java logging framework (alas, we have plenty of those...) support putting a Throwable as the last parameter.
This will result in a stack trace being logged, which can be extremely useful in diagnosing and fixing the problem.
I'd only ever not give the exception to the logger if the cause of the exception is really well established and printing the exception is just unnecessary noise. For example here:
try {
int port = Integer.parseInt(input);
// do something with the port
} catch (NumberFormatException e) {
logger.error("'{}' is not a valid port number: {}", input, e.toString);
}
Another case is when the exception is being re-thrown (and something else will eventually log it with more detail).
But not with a "Problem with server" (and at FATAL level no less). That looks like you want to get as much info as you can get.
Also note that in those cases, e.toString() is usually better than e.getMessage() because it also includes the name of the exception in addition to its message (which may be empty).

Log4j2, set log level at runtime for Thread specific

We have a webserver and multiple users log in to it. We generally put log level to ERROR or INFO level. But sometimes, for debugging purpose, we need to see logs. There is one way to set it at runtime, but this process is not so good in case of loads of traffic. Important logs will be missed and also we don't know for how much time we need to keep it that way. I have written a wrapper in log4j v1.2, which just ignores the level check if userid belongs to some TestUsersList. So, it opens all logs for a particular user[a thread] only. A snippet is below-
public void trace(Object message) {
Object diagValue = MDC.get(LoggerConstants.IS_ANALYZER_NUMBER);
if (valueToMatch.equals(diagValue)) { // Some condition to check test number
forcedLog(FQCN, Level.TRACE, message, null);
return;
}
if (repository.isDisabled(Level.TRACE_INT))
return;
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel()))
forcedLog(FQCN, Level.TRACE, message, null);
}
But now I have moved to log4j2, I don't want to write this wrapper again. Is there any inbuilt functionality which log4j2 provides for this?
This can be done with filters. Add a logger to the configuration that logs all the messages you want, then add a ThreadContextMapFilter that has a KeyValuePair for each user you want to log.
Then put the user ids in the Thread Context within the code.

How to configure Camel's RedeliveryPolicy retriesExhaustedLogLevel?

I have set up an errorHandler in a Camel route that will retry a message several times before sending the message to a dead letter channel (an activemq queue in this case). What I would like is to see an ERROR log when the message failed to be retried the max number of times and was then sent to the dead letter queue.
Looking at the docs for error handling and dead letter channels, it seems that there are 2 options available on the RedeliveryPolicy: retriesAttemptedLogLevel and retriesExhaustedLogLevel. Supposedly by default the retriesExhaustedLogLevel is already set at LoggingLevel.ERROR, but it does not appear to actually log anything when it has expended all retries and routes the message to the dead letter channel.
Here is my errorHandler definition via Java DSL.
.errorHandler(this.deadLetterChannel(MY_ACTIVE_MQ_DEAD_LETTER)
.useOriginalMessage()
.maximumRedeliveries(3)
.useExponentialBackOff()
.retriesExhaustedLogLevel(LoggingLevel.ERROR)
.retryAttemptedLogLevel(LoggingLevel.WARN))
I have explicitly set the level to ERROR now and it still does not appear to log out anything (to any logging level). On the other hand, retryAttemptedLogLevel is working just fine and will log to the appropriate LoggingLevel (ie, I could set retryAttemptedLogLevel to LoggingLevel.ERROR and see the retries as ERROR logs). However I only want a single ERROR log in the event of exhaustion, instead of an ERROR log for each retry when a subsequent retry could potentially succeed.
Maybe I am missing something, but it seems that the retriesExhaustedLogLevel does not do anything...or does not log anything if the ErrorHandler is configured as a DeadLetterChannel. Is there a configuration that I am still needing, or does this feature of RedeliveryPolicy not execute for this specific ErrorHandlerFactory?
I could also set up a route to send my exhausted messages that simply logs and routes to my dead letter channel, but I would prefer to try and use what is already built into the ErrorHandler if possible.
Updated the ErrorHandler's DeadLetterChannel to be a direct endpoint. Left the 2 logLevel configs the same. I got the 3 retry attempted WARN logs, but no ERROR log telling me the retries were exhausted. I did, however, set up a small route listening to the direct dead letter endpoint that logs, and that is working.
Not a direct solution to my desire to have the ERROR log work for the exhaustion, but is an acceptable workaround for now.
Please try with this code:
.errorHandler(deadLetterChannel("kafka:sample-dead-topic")
.maximumRedeliveries(4).redeliveryDelay(60000)
.retriesExhaustedLogLevel(LoggingLevel.WARN)
.retryAttemptedLogLevel( LoggingLevel.WARN)
.retriesExhaustedLogLevel(LoggingLevel.ERROR)
.logHandled(true)
.allowRedeliveryWhileStopping(true)
.logRetryStackTrace(true)
.logExhausted(true)
.logStackTrace(true)
.logExhaustedMessageBody(true)
)
retry is configured for 1 minute interval.
Camel application logged the errors for evry retry with the detailed information.

Hornetq embedded, Couldn't find any bindings for address

I'm using an embedded HornetQ instance from within a JUnit test case.
Somehow I can't get my test driver to deliver a message onto the bus. There is no exception or anything that says that the message bus wasn't working or properly set up(see [1]).
Only when I run the test case in debug mode I'm seeing some traces starting with "Couldn't find any bindings for address..." (see [2]).
Is this trace message something that can be ignored? "No binding" sounds to me like there could be no hornetq available at all.
[1]
Q221007: Server is now live
[FF] [ScalaTest-run] [2014-06-11 15:03:03,555 INFO] HornetQServerImpl.java:460 - HQ221001: HornetQ Server version 2.5.0.SNAPSHOT (Wild Hornet, 124) [ea2511b0-e5c6-11e3-a213-b1fcc2ec9262]
[2]
Couldn't find any bindings for address=hornetq.notifications on message=ServerMessage[messageID=5,durable=true,userID=null,priority=0, bodySize=512,expiration=0, durable=true, address=hornetq.notifications,properties=TypedProperties[{_HQ_User=null, _HQ_NotifTimestamp=1402491783941, _HQ_Distance=0, _HQ_SessionName=b9525487-f168-11e3-8314-fb544e2d7270, _HQ_NotifType=CONSUMER_CREATED, _HQ_Address=xxx.messaging.RequestMessage-integ-test, _HQ_ClusterName=d78dbd27-bfe8-47f9-8b51-06c4eeb63543-integ-testea2511b0-e5c6-11e3-a213-b1fcc2ec9262, _HQ_RoutingName=d78dbd27-bfe8-47f9-8b51-06c4eeb63543-integ-test, _HQ_ConsumerCount=1, _HQ_RemoteAddress=invm:0}]]#1086110741
[FF] [Thread-0 (HornetQ-remoting-threads-HornetQServerImpl::serverUUID=ea2511b0-e5c6-11e3-a213-b1fcc2ec9262-1032009487-1905514837)] [2014-06-11 15:03:03,942 DEBUG] PostOfficeImpl.java:685 - Message ServerMessage[messageID=5,durable=true,userID=null,priority=0, bodySize=512,expiration=0, durable=true, address=hornetq.notifications,properties=TypedProperties[{_HQ_User=null, _HQ_NotifTimestamp=1402491783941, _HQ_Distance=0, _HQ_SessionName=b9525487-f168-11e3-8314-fb544e2d7270, _HQ_NotifType=CONSUMER_CREATED, _HQ_Address=xxx.messaging.RequestMessage-integ-test, _HQ_ClusterName=d78dbd27-bfe8-47f9-8b51-06c4eeb63543-integ-testea2511b0-e5c6-11e3-a213-b1fcc2ec9262, _HQ_RoutingName=d78dbd27-bfe8-47f9-8b51-06c4eeb63543-integ-test, _HQ_ConsumerCount=1, _HQ_RemoteAddress=invm:0}]]#1086110741 is not going anywhere as it didn't have a binding on address:hornetq.notifications
This specific code is just a Log.debug.
Couldn't find any bindings for address=hornetq.notifications on...
We send notifications for things that happen on the servers, and you won't always have a listener for these notifications. on this case the notification message is just not being routed as you have no consumers.. which is perfectly fine. This has nothing to do with the error you're having... it's irrelevant. You should look for other clues on your test. I'm not giving this as an answer as it doesn't answer your question. I don't have enough info to do it.
I would need more information to answer exactly why you're not receiving messages on your test.. but this specific message you posted has no direct relation.

can we change the logging level of log4j at runtime

i have an issue, i want to change the logging level of log4j at runtime, i have tried many things with log4j.properties file, i have also tried to written a code which after particular time again reads the properties file and again configure the logger.
but the problem is, i want to change the logging level to DEBUG for one API call, and then when that call is completed, the logger should again change to the previous value..
please help..
Calling the Logger.setLevel method with the desired Level can alter a Logger's output level at runtime.
The following is an example which demonstrates its usage:
Logger logger = Logger.getLogger("myLogger");
logger.addAppender(new ConsoleAppender(new SimpleLayout()));
System.out.println("*** The current level will be INFO");
logger.setLevel(Level.INFO);
logger.warn("Only INFO and higher will appear");
logger.info("Only INFO and higher will appear");
logger.debug("Only INFO and higher will appear");
System.out.println("*** Changing level to DEBUG");
// remember the previous level
Level previousLevel = logger.getLevel();
logger.setLevel(Level.DEBUG);
logger.warn("DEBUG and higher will appear");
logger.info("DEBUG and higher will appear");
logger.debug("DEBUG and higher will appear");
System.out.println("*** Changing level back to previous level");
// revert to previous level
logger.setLevel(previousLevel);
logger.warn("Only INFO and higher will appear");
logger.info("Only INFO and higher will appear");
logger.debug("Only INFO and higher will appear");
The above outputs:
*** The current level will be INFO
WARN - Only INFO and higher will appear
INFO - Only INFO and higher will appear
*** Changing level to DEBUG
WARN - DEBUG and higher will appear
INFO - DEBUG and higher will appear
DEBUG - DEBUG and higher will appear
*** Changing level back to previous level
WARN - Only INFO and higher will appear
INFO - Only INFO and higher will appear
The above demonstrates how to change the level of one Logger named myLogger, but if the levels of all the loggers in the current repository should be changed, then the setLevel method on the root logger obtained by Logger.getRootLogger should be called to change the levels on all the child loggers.
The log level of a logger can be changed by calling setLevel as described by #coobird. However, there is a catch!
When you call getLogger(name), the logging library will return you an existing Logger object if possible. If two or more threads request a logger with the same name, they will get the same object. If one of the threads calls setLevel, this will change the logger level for all of the others. That can lead to unexpected behavior.
If you really need to do this kind of thing, a better approach would be to create a logger with a different name for the case where you want to logging at a different level.
However, I'm not convinced of the wisdom of the application calling setLevel at all. The setLevel method is about filtering the log messages, and you should not be wresting control of logging filtering away from the user / deployer.
I think it makes sense to call setLevel if a server has a "Controller" thread. That way, you can dynamically change logging level at runtime to debug an issue, and change it back when you are done.
But I don't know what happens when it is called from a separate thread.
setLevel method is there only for java.util.logging.Logger and not for org.apache.logging.log4j.Logger
This is how we set log level in apache log4j
org.apache.logging.log4j.core.LoggerContext
ctx = (LoggerContext) LogManager.getContext(false);
org.apache.logging.log4j.core.config.Configuration
conf = ctx.getConfiguration();
conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(Level.DEBUG);
ctx.updateLoggers(conf);
If you are using Spring Boot (1.5+), you can use logger endpoint to POST desired logging level.

Categories