如何在以下上下文中获得正确的记录器行号

时间:2014-11-20 12:09:21

标签: java logging jboss slf4j appender

我花了一些时间来找出一种可持续的方法,从ERROR服务器实时过滤掉我的应用程序中的JBoss日志。使用Log4j,我可以轻松使用SocketAppender,并将其配置为实时通知ERROR日志的方式。不幸的是我无法用JBoss AS 7执行此操作。除了SocketAppender之外,我找不到SMTPAppender类型的实现。所以我想出了解决这个问题的方法。请看看到目前为止我做了什么。

我为Logger编写了一种包装器。

我的应用程序的示例类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {
 private Logger logger= LoggerFactory.getLogger(MyClass.class);

 public void updateData(String data){
   logger.info("updating data with {} ",data);
   try {
        // do somthing
   }catch (Exception e){
        //something went wrong
       logger.error("update fail ",e);// I want to get this message real time
    }
 }
}

现在我想到了一种获取ERROR日志的方法。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyLogger {
    private Logger logger = null;

    private MyLogger() {
    }

    public static MyLogger getLogger(Class clazz) {
        MyLogger logger = new MyLogger();
        logger.logger = LoggerFactory.getLogger(clazz);
        return logger;
    }

    public void info(String format, Object... arguments) {
        logger.info(format,arguments);
    }

    public void error(String format, Object... arguments) {
        // now i can send this message real time,
        // i am calling web service with error log by a new Thread 
        logger.error(format,arguments); // say line number 10
    }
}

MyLogger使用如下

public class MyClass {
    private static MyLogger logger= MyLogger.getLogger(MyClass.class);

    public void updateData(String data){
       logger.info("updating data with {} ",data);
       try {
            // do somthing
       }catch (Exception e){
            //something went wrong
           logger.error("update fail ",e); // say line number 14
       }
    }
}

此时我的要求匹配,但这会产生一个新问题。

以下是JBoss

的记录器格式配置
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p (%F:%L) (%t) %s%E%n"/>

现在%F - 文件名将成为MyLogger类。和%L - 行号将成为导致不准确日志的MyLogger行号。

示例日志的一部分

(MyLogger.java : 10) // but this should be (MyClass.java : 14)

现在我已将此模式更改为

<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c:%L] (%t) %s%E%n"/>

这几乎可以正常工作,但是%c - 类名按预期提供了正确的类。但是没有办法获得行号(正确的行号)。

改变记录器后,我得到了什么

(com.my.test.MyClass : 10) // but this should be (com.my.test.MyClass : 14)    

以下是我的问题。

  1. 是否有任何日志追加器(SocketAppenderJMSAppender)与JBoss AS7一起使用?(找不到Jboss AS 7的解决方案)
  2. 有没有更好的方法而不是这个?
  3. 有没有办法使用这种方法获得正确的行号?
  4. 我已经在JBossDeveloper中提出了一个问题。但至少还没有评论。

    https://developer.jboss.org/thread/249729

    任何帮助都非常感谢。

1 个答案:

答案 0 :(得分:0)

如果您使用的版本与JBoss 7.2(EAP 6.1)相同或更高,则可以使用 Log4j appenders 作为自定义处理程序(check this issue)。

<强>例如

<custom-handler name="server" class="org.apache.log4j.net.SocketAppender" module="org.apache.log4j">
  <level name="INFO"/>
  <formatter>
    <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
  </formatter>
  <properties>
    <property name="RemoteHost" value="10.10.10.10"/>
    <property name="Port" value="1234"/>
    <property name="LocationInfo" value="true"/>
    <property name="ReconnectionDelay" value="10000"/>
  </properties>
</custom-handler>

在其他情况下,使其在JBoss AS 7中运行的唯一方法是为java.util.logging.Handler开发自定义SocketAppender

查看Creating a custom logging handler in JBOSS as 7.1.0 FinalCustom log handlers on 7.0.1以创建自定义日志处理程序,然后将其委派给Log4jAppenderHandler

例如(示例代码):

import java.util.Collections;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.net.SocketAppender;
import org.apache.log4j.net.SyslogAppender;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import org.jboss.logmanager.ExtLogRecord;
import org.jboss.logmanager.log4j.handlers.Log4jAppenderHandler;


public class SocketHandler extends Handler {

    private final Log4jAppenderHandler log4j = new Log4jAppenderHandler(new SocketAppender());

    @Override
    public void publish(LogRecord record) {
        if (record == null) {
            return;
        }
        ExtLogRecord extRecord;
        if (record instanceof ExtLogRecord) {
            extRecord = (ExtLogRecord) record;
        } else {
            extRecord = ExtLogRecord.wrap(record);
        }
        if (isLoggable(record)) {
            LoggingEvent event = new LoggingEvent(extRecord.getLoggerClassName(),
                    Logger.getLogger(extRecord.getLoggerClassName()), extRecord.getMillis(),
                    Level.toLevel(extRecord.getLevel().toString()), extRecord.getFormattedMessage(),
                    extRecord.getThreadName(), extRecord.getThrown() == null ? null
                            : new ThrowableInformation(extRecord.getThrown()), extRecord.getNdc(),
                    new LocationInfo(new Throwable(), extRecord.getLoggerClassName()),
                    Collections.singletonMap("org.jboss.logmanager.record", extRecord));
            ((SyslogAppender) log4j.getAppender()).doAppend(event);
            flush();
        }
    }

    @Override
    public void flush() {
        log4j.flush();
    }

    @Override
    public void close() throws SecurityException {
        log4j.close();
    }

    @Override
    public void setFilter(Filter filter) {
        log4j.setFilter(filter);
    }

    @Override
    public void setFormatter(Formatter formatter) {
        log4j.setFormatter(formatter);
    }

    public void setThreshold(String threshold) {
        ((SocketAppender) log4j.getAppender()).setThreshold(Level.toLevel(threshold));
    }

    public void setRemoteHost(String remoteHost) {
        ((SocketAppender) log4j.getAppender()).setRemoteHost(remoteHost);
    }

    public void setPort(String port) {
        try {  
            ((SocketAppender) log4j.getAppender()).setPort(Integer.parseInt(port));  
       } catch (Exception e) {}  
    }

    public void setReconnectionDelay(String reconnectionDelay) {
        try {  
            ((SocketAppender) log4j.getAppender()).setReconnectionDelay(Integer.parseInt(reconnectionDelay));  
       } catch (Exception e) {}  
    }

    public void setLocationInfo(String locationInfo) {
        try {  
            ((SocketAppender) log4j.getAppender()).setLocationInfo(Boolean.parseBoolean(locationInfo));  
       } catch (Exception e) {}  
    }

}

我认为最好的方法就是这样,所以你不会在应用程序中使用日志记录实现。

另请参阅:Logging Configuration

我希望这有帮助。