What are the best debugging tricks with Weld/CDI? - java

One of the beauties with Java EE 6 is the new dependency injection framework - CDI with the Weld reference implementation - which has prompted us to start migrating internally to JSR-330 in an implementation agnostic manner, with the explicit target of being able to have a core jar which is frozen, and then being able to add extra jars providing new modules replacing functionality in the core jar.
I am now in the process of making the above work with Weld, and to be frank there is simply too much magic going on behind the covers. Either it works or it doesn't, and it doesn't provide very much help by default on what happens so you can investigate what is wrong and fix it.
I would expect that there are switches to switch which can easily enable things like:
What classpath entries are scanned and where? What was the result?
What beans are available for injection for which class?
What caused a given bean not to be considered for later? A given jar?
In other words, I need to see the decision process in much more detail. For some reason this is not as needed with Guice, perhaps because there is much less magic, and perhaps because the error messages are very good.
What do you do to debug your Weld applications, and how much does it help?

Short answer: there is no dedicated debug option for CDI (as no such thing is required by the spec), and no dedicated debug option for Weld.
Long Answer: There is a lot you can do on your own. Familiarise yourself with the extension mechanism of CDI, and you'll discover that you can easily (really!) write your own extension that debugs your required information
What classpath entries are scanned and
where? What was the result?
Listen to the ProcessAnnotatedType-Event
What beans are available for injection
for which class?
Query the BeanManager for that.
What caused a given bean not to be
considered for later? A given jar?
Listen to the AfterBeanDiscovery-Event and see what you've got in the BeanManager. Basically, the following scenarios make a ManageBean ineligible for injection:
it's no ManagedBean (like there is no beans.xml in the jar)
it does not qualify as a managed bean (https://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/beanscdi.html#d0e794)
it has no BeanType (#Type{})
it is vetoed (Seam Solder) or suppressed by any other extension-mechanism

Weld uses Simple Logging for Java (sl4j). If you are using Tomcat, I suggest you add sl4j-jdk14-x.x.x.jar to application class path and append following lines to apache-tomcat-7.0.x/conf/logging.properties:
org.jboss.weld.Bootstrap.level = FINEST
org.jboss.weld.Version.level = FINEST
org.jboss.weld.Utilities.level = FINEST
org.jboss.weld.Bean.level = FINEST
org.jboss.weld.Servlet.level = FINEST
org.jboss.weld.Reflection.level = FINEST
org.jboss.weld.JSF.level = FINEST
org.jboss.weld.Event.level = FINEST
org.jboss.weld.Conversation.level = FINEST
org.jboss.weld.Context.level = FINEST
org.jboss.weld.El.level = FINEST
org.jboss.weld.ClassLoading.level = FINEST
This will generate lots of debug in console, so you`d better select something specific and comment out other lines.
Other logging libraries (like log4j) can be configured using their respective config files and adding similar levels.

I can suggest a few options:
lower the logging threshold. I don't know what logging framework is used by Weld, but you can see that and configure, say, DEBUG or INFO
get the source code and put breakpoints in the BeanManager implementation (BeanManagerImpl perhaps). It is the main class in CDI and handles almost everything.
Try putting a different implementation (if not tied by the application server) - for example OpenWebBeans. Its exception messages might be better
Open the specification and read about the particular case. It is often the case the you have missed a given precondition - for example an annotation has to have a specific #Target, otherwise it is not handled by CDI.
I can confirm that the exception messages of Weld are rather disappointing. I haven't used Guice, but in Spring they are very, very informative. With Weld I had to refer to the 4th point above (opened the spec) and verify all preconditions. This was my suspicion initially - that even though the spec looks very good, the implementations will not be as shiny (at first at least). But I guess one gets used to this.

Related

Isn't it possible to configure logging INSIDE the application when using jboss AS 7.1.1.Final?

I read a lot but I couldn't figure out how I could specify for example the log level for specific classes.
Only way I could figure out was in the standalone.xml but why should I configure some application specific setting very general in the server? This complicates the deployment process unnecessary.
Isn't it somehow possible to define the specific log level and the output files somewhere inside the war without touching the server?
Btw. it doesn't matter if log4j or commons-logging or slf4j or whatever is used.
Using a logging.properties file or a log4j configuration file in your deployment will work in JBoss EAP 6.x and WildFly (formerly JBoss AS). Note though that a log4j configuration would only work if you use log4j for your logging facade.
That said I agree with Marko that this should probably be done in the server configuration. I would also encourage you to use the CLI or web interface rather than editing the raw XML as well. You can get some more information on the documentation.
I am sorry for not providing a direct answer, but consider this: the application being in charge of logging levels is a bad idea most of the time as this is something an AS admin should be able to change at any time. For example, the point of the DEBUG or TRACE log levels is to be able to place a lot of such statements in the code without hurting the production server's performance. However, once a bug is detected, you want to be able to lower the logging level without rebuilding the application. This should be a purely administrative task.
On the other hand, I do recognize the need to at least have a decent starting point for the logging configuration and I don't know of any architecture which would allow the application to provide defaults which are overridable by the server configuration.

Best practices for an application-wide logger

After a lot of attempts, I have am finally able to formulate a question. I hope it makes some sense and is easy to understand. Working on a web-application that uses Spring and Jersey. I am required to implement an application-wide logger that should log all the activities performed on the application into a database. For the time being I have used the HAS-A implementation and called the logging method everywhere a CRUD operation is performed. Something like this:
LogBean lBean=new LogBean("rickesh#email.com","update","address","127.0.0.1");
logToDatabase(lBean);
But this causes a lot of repeated lines of code and I have to repeatedly keep instantiating and calling the log method every section the CRUD operation in performed. Is there any way I can pull out the logging from the controller layer, the REST layer? Are there any specific functionality in Spring or Jersey with which I can perform logging on a separate layer and I don't have to keep repeating the same lines of code everywhere. Please advice.
If you are getting messy with writing your logs you should look into AOP. If you are already using spring you should read about Spring AOP, and for logging per se, read using Spring AOP for logging
AOP is a better way but if getting to learn it to resolve this issue is going to take longer then here is a simple alternative.
Add log4j JAR to your WebApp. Make sure, log4j version bundled in your WebApp doesn't conflict with the version already with your Application Server
Place a log4j.xml for FILE and CONSOLE appendars in your class path (src/main/resources)
There is a Log4JConfigureListener provided by Spring which you can declare under section in your web.xml
Additionally, if too much log is generated, you can limit the output of the loggers via either log4j.xml in your application to certain packages only or via using Root logger configuration for your project specific packages. For example, in JBoss you can add a "category" for a package at a specific LOG level
Your specific "separate layer" should have a separate and distinct package name to target the log appendars for that layer
Hope this helps!

Advantage in using Java Logger?

I want to log information to a file and want to know is there any advantage in using the Java Logger class versus my own personal method of logging?
I know using a logger I just add my own FileHandler to the logger. My personal method is just using a FileOutputStream.
Honestly your logger may be as good, it's pretty easy to put in log levels, filtering, etc.
The problem is when you start to put together code from 10 different groups each with their own logging. Some use System.out, some use some custom logger, some use log4j, ...
How do you parse or redirect the output? How do you filter all that output to just show your messages (For instance, filtering options in log4j won't prevent messages being sent straight to System.out).
It's a pretty big bulk change depending on which system you are moving from/to. Better just to use one very common one from the beginning and hope that it's the one everybody else on the project chooses.
The real question is: why would you bother writing your own logger when there are already existing libraries for doing that? Does your logger do something that the others don't? I kind of doubt it.
Standardization is another big issue - see Bill K's answer.
For most scenarios, a standard logging framework is the way to go. They are pretty flexible. But using your own implementation can also be a valid option, specially if we are not speaking of traditional logging (global debugging, problems, warning messages) but about specific informational meesages or accounting.
Among other factors, bear in mind that the standarization of logging allows third party libraries to cooperate. For example, if you have a standard web application using (say) Hibernate, and you have configured a standard Java logging lib, then you can not only log from your own code but also tell Hibernate to log debugging info to your log files (not necessarily the same files). That is very useful - almost a must.
If you code your own logging library with a plain FileOutputStream, you must decide -among other things- if you are going to keep the file opened, or reopen-append-close in each write - and you must take of synchronization and related issues. Nothing terribly complicated, though.
The logger gives to ability to define different levels of importance of the logged messages and the ability to use different sink for the output - the console, a file, etc.
Also it's easy to enable or disable only some type of message when using a logger - for example you don't want to see every debug message in production.
A logging framework allows you specify logging levels (e.g. log only critical messages, log only debug messages etc.). It also allows you to log to multiple destinations (e.g. to a file, to syslog etc.) and you can do this even after your application is fully built by just changing a config file and not changing any code. It can also format your logs easily depending on various parameters.
There are numerous other advantages since proper logging is a rather involved problem and these packages have been written to solve them. I think the important question, why would you not use them?
Well I would always prefer tested thing and approved by community over something which still need a lot of test. Logger allows you many things which will consume you some time to implement and to test the robustness of your solution. A big plus will be the know-how of the next person who will do something with your code, in case it will be your logger, normally it would take more time to learn how its working out, since there is much more examples and documentation for java.util.logger.
Like all others mention, there are more advantages to using a more common logging system over writing your own. To be honest, the Java util logging api is not nearly as extensive and configurable as other libraries you might find out there on the internet.
Bare in mind that rolling your own always has the disadvantage of being less tested and therefore more prone to break or skip some potentially crucial messages.
Personally I prefer using SLF4J since it allows me to plug in adapters for more commonly used logging frameworks and then let's me pick my own actual logging implementation, this solves most of the problems with different library writers preferring different logging frameworks. And if you consider yourself up for the task you could writer an implementation for SLF4J yourself ;)

Tell OpenEJB to ignore MDB

I wrote an unit-test for an activity which finally puts a message into a queue. As soon as a message is put into that queue, a message driven bean starts processing. But I don't want to test MDBs in a unit test. How can I tell OpenEJB to ignore them?
I set up OpenEJB with several properties:
p.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.openejb.client.LocalInitialContextFactory");
p.setProperty("openejb.deployments.classpath.include", ".*");
p.setProperty("openejb.localcopy", "false");
// Messaging
p.put("MyJmsResourceAdapter",
"new://Resource?type=ActiveMQResourceAdapter");
// Do not start the ActiveMQ broker
p.put("MyJmsResourceAdapter.BrokerXmlConfig", "");
p.put("MyJmsConnectionFactory",
"new://Resource?type=javax.jms.ConnectionFactory");
p.put("MyJmsConnectionFactory.ResourceAdapter", "MyJmsResourceAdapter");
p.put("queue/MyQueue",
"new://Resource?type=javax.jms.Queue");
I know I must set openejb.deployments.classpath.exclude, but I can't figure out the right value:
p.setProperty("openejb.deployments.classpath.exclude", "org.example.mdb.*");
For example my class is named org.example.mdb.MyMDB.
just my 2 cents:
try ".*org/example/mdb.*" or ".*org.example.mdb.*"
from Loading Deployments from the Classpath:
Note by default these settings will
only affect which jars OpenEJB will
scan for annotated components when no
descriptor is found. If you would like
to use these settings to also filter
out jars that do contain descriptors,
set the
openejb.deployments.classpath.filter.descriptors
property to true. The default is false
We don't have that feature, but it could easily be added if you wanted to do a little hacking -- new contributions and contributors are always welcome.
This class will do exactly what you want... and a few things you probably don't want :) It strips out all MDBs and JMS resource references (the good part) and it strips out all entity beans and persistence unit references (the part you probably don't want). We wrote it due to some debugging issues we were having when either ActiveMQ or OpenJPA were loaded. If you cleaned it up we'd happily take it back and support it as a feature.
There is a similar feature which strips out all web services. It is installed in the ConfigurationFactory if a specific system property is set. Should be easy to plug an "MDB & JMS" remover using a similar flag at basically that same place in ConfigurationFactory
In fact since in OpenEJB all annotation and xml meta-data is merged into one object tree (which is also a JAXB tree), you could do pretty powerful transformations of the app prior to it being actually deployed. Say for example swap out specific beans for mock versions.
One of those things I think would make an excellent feature but haven't yet had the time to work on. I.e. making some clean hook for people to mess with the tree just before we send it off for deployment. Anyone reading this is welcome to jump in and take a stab at it (yay open source!).

java logging vs Log4j in Spring framework. Which one is the most suitable

We are developing a web-based application in Java using the Spring framework. We are wondering which Logging system would be the most appropriate for it, whether Log4j or JUL (java.util.Logging), which is integrated with jdk. As far as I'm concerned, the former is more popular among developers and offers higher customization options, but I'm not sure which is simpler to adapt with spring.
any help will be appreciated.
thanks!
Before you start with log4j, look at logback. Log4j shouldn't be used for new projects anymore. If you have legacy code that needs any logging framework, use slf4j to make the old code talk to logback (or log4j if you must).
The main reasons you should not use JUL is that it implements the bare minimum that you need for logging, the configuration is hard at best and, if you use any component that doesn't use it, you'll have to deal with two logging frameworks.
Regardless of which logging framework you use in your own code, as far as I can remember, Spring has a hard dependency on commons-logging. You can still use whatever you like for your own logging (I'd recommend SLF4J as your facade, with logback as your implementation), but Spring internally needs commons-logging. Whether you want to depend on multiple frameworks is your choice; it shouldn't prove problematic.
Spring uses commons logging, which is a log abstraction facility but has issues that sl4j doesn't have. Hibernate moved to slf4j - I would like to see spring do the same, but I don't think they have any plans in this regard.
So as long as your log abstraction facility (use slf4j) logs to the same logging framework as you've configured commons logging in spring, then you're good. One log configuration for both. You might find an adapter for logback for commons and slf4j.
Since the other responses didn't actually answer your question, I thought I'd have a stab at it.
Firstly, java.util.logging is horrible. It's a pain to use, and a pain to configure. Log4J is nicer on both counts. However, you should pick whichever one you're most comfortable with. Spring uses commons-logging, which in turn will use either log4j (if found on the classpath) or java.util.logging otherwise. In otherwords, if your application already has log4j present, then Spring will effectively use that, and so should you. If log4j is not already present, then either use java.util.logging (if you choose to), or add log4j to your classpath and use that.

Categories

Resources