Not able to call method "error" from the logger object. - java

package firstAOP;
import java.util.logging.Logger;
public class OrderDAO
{
private final static Logger logger = Logger.getLogger(OrderDAO.class.getName());
public boolean saveOrder(Order order)
{
boolean flag =false;
try
{
//functional code
flag = true;
}
catch(Exception e)
{
logger.error(e);
}
return flag;
}
}
In the above code I get an error in the line "logger.error(e)"
This is the error:
The method error() is undefined for the type Logger
Rest of the methods like logger.info are working.
And if it is not too much to ask can you please tell me have I declared logger correctly. And what will happen if I write:
private final static Logger logger = Logger.getLogger(SaveOrder.class.getName());
SaveOrder is another class in the same package.

You are using java.util.logging.Logger and this logger has no error() method.
Either use
Logger.log(Level, String);
Logger.log(Level, String, Throwable);
with one of the levels defined in java.util.logging.Level
or
Logger.severe(String);
... to your second question:
The logger is declared well.
If you change the logger declaration to
private final static Logger logger = Logger.getLogger(SaveOrder.class.getName());
then the logger will have another name. The name is used when you configure the logging system. I would suggest you to read the Java Logging Overview and come back when you have a particular question about the java logging system.

Another alternative:
Try this add below import:
import org.apache.log4j.Logger;
and remove
import java.util.logging.Logger;
LOG.error(e.getMessage(),e);
Another example :
LOG.error("Error in loading the product data for Mass Request : = " + requestId);
example with info level logging:
LOG.info("Loading the product data...for " + requestId);

Related

Write the log in to existing common log file using slf4j

I have multiple services and each one of them interacting with each other. There is common.log file where I am writing the common log in to this file. logback.xml entry for this common.log is present in to another service lets name it as Service1. I want to write the some common things in to this existing common.log file using slf4j.
I tried to write a utility class to write the log from Service2 application to common.log and using the java.util.logging package as below ,
public class LogUtil {
private static LogUtil instance = new LogUtil();
public static LogUtil getInstance() {
return instance;
}
private static final Logger logger = Logger.getLogger(LogUtil.class.getName());
static {
try {
String logFile = System.getProperty("home") + "/logs/common.log";
FileHandler fh = new FileHandler(logFile, true);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
logger.addHandler(fh);
} catch (Exception e) {
e.printStackTrace();
}
}
public void error(String msg) {
logger.log(Level.SEVERE,"[Error Common] :"+msg);
}
}
I want to do it using the slf4j api. Please suggest me some approach to write the utility class using slf4j.

How to Override Client Side Soap Logging - Spring Boot

I'm consuming a soap webservice inside a spring boot application. The response/request logging is too big, because of one attribute which is too large. So I want to intercept that logging and remove the offending attribute.
I've been messing about with SoapEnvelopeLoggingInterceptor, but i think that is just for Server side logging. It will not get picked up.
I have configured my soap logging inside yml as follows:
logging:
pattern:
...
level:
...
org.springframework.ws.client.MessageTracing.sent: TRACE
org.springframework.ws.client.MessageTracing.received: TRACE
org.springframework.ws.server.MessageTracing: DEBUG
That works fine for logging both request and response, but I need to remove a very large problematic attribute from the envelope. Any ideas?
You can extend ClientInterceptorAdapter the abstract implementation ClientInterceptors and oveeride handleRequest and handleResponse to parse, modify and log your custom message.
The below code delegates to AbstractLoggingInterceptor handleRequest and handleResponse and overrides the logMessage to create a custom message.
Something like
public class MyInterceptor extend ClientInterceptorAdapter {
private final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
private EndpointInterceptor endpointInterceptor = new AbstractLoggingInterceptor() {
#Override
protected Source getSource(WebServiceMessage webServiceMessage) {
// Base logic same as SoapEnvelopeLoggingInterceptor getSource method.You can adjust to your preference.
if(webServiceMessage instanceof SoapMessage) {
SoapMessage soapMessage = (SoapMessage)webServiceMessage;
return soapMessage.getEnvelope().getSource();
} else {
return null;
}
}
#Override
protected void logMessage(String message) {
// You can use your regex to remove the attribute and log the message.
this.logger.debug(message);
}
};
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
return endpointInterceptor.handleRequest(messageContext, null);
}
#Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
return endpointInterceptor.handleResponse(messageContext, null);
}
}
There is no simple way of doing that. You ether implement your own Logger by extending sl4j API or wrap log calls and do the transformations there.
The first way will require some efforts because you'll need to implement batch of classes and make sure that the other parts of log system are not broken.
But second part is pretty strait forward.
You have ti create a logger wrapper which implements Logger interface, could be something like this:
public class LoggerWrapper extends MarkerIgnoringBase {
private final Logger logger;
public LoggerWrapper(Logger logger) {
this.logger = logger;
}
private String transformMessage(String input) {
// do all needed regexp transformations here
}
#Override
public void debug(String msg) {
String transformedMessage = transformMessage(msg);
// delegate log call to inner logger
logger.debug(transformedMessage);
}
// implement the rest of the methods here
}
And in the code you might use it like this:
private static final Logger log = new LoggerWrapper(
LoggerFactory.getLogger(SomeClass.class)
);
You can also wrap the logger without implementing Logger interface (in my case it is MarkerIgnoringBase class). In that case you'll not need to implement number of methods from the interface, however you'll louse interchangeability.
The drawback of this solution is that you have to log the messages in advance on your side (not via MessageTracing) but if it is possible I would go this way. On the other hand the first solution does it out of the box.

