I am using SaxonJ to perform XSLT transformation from Java.
My XSLT files have to output any debug/info as output since my transformation logic is complex.
Is there a way in which I can redirect to log4j so that I can store have the transformation information in a log file?
My system already uses log4j to log output to file. I want to append the transformation debug messages as well.
Any ideas?
I am pretty sure that you have already found out how to perform this. But I hope that my answer will be useful for other people.
All you need to do is implementing MessageListener interface: http://www.saxonica.com/documentation/javadoc/net/sf/saxon/s9api/MessageListener.html
public class MessageListenerImpl implements MessageListener {
private static Logger logger = Logger.getLogger(MessageListenerImpl.class);
public void message(XdmNode content, boolean terminate, SourceLocator locator) {
if (terminate) {
logger.error(content.getStringValue());
System.exit(1);
} else {
logger.warn(content.getStringValue());
}
}
}
You can configure your own Message emitter. There are various interfaces to do this, see for example
http://www.saxonica.com/documentation/javadoc/net/sf/saxon/lib/FeatureKeys.html#MESSAGE_EMITTER_CLASS
or there's a simpler interface in the s9api XsltTransformer class.
Related
I'm using logback in spring-boot 2.2.5.RELEASE, I need to get the log object in memory so I can manipulate the info and proccess it.
What I would expect is something like this.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component
public class application {
Logger logger = LoggerFactory.getLogger(application.class);
public void executeTask(Integer queryMinutes) {
logger.info(INICIO_TRANSACCION, metodo);
try {
//Do something
//Log informative messages
} catch (DBException e) {
//Log ERROR messages
logger.error(MENSAJE_EXCEPCION + e, e);
logger.info(ROLBACK_TRANSACCION);
} finally {
//Here I need to call a method to further process the info printed in the log something like
logger.getMessage();
logger.getLineNumber();
logger.getThread();
callSomeMethod(logger);
logger.info(TIEMPO_PROCESO, (System.currentTimeMillis() - tiempoInicial));
logger.info(FIN_TRANSACCION, metodo);
}
}
}
I know that when you work with appenders we usually define a ILoggingEvent object and this give access to logger.getMessage() and more,
The question is how to get the log object in my java class so I can access the properties.
The basic design of logback (and log4j) is that it is part of your program but is not visible to the calling code. Hence what you want to do is basically against the spirit of the framework you want to use, which I suggest you reconsider.
The logback term for the component that actually ensures that the destination receives a log event is an "appender". http://logback.qos.ch/manual/appenders.html
The problem is that you want to send a mail using a non-standard API, otherwise you could just have used the standard SMTPAppender (http://logback.qos.ch/manual/appenders.html#SMTPAppender)
I would suggest either subclassing the SMTPAppender to do what you want, or write a javax.mail.Session object that implements the JavaMail API and provide it to a stock SMTPAppender using JNDI. Or a third thing. Just not in your own part of the code.
I am trying to migrate from Log4j 1.7 to Log4j2.4
In 1.7, I as creating AppLogger class by extending org.apache.log4j.Logger and using extending debug/error/fatal Methods
e.g.,
public void error(Object message) {
Object error = message;
if (message instanceof Exception) {
Exception e = (Exception) message;
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
error = sw.toString();
}
super.error(error);
}
But in Log4j 2.x, I am not able to extend the class org.apache.logging.log4j.Logger;
What is the Best way to achieve this?
I can understand why you might have wanted to do this with Log4j 1.x, but I cannot figure out why you would want to do this with log4j 2. The best place to do this is in a Layout, but most already do this.
As Ralph pointed out, Log4j2 has a very rich set of functionality, and if you go over the documentation, you often find that you can achieve your goals using the built-in layouts, lookups, filters and other features.
Writing a custom lookup only takes a few lines of code and gives you a powerful hook into the logging subsystem which you can use for many purposes.
If you really want to extend Logger for whatever reason, be aware that some layouts require Log4j to walk the stacktrace to report which class and line in your code from the logger was called from. This mechanism is a bit complex and in general I would recommend you create a Logger wrapper instead of extending it. (Prefer delegation to subclassing.)
Log4j has a tool to make this easy for you: the Custom Logger Generator tool documented in the Custom Log Levels page. Try this and see if it gives you what you need.
I have done some Googling around it but couldn't find any relevant information. log4j supports a bunch of log appenders, there's documentation all over the net about ConsoleAppender and FileAppender, but there are very little or no information about appenders such as NullAppender, JDBCAppender etc. I am particularly interested about NullAppender.
<appender name="???" class="org.apache.log4j.varia.NullAppender">
<appender name="???" class="org.apache.log4j.jdbc.JDBCAppender">
Does anyone have any specific info on these? especially on the NullAppender?
I started looking here.
For the NullAppender, there's not a lot of doc largely because there's nothing to configure: you can define one with <appender name="foo" class="org.apache.log4j.varia.NullAppender"/> and that's about it. From the Javadoc:
A NullAppender merely exists, it never outputs a message to any device.
There aren't a lot a different ways to do nothing. (It exists so that you can trash output without modifying too much of your config.)
For the JDBCAppender, the Javadoc is here: http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/jdbc/JDBCAppender.html
The param tags in the XML config correspond to setters in the Java class, but note the big red warning at the top of the Javadoc:
WARNING: This version of JDBCAppender is very likely to be completely replaced in the future. Moreoever, it does not log exceptions.
So maybe not the best class to be relying on, given that log4j v2.0 is currently in beta, and that a cursory look over the alpha release seems to indicate that it doesn't exist in v2.
A simple google for this class will get you
Nullappender
So essentially if you use the NullAppender your log messaged are written nowhere.
The NullAppender basically does nothing, like others have already pointed out. I just wanted to layout some details.
AppenderSkeleton implements Appender {
...
#Override
public synchronized void doAppend(LoggingEvent event) {
...
}
...
abstract protected void append(LoggingEvent event);
}
public class NullAppender extends AppenderSkeleton {
public static String s;
public String t;
...
#Override
public void doAppend(LoggingEvent event) {
if(layout != null) {
t = layout.format(event);
s = t;
}
}
#Override
public void append(LoggingEvent event) {
}
See also: Source-NullAppender & Source-AppenderSkeleton
What happens at each and every log.trace/debug/... call is
-> org.apache.log4j.Category.forcedLog(String fqcn, Priority level, Object message, Throwable t)
-> org.apache.log4j.Category.callAppenders(LoggingEvent event)
-> org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(LoggingEvent event) is called on each Appender within that Logger
-> org.apache.log4j.Appender.doAppend(LoggingEvent event)
which is NullPointers implementation of doAppend in this case.
As you see, the NullAppender takes away the synchronization, NullAppender.doAppend produces some overhead, but it is very little in most scenarios.
As for JDBCAppender it should not be used.
WARNING: This version of JDBCAppender
is very likely to be completely replaced in the future. Moreoever,
it does not log exceptions.
See: JDBC-Appender-Source Line 34-36
As an alternative you might want to check out clusterlog
Before I reinvent the wheel - I want to be able to insert debugging traces in my code, such as say("We are here.");, without defining static void say() in every class. It needs to do System.out.println(s), and to be globally switched on or off (doSay(false)), and I'd also like it to be able to identify the class from which it's being invoked (as described here). For example:
MyClass: We are here.
Does Java already have such a tool?
Use SLF4j, not log4j (at least, not directly). They are both created by the same author, Ceki Gülcü, but SLF4J incorporates knowledge gained by seeing log4j in use, and looking at advances in other logging packages.
SLF4J is a common API for a number of different underlying logging systems, like log4j, the java.util.logging package, etc. It also has its own "native" implementation, logback.
One reason I like it better than log4j is its support for message templates. These keep your code simpler.
Also, it allows me to include logging in a library, but let the user of my library choose the logging implementation. Without something like this, a user might have to configure logging just for my library, and it wouldn't be unified with the rest of his application.
The most popular Java logging framework is Log4J which does this (and much more).
Look here for a list of other.
Yes. It's called a logging framework. Java has java.util.logging. But many prefer using Log4J.
You could use a logger like Apache's Log4J and do something like logger.trace("We are here");. When you want that off, set the log level higher (debug, warn, error) in your configuration and the trace logs will disappear.
Java has more advanced logging tools, like log4j or logback. There you should create a public static final Logger logger = Logger.getLogger(..) and use the logger to write debug/info/warn/error messages to wherever you like. They are highly configurable - what and where to log.
For the simpler case (if this is a toy project), you can simply define a class with the public static void log(..) method and use it from every class.
Why not static-declare a function in your Main.java, and use it allround?
public class Main {
private static boolean debug;
public static void setDebug(boolean d) { Main.debug = d; }
public static void say(String s) { if(Main.debug) System.out.println(s); }
}
Let me know if this fits your needs.
Edit: revised the code
I didn't know about static import! I combined ideas from #ninetwozero, #karl, and #erickson to create this:
package myPkg;
public class CLHUtilities {
private static boolean saying = false;
public static void tracing(boolean b) {
saying = b;
}
/*
* Technique taken from:
* http://stackoverflow.com/questions/282977/which-class-invoked-my-static-method
*/
public static void say(String s) {
if (saying) {
Throwable t = new Throwable();
StackTraceElement[] trace = t.getStackTrace();
String className = trace[1].getClassName();
String whoCalledMe = null;
try {
whoCalledMe = Class.forName(className).getSimpleName();
} catch (Exception e) {
}
System.out.println(whoCalledMe + ": " + s);
}
}
}
which can be used simply as:
import static myPkg.CLHUtilities.*;
:
tracing(true);
:
say("We are here.");
Which suits my needs perfectly.
I have a log statement in which I always use this.getClass().getSimpleName()as the 1st parameter.
I would like to put this in some sort of macro constant and use that in all my log statements.
But I learned that Java has no such simple mechanism unlike say C++.
What is the best way to achieve this sort of functionality in Java?
My example log statements (from Android) is as follows..
Log.v(this.getClass().getSimpleName(),"Starting LocIden service...");
Java doesn't have macros but you can make your code much shorter:
Log.v(this, "Starting LocIden service...");
And in the Log class:
public void v(Object object, String s)
{
_v(object.getClass().getSimpleName(), s);
}
Another approach could be to inspect the call stack.
Karthik, most logging tools allow you to specify the format of the output and one of the parameters is the class name, which uses the method Mark mentioned (stack inspection)
For example, in log4j the parameter is %C to reference a class name.
Another approach is to follow what android suggests for its logging functionality.
Log.v(TAG, "Message");
where TAG is a private static final string in your class.
Use a proper logging framework (e.g. slf4j). Each class that logs has its own logger, so there's no need to pass the class name to the log method call.
Logger logger = LoggerFactory.getLogger(this.getClass());
logger.debug("Starting service");
//...
logger.debug("Service started");