logback com EJB3.1

Estou usando o logback / slf4j para manipular o log em meu aplicativo. Tudo estava funcionando perfeitamente até que comecei a usar EJBs. Depois que adicionei um EJB sem estado ao meu aplicativo, o criador de logs começou a ignorar meu logback.xml e parou de usar meus appenders. Eu mudei para uma configuração de logger programático para ver o que estava errado e agora estou recebendo o seguinte erro quando tento usar meu logger dentro do EJB:

org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext

proveniente da linha:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

Existe alguma configuração especial necessária para que o logback funcione com os EJBs? Se importa, estou implantando no glassfish v3.

Isso parece muito próximo ao problema descrito neste segmento e suspeito de um problema de carregamento de class semelhante. Devido à maneira como o logback.xml carrega o logback.xml (mais precisamente a forma como ele recupera um ClassLoader ), ele pode falhar ao pegar seu arquivo de configuração e retornar a BasicConfiguration padrão.

Não tenho certeza de como você empacota seu código, mas a solução sugerida é include o logback.xml em uma biblioteca EAR. Se você não estiver usando um pacote EAR, tente identificar o carregador de classs usado para ver onde colocar o arquivo logback.xml .

No final, isso pode ser um problema no logback. Não verifiquei o rastreador de problemas deles.

Atualização: Se você usar um pacote de guerra, tente configurar o GlassFish para usar primeiro os classloaders filho antes de delegar. No sun-web.xml :

    