How to Create a Custom Appender in log4j2?

As disscussed in this link : How to create a own Appender in log4j?
For creating a custom appender in log4j 1.x we have to extend the AppenderSkeleton class and implements its append method.
Similarly How we can create a custom appender in log4j2 as we dont have AppenderSkelton class to extend and all other appender extend AppenderBase class .
This works quite differently in log4j2 than in log4j-1.2.
In log4j2, you would create a plugin for this. The manual has an explanation with an example for a custom appender here: http://logging.apache.org/log4j/2.x/manual/extending.html#Appenders
It may be convenient to extend org.apache.logging.log4j.core.appender.AbstractAppender, but this is not required.
When you annotate your custom Appender class with #Plugin(name="MyCustomAppender", ...., the plugin name becomes the configuration element name, so a configuration with your custom appender would then look like this:
<Configuration packages="com.yourcompany.yourcustomappenderpackage">
<Appenders>
<MyCustomAppender name="ABC" otherAttribute="...">
...
</Appenders>
<Loggers><Root><AppenderRef ref="ABC" /></Root></Loggers>
</Configuration>
Note that the packages attribute on the configuration is a comma-separated list of all the packages with custom log4j2 plugins. Log4j2 will search these packages in the classpath for classes annotated with #Plugin.
Here is a sample custom appender that prints to the console:
package com.yourcompany.yourcustomappenderpackage;
import java.io.Serializable;
import java.util.concurrent.locks.*;
import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.config.plugins.*;
import org.apache.logging.log4j.core.layout.PatternLayout;
// note: class name need not match the #Plugin name.
#Plugin(name="MyCustomAppender", category="Core", elementType="appender", printObject=true)
public final class MyCustomAppenderImpl extends AbstractAppender {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
protected MyCustomAppenderImpl(String name, Filter filter,
Layout<? extends Serializable> layout, final boolean ignoreExceptions) {
super(name, filter, layout, ignoreExceptions);
}
// The append method is where the appender does the work.
// Given a log event, you are free to do with it what you want.
// This example demonstrates:
// 1. Concurrency: this method may be called by multiple threads concurrently
// 2. How to use layouts
// 3. Error handling
#Override
public void append(LogEvent event) {
readLock.lock();
try {
final byte[] bytes = getLayout().toByteArray(event);
System.out.write(bytes);
} catch (Exception ex) {
if (!ignoreExceptions()) {
throw new AppenderLoggingException(ex);
}
} finally {
readLock.unlock();
}
}
// Your custom appender needs to declare a factory method
// annotated with `#PluginFactory`. Log4j will parse the configuration
// and call this factory method to construct an appender instance with
// the configured attributes.
#PluginFactory
public static MyCustomAppenderImpl createAppender(
#PluginAttribute("name") String name,
#PluginElement("Layout") Layout<? extends Serializable> layout,
#PluginElement("Filter") final Filter filter,
#PluginAttribute("otherAttribute") String otherAttribute) {
if (name == null) {
LOGGER.error("No name provided for MyCustomAppenderImpl");
return null;
}
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
return new MyCustomAppenderImpl(name, filter, layout, true);
}
}
For more details on plugins:
http://logging.apache.org/log4j/2.x/manual/plugins.html
If the manual is not enough, it may be useful to look at the source code for the built-in appenders in log4j-core.
As you pointed out AppenderSkeleton is not available anymore so the solutions in How to create my own Appender in log4j? will not work.
Using Mockito, or similar library to create an Appender with an ArgumentCaptor will not work if you're expecting multiple logging messages because the MutableLogEvent is reused over multiple log messages.
The most generic solution I found for log4j2 is to provide a mock implementation that records all the messages. It does not require any additional libraries like Mockito or JMockit.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.AbstractAppender;
private static MockedAppender mockedAppender;
private static Logger logger;
#Before
public void setup() {
mockedAppender.message.clear();
}
/**
* For some reason mvn test will not work if this is #Before, but in eclipse it works! As a
* result, we use #BeforeClass.
*/
#BeforeClass
public static void setupClass() {
mockedAppender = new MockedAppender();
logger = (Logger)LogManager.getLogger(ClassWithLoggingToTest.class);
logger.addAppender(mockedAppender);
logger.setLevel(Level.INFO);
}
#AfterClass
public static void teardown() {
logger.removeAppender(mockedAppender);
}
#Test
public void test() {
// do something that causes logs
for (String e : mockedAppender.message) {
// add asserts for the log messages
}
}
private static class MockedAppender extends AbstractAppender {
List<String> message = new ArrayList<>();
protected MockedAppender() {
super("MockedAppender", null, null);
}
#Override
public void append(LogEvent event) {
message.add(event.getMessage().getFormattedMessage());
}
}
It looks like plugin appenders are scanned at startup and cannot be added during runtime. Is that true?
to add new appender while running you can use monitorInterval property to update log configuration i.e. every 60 sec:
<Configuration monitorInterval="60">

log4j: Class name showing in log is not correct when I call the logger from another class

Basically, when using log4j, I know we have to initiate a Logger by using Logger.getLogger(MyClass.class) or Logger.getLogger("MyClass").
I have too many classes and I dont want to add this statement in every class. Rather, what I woudl like to do is this
Logger.info(this,"My message");
Where Logger is a class I have written (not the one in log4j) which in turn initiates an object of type Logger (org.apache.log4j.Logger) and carries on with the message.
This is my Logger.java
package com.mypackage;
/**
* #author Sriram Sridharan
*Custom logging implementation using log4j
*/
public class Logger {
private static org.apache.log4j.Logger logger;
/**
* Writes an INFO log
* #param oClass
* #param message
*/
public static void INFO(Object oClass, String message){
org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(oClass.getClass());
logger.info(message);
}
}
Now, I have my own class, that calls this Logger implementation to log events. it looks like this
public class MyClass {
public void myMethod(){
com.mypackage.Logger.INFO(this, "Hello, World");
}
}
I don't have a problem with the logs. They're fine. However, the Class name displayed in the logs is the same (Logger). This is the output
INFO [main] (Logger.java:18) - Hello, World
I expect this
INFO [main] (MyClass.java:18) - Hello, World
Where am I going wrong?
Use %c pattern to output category /getLogger("myCategory")/ instead of %C that prints caller class.
The idea is that you have generic method:
public static void debug(String category, String message) {
Logger logger = org.apache.log4j.Logger.getLogger(category);
logger.debug(message);
}
and your log4j configuration contains your pattern:
%d{ISO8601} %c %m %n
and this will print
2014-02-21 14:38:120 YourCategory Your Message
So you do not need to mess up with instatiation of Logger for each class with log.
you are using logger.info(message); inside Logger class so always Logger.java you will get in your log file.
You can log the message inside the class in which you want to log, the classname will be logged.
You don't use the class parameter in obtaining the log4j logger, so log4j assumes your logger class.
Try
public static void INFO(Object oClass, String message){
org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(oClass.getClass());
logger.info(message);
}
instead.

Setting up java Logger for a specific package

could anybody explain to me, how to set up java Logger for various classes from a concrete package ?
for example:
if I get this one and set it up
Logger logger = Logger.getLogger("com.google.api.client.*");
logger.setLevel(Level.CONFIG);
logger.addHandler(new Handler() {
#Override
public void close() throws SecurityException {
}
#Override
public void flush() {
}
#Override
public void publish(LogRecord record) {
// default ConsoleHandler will take care of >= INFO
if (record.getLevel().intValue() < Level.INFO.intValue()) {
System.out.println(record.getMessage());
}
}
});
there are conditions like this
Logger.getLogger(HttpTransport.class.getName()).isLoggable(Level.CONFIG);
in the library where HttpTransport is part of com.google.api.client.*
But the problem is, that
Logger.getLogger(HttpTransport.class.getName()).isLoggable(Level.CONFIG);
is false ... like if a different logger was obtained
How else should I set it for all classes from the same package? if there are conditions for loggers for concrete classes like HttpTransport.
You do not want the .* in your package string.
Change
Logger logger = Logger.getLogger("com.google.api.client.*");
to
Logger logger = Logger.getLogger("com.google.api.client");

Categories