开发者

Configuring gwt-log's remoteLogger; use log4j to put it in a separate file

I have a (Smart)GWT application, that uses Spring on the server-side, and logs its stuff there via log4j. This works (deploying on tomcat6/ubuntu 10.04 LTS).

On the client-side I use the gwt-log remote logging library, configured properly. When running debug mode, I see the gwt-logs in the Eclipse 'Development Mode' pane. When deployed however, I don't see the gwt-log logs. I have configured things as follows:

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
...
<appender name="FILE_LOG2" class="org.apache.log4j.FileAppender">
  <param name="File"   value="${PuzzelVandaag-instance-root}WEB-开发者_Python百科INF/logs/Sytematic.log" />
  <param name="Append" value="true" />          
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="--- %d [%.4t] %-5p %c{1} - %m%n"/>
  </layout>     
</appender>
...
<!-- this one works, normal server-side code -->
<category name="com.isomorphic">
   <priority value="DEBUG" />
   <appender-ref ref="FILE_LOG2" />
</category>
<!-- currently I use this to configure gwt-log stuff. Is this the right way? --> 
<category name="gwt-log"> 
  <level value="DEBUG" />
  <appender-ref ref="FILE_LOG2"/> 
</category> 

The server-side package logging works, but I have troubles with the client-side. I am fairly sure the remote logging servlet works, as I don't see any errors on this. I have it configured as follows, in web.xml:

<servlet> 
  <servlet-name>gwt-log-remote-logger-servlet</servlet-name>  
  <servlet-class>com.allen_sauer.gwt.log.server.RemoteLoggerServiceImpl</servlet-class> 
 </servlet>  
 <servlet-mapping> 
   <servlet-name>gwt-log-remote-logger-servlet</servlet-name>  
   <url-pattern>/[modulename]/gwt-log</url-pattern> 
 </servlet-mapping> 

When I log stuff, I do a call like Log.debug("some msg"), whilst importing com.allen_sauer.gwt.log.client.Log.

All-in-all I think I followed the correct approach. I also run hosted mode with the -Dlog4j.debug parameter, and this is what it tells me:

log4j: Retreiving an instance of org.apache.log4j.Logger.
log4j: Setting [gwt-log] additivity to [true].
log4j: Level value for gwt-log is  [DEBUG].
log4j: gwt-log level set to DEBUG
log4j: Adding appender named [STDOUT] to category [gwt-log].
log4j: Adding appender named [SmartClientLog] to category [gwt-log].
log4j: Adding appender named [FILE_LOG2] to category [gwt-log].

For completion, here is the relevant part of .gwt.xml:

<inherits name="com.allen_sauer.gwt.log.gwt-log-DEBUG"/>  
<set-property name="log_DivLogger" value="DISABLED"/>  
<!-- In gwt-log-3.0.3 or later -->  
<inherits name="com.allen_sauer.gwt.log.gwt-log-RemoteLogger"/> 

Am I missing something obvious? I am a log4j newbie... Any help would be greatly appreciated!


If you take a look at the com.google.gwt.logging.server.RemoteLoggingServiceImpl code you will see that it is using java.util.logging.Logger to perform it's logging.

You are using Log4j.

There are two options for getting your logs to appear in Log4j.

  1. Implement your own RemoteLoggingService
  2. Use slf4j to "bridge" java.util.logging with log4j logging

Option 1 is not too hard. I have below the class I created for this. Remember to point your web.xml to this new class.

    import java.util.logging.LogRecord;

    import com.google.gwt.logging.shared.RemoteLoggingService;
    import com.google.gwt.user.server.rpc.RemoteServiceServlet;

    import java.util.logging.Level;
    import org.springframework.stereotype.Component;

    public class MyRemoteLoggingServlet extends RemoteServiceServlet implements RemoteLoggingService {

        private final MyLogger logger = MyLoggerFactory.getLogger(getClass());

        @Override
        public String logOnServer(LogRecord record) {

            Level level = record.getLevel();
            String message = record.getMessage();

            if (Level.INFO.equals(level)) {
                logger.info(message);
            } else if (Level.SEVERE.equals(level)) {
                logger.error(message);
            } else if (Level.WARNING.equals(level)) {
                logger.warn(message);
            } else if (Level.FINE.equals(level)) {
                logger.debug(message);
            }

            return null;
        }

    }

Option 2

In this option you use SLF4J for your logging and configure a bridge that will redirect the java.util.logging.Logger to Log4j. I havent implemented this method myself, but you can read about it here: JUL to SLF4J Bridge


I took this approach, works for me.

public class UILogging extends RemoteServiceServlet implements
    RemoteLoggingService {

private static final String SYMBOL_MAPS = "symbolMaps";

private static StackTraceDeobfuscator deobfuscator = null;

private static Logger logger = Logger.getLogger(UILogging.class);

@Override
public void init(ServletConfig config) throws ServletException {
    super.init(config);
    setSymbolMapsDirectory(config.getInitParameter(SYMBOL_MAPS));
}

/**
 * Logs a Log Record which has been serialized using GWT RPC on the server.
 * 
 * @return either an error message, or null if logging is successful.
 */
public final String logOnServer(LogRecord lr) {
    String strongName = getPermutationStrongName();
    try {
        if (deobfuscator != null) {
            lr = deobfuscator.deobfuscateLogRecord(lr, strongName);
        }
        if (lr.getLevel().equals(Level.SEVERE)) {
            logger.error(lr.getMessage(),lr.getThrown());
        } else if (lr.getLevel().equals(Level.INFO)) {
            logger.info(lr.getMessage(),lr.getThrown());
        } else if (lr.getLevel().equals(Level.WARNING)) {
            logger.warn(lr.getMessage(),lr.getThrown());
        } else if (lr.getLevel().equals(Level.FINE)) {
            logger.debug(lr.getMessage(),lr.getThrown());
        } else if (lr.getLevel().equals(Level.ALL)) {
            logger.trace(lr.getMessage(),lr.getThrown());
        }
    } catch (Exception e) {
        logger.error("Remote logging failed", e);
        return "Remote logging failed, check stack trace for details.";
    }
    return null;
}

/**
 * By default, this service does not do any deobfuscation. In order to do
 * server side deobfuscation, you must copy the symbolMaps files to a
 * directory visible to the server and set the directory using this method.
 * 
 * @param symbolMapsDir
 */
public void setSymbolMapsDirectory(String symbolMapsDir) {
    if (deobfuscator == null) {
        deobfuscator = new StackTraceDeobfuscator(symbolMapsDir);
    } else {
        deobfuscator.setSymbolMapsDirectory(symbolMapsDir);
    }
}
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