Atualização: fiz um pequeno teste do meu lado e … não consigo reproduzir seu problema. Eu criei um projeto para um webapp Java EE 6 que possui a seguinte estrutura:

 amostra de tree $
 amostra
 | - pom.xml
 `- src
     `- principal
         | - java
         |  `- com
         |  `- stackoverflow
         |  `- q2418355
         |  | - SimpleEJB.java
         |  `- https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet.java
         | - resources
         |  `- logback.xml
         `- webapp
             | - META-INF
             |  `- MANIFEST.MF
             | - WEB-INF
             |  `- lib
             `- index.jsp

Meu pom.xml se parece com:

   4.0.0 com.stackoverflow.q2418355 sample 1.0-SNAPSHOT war sample Maven Webapp http://maven.apache.org   javax javaee-api 6.0 provided   junit junit 4.7 test   ch.qos.logback logback-classic 0.9.18   org.slf4j slf4j-api 1.5.11      org.apache.maven.plugins maven-compiler-plugin 2.0.2  1.6 1.6    org.apache.maven.plugins maven-war-plugin 2.1-beta-1  false    sample   

O código para SimpleEJB.java é:

 package com.stackoverflow.q2418355; import javax.ejb.Stateless; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Stateless public class SimpleEJB { private static Logger logger = LoggerFactory.getLogger(SimpleEJB.class); public String sayHello(String name) { logger.debug(">> sayHello()"); logger.debug("<< sayHello()"); return "Hello " + name + "!!!"; } } 

O código para https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet.java é:

 package com.stackoverflow.q2418355; import java.io.IOException; import java.io.PrintWriter; import javax.ejb.EJB; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = { "/https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet" }) public class https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet extends HttpServlet { @EJB SimpleEJB bean; private static Logger logger = LoggerFactory.getLogger(https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet.class); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { logger.debug(">> doGet()"); PrintWriter out = response.getWriter(); out.println(""); out.println("

Serving at: " + request.getContextPath() + "

"); out.println("

Invoking EJB: " + bean.sayHello("Duke") + "

"); out.println(""); logger.debug("<< doGet()"); } }

O código para index.jsp é:

   

Hello World!

Invoke the Servlet by clicking here.

E meu logback.xml parece com:

    %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n    /tmp/logs/testFile.log true  %-4relative [%thread] %-5level %logger{35} - %msg%n         

Meu logback.xml é carregado de forma logback.xml e recebo o seguinte rastreio (extraído do meu arquivo de log) ao chamar o servlet:

 10913 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet - >> doGet() 10928 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.SimpleEJB - >> sayHello() 10928 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.SimpleEJB - << sayHello() 10932 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet - << doGet() 

Eu também tentei com o EJB empacotado em seu próprio JAR e implementado no WEB-INF/lib e obter o mesmo resultado, ele simplesmente funciona. Você consegue identificar alguma diferença óbvia? Talvez faça o upload de uma versão simplificada do seu aplicativo (muito provavelmente será necessário para o relatório de bug BTW).

Estou executando o GlassFish v3 no Eclipse 3.5 (com o plugin GlassFish v3).

O org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext exceção org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext mostra que o SLF4J não está ligado ao logback-classic, mas ao slf4j-jdk14. Em suma, o código de log-in não é o culpado porque não está sendo exercitado nem chamado.

Parece que o GFv3 está exportando o slf4j-jdk14.jar para o seu aplicativo e, portanto, sobrescrevendo sua escolha do backend de logging, logback neste caso. Esse é um desses cenários em que o servidor de aplicativos, inadvertidamente, impõe suas opções ao usuário.

Se de fato o GFv3 impuser sua binding ao SLF4J no usuário final, então esse é um problema do GFv3 que deve ser resolvido pelos desenvolvedores do GFv3. Eu posso estar errado, mas acho que eles assumem que o usuário final não desejará nenhuma outra funcionalidade de log além do que é fornecido pelo java.util.logging e apenas empacota o slf4j-jdk14 no GFv3. Os usuários precisam contatá-los e reclamar que sua suposição está incorreta. Também é possível que eles estejam cientes desse problema e já forneçam uma solução alternativa …

Basicamente, o problema é que o servidor de aplicativos usa o slf4j AND, que suas tentativas de usá-lo vão para a binding slf4j do servidor de aplicativos, em vez daquele que você deseja.

Você não pode simplesmente usar a binding slf4j no Glassfish?

Aqui está praticamente o código relevante exato:

O Login EJB:

 @Stateless @Interceptors(LoggingInterceptor.class) public class LoginEJB { @PersistenceContext(unitName = "persistence") private EntityManager em; public User getUser(String username) { try { Query query = em.createQuery("Select u from User u where u.userName = '" + username + "'"); User user = (User) query.getSingleResult(); return user; } catch (NoResultException e) { return null; } } } 

O interceptador onde meu código de registro é:

 import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LoggingInterceptor { private Logger logger = LoggerFactory.getLogger(this.getClass()); @AroundInvoke public Object logMethod(InvocationContext ic) throws Exception { logger.info("[{}] Entering - {}()", ic.getTarget().toString() , ic.getMethod().getName()); try { return ic.proceed(); } finally { logger.info("[{}] Exiting - {}()", ic.getTarget().toString() , ic.getMethod().getName()); } } } 

O logback.xml

    %d{HH:mm:ss.SSS} [%-5level] [%logger{36}] - %msg%n    c:\ItamLogs\log.txt  c:\ItamLogs\Archive\log-%d{yyyy-MM-dd}.txt   [%-5level] - %d{HH:mm:ss.SSS} [%logger{35}] - %msg%n           

O bean de apoio do jsf2.0.

 @ManagedBean public class LoginBacking extends AbstractBacking { @NotEmpty(message = "User Name required.") private String username; @NotEmpty(message = "Password required.") private String password; @EJB private LoginEJB loginEJB; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String performLogin() { String result = "login"; User user = loginEJB.getUser(username); if(null == user || !user.getPassword().equals(password)) { this.getFacesContext().addMessage("login-form:button-submit", new FacesMessage("The User Name or Password entered is incorrect.")); return result; } this.setCurrentUser(user); result = "success"; return result; } } 

Eu tenho uma página jsf que tem

    

finalmente meu pom

  4.0.0 com.test tester 1.0/version> Code war   maven2-repository.dev.java.net Java.net Repository for Maven http://download.java.net/maven/2/    codecaus codehaus http://repository.codehaus.org    ibiblio http://www.ibiblio.org/maven2/   jboss http://repository.jboss.com/maven2  true   false    jboss-snapshot http://snapshots.jboss.org/maven2  true   true    java.net.glassfish Repository hosting the jee6 artifacts http://download.java.net/maven/glassfish     jboss-plugins http://repository.jboss.com/maven2  true   false    jboss-snapshot-plugins http://snapshots.jboss.org/maven2  true   true      javax.faces jsf-api 2.0 provided   javax.servlet servlet-api 2.5 provided   javax.el el-api 1.0 provided   javax.validation validation-api 1.0.0.GA   org.glassfish bean-validator 3.0-JBoss-4.0.0.Beta3   org.glassfish.extras glassfish-embedded-all 3.0 test   javax javaee-api 6.0-SNAPSHOT   junit junit 4.7   javax.faces jsf-api 2.0 provided    org.hibernate hibernate-core 3.5.0-CR-2   org.hibernate hibernate-annotations 3.5.0-CR-2   org.hibernate hibernate-commons-annotations 3.2.0.Beta1   org.hibernate hibernate-entitymanager 3.5.0-CR-2   org.hibernate hibernate-c3p0 3.5.0-CR-2   postgresql postgresql 8.4-701.jdbc4    ch.qos.logback logback-core 0.9.18   ch.qos.logback logback-classic 0.9.18   org.slf4j slf4j-api 1.5.11   org.eclipse.persistence javax.persistence 2.0.0    gfv3ee6      org.apache.maven.plugins maven-compiler-plugin  1.6 1.6    org.apache.maven.plugins maven-war-plugin 2.0      org.apache.maven.plugins maven-war-plugin 2.0     

Edit: Eu também tentei mudar meu logger para uma estática, sem alteração.