【问题标题】:How can get correct logger line number in the following context如何在以下上下文中获取正确的记录器行号
【发布时间】:2015-01-18 07:02:58
【问题描述】:

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

我为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的logger格式配置

<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-class name 给出了预期的正确类。但是没有办法获得行号(正确的行号)。

更改记录器专利后我得到什么

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

这是我的问题。

  1. 是否有任何日志附加程序(SocketAppenderJMSAppender)与 JBoss AS7 一起工作?(发现没有与 Jboss AS 7 一起工作的解决方案)
  2. 还有比这个更好的方法吗?
  3. 有没有办法使用这种方法获得正确的行号?

我已经在JBossDeveloper 中提出了一个问题。但至少仍然没有评论。

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

任何帮助都非常感谢。

【问题讨论】:

    标签: java logging jboss slf4j appender


    【解决方案1】:

    如果您使用的版本等于或高于 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 中工作的唯一方法是为 SocketAppender 开发自定义 java.util.logging.Handler

    查看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

    希望对你有所帮助。

    【讨论】:

    • @RuchiraGayanRanaweera 检查类路径中没有其他版本的 log4j,例如在部署(ear/war)中。您必须使用服务器提供的 log4j 版本。您可以在战争部署中包含来自 META-INF/MANIFEST.MFWEB-INF/jboss-deployment-structure.xml 的 log4j 依赖项。见mastertheboss.com/jboss-server/jboss-log/…
    猜你喜欢
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 2014-06-30
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多