سؤال

ولدي جافا التطبيق الذي يستخدم log4j.

والتكوين:

log4j.rootLogger=info, file

log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=${user.home}/logs/app.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d [%t] %c %p %m%n

وهكذا يتم إلحاق جميع البيانات سجل بشكل صحيح إلى الملف، ولكن أنا فقدان المعياري وستدير. كيف يمكنني إعادة توجيه آثار كومة استثناء وsysouts إلى ملف المدلفن يومي؟

هل كانت مفيدة؟

المحلول

// I set up a ConsoleAppender in Log4J to format Stdout/Stderr
log4j.rootLogger=DEBUG, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%t] %-5p %c - %m%n


// And I call this StdOutErrLog.tieSystemOutAndErrToLog() on startup

public class StdOutErrLog {

    private static final Logger logger = Logger.getLogger(StdOutErrLog.class);

    public static void tieSystemOutAndErrToLog() {
        System.setOut(createLoggingProxy(System.out));
        System.setErr(createLoggingProxy(System.err));
    }

    public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
        return new PrintStream(realPrintStream) {
            public void print(final String string) {
                realPrintStream.print(string);
                logger.info(string);
            }
        };
    }
}

نصائح أخرى

في كود Skaffman: لإزالة خطوط فارغة في سجلات log4j، فقط إضافة "println" طريقة لPrintStream من createLoggingProxy

public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
    return new PrintStream(realPrintStream) {
        public void print(final String string) {
            logger.warn(string);
        }
        public void println(final String string) {
            logger.warn(string);
        }
    };
}

والتقطت الفكرة من مايكل S.، ولكن مثل المذكورة في تعليق واحد، لديه بعض المشاكل: أنه لا التقاط كل شيء، وأنه يطبع بعض خطوط فارغة

وأيضا أردت أن فصل System.out وSystem.err، لذلك، يتم تسجيل هذا System.out مع 'INFO' مستوى السجل ويحصل بتسجيل الدخول System.err مع 'ERROR' (أو 'WARN' إذا أردت).

وهكذا وهذا هو بلدي الحل: أولا فئة التي تمتد OutputStream (انه من الاسهل لتجاوز كافة أساليب OutputStream من لPrintStream). فإنه يسجل مع مستوى السجل المحدد، وكذلك نسخ كل شيء لOutputStream آخر. وأيضا يكشف سلاسل "فارغة" (التي تحتوي على المسافات فقط) وعدم تسجيل لهم.

import java.io.IOException;
import java.io.OutputStream;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class LoggerStream extends OutputStream
{
private final Logger logger;
private final Level logLevel;
private final OutputStream outputStream;

public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream)
{
    super();

    this.logger = logger;
    this.logLevel = logLevel;
    this.outputStream = outputStream;
}

@Override
public void write(byte[] b) throws IOException
{
    outputStream.write(b);
    String string = new String(b);
    if (!string.trim().isEmpty())
        logger.log(logLevel, string);
}

@Override
public void write(byte[] b, int off, int len) throws IOException
{
    outputStream.write(b, off, len);
    String string = new String(b, off, len);
    if (!string.trim().isEmpty())
        logger.log(logLevel, string);
}

@Override
public void write(int b) throws IOException
{
    outputStream.write(b);
    String string = String.valueOf((char) b);
    if (!string.trim().isEmpty())
        logger.log(logLevel, string);
}
}

وثم فئة أداة بسيطة جدا لضبط out وerr:

import java.io.PrintStream;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class OutErrLogger
{
public static void setOutAndErrToLog()
{
    setOutToLog();
    setErrToLog();
}

public static void setOutToLog()
{
    System.setOut(new PrintStream(new LoggerStream(Logger.getLogger("out"), Level.INFO, System.out)));
}

public static void setErrToLog()
{
    System.setErr(new PrintStream(new LoggerStream(Logger.getLogger("err"), Level.ERROR, System.err)));
}

}

إذا كنت تستخدم تطبيق الخادم، والحاويات بريمج أو شيئا من هذا القبيل، انظر kgiannakakis في الإجابة .

لتطبيقات بذاتها ترى هذا . يمكنك reassing ستدين و <لأ href = "http://java.sun.com/javase/6/docs/api/java/lang/System.html#setOut(java.io.PrintStream)" يختلط = "نوفولو noreferrer "> المعياري و <لأ href =" http://java.sun.com/javase/6/docs/api/java/lang/System.html#setErr(java.io.PrintStream) "يختلط = "noreferrer نوفولو"> ستدير باستخدام java.lang.System الصف. في الأساس إنشاء فئة فرعية جديدة من PrintStream وتعيين هذا المثال إلى System.out.

شيء على طول هذه الخطوط في بداية التطبيق الخاص بك (غير مجربة).

// PrintStream object that prints stuff to log4j logger
public class Log4jStream extends PrintStream {
      public void write(byte buf[], int off, int len) {
        try {
           // write stuff to Log4J logger
        } catch (Exception e) {
       }
    }
}

// reassign standard output to go to log4j
System.setOut(new Log4jStream());

والأجوبة أعلاه يعطي فكرة ممتازة لاستخدام وكيل للتسجيل STDOUT / ERR. ومع ذلك أمثلة التنفيذ المقدمة لا تعمل بشكل جيد لجميع الحالات. على سبيل المثال، حاول

<اقتباس فقرة>   

وSystem.out.printf ( "اختبار٪ ق \ ن"، "ABC")؛

ورمز من الأمثلة المذكورة أعلاه ستخفض الانتاج الى قطع منفصلة على حدة وفي عدة إدخالات Log4j لا يمكن قراءتها.

والحل هو للتخفيف من الانتاج حتى الزناد '\ ن' وجدت في نهاية المخزن المؤقت. أحيانا ينتهي المخزن المؤقت مع '\ ص \ ن'. الطبقة أدناه يعالج هذه المشكلة. انها تعمل بكامل طاقتها. استدعاء ربط أسلوب ثابت () لتفعيلها.

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

// Based on
// http://stackoverflow.com/questions/1200175/log4j-redirect-stdout-to-dailyrollingfileappender
public class Log4jStdOutErrProxy {

  public static void bind() {
    bind(Logger.getLogger("STDOUT"), Logger.getLogger("STDERR"));
  }

  @SuppressWarnings("resource")
  public static void bind(Logger loggerOut, Logger loggerErr) {
    System.setOut(new PrintStream(new LoggerStream(loggerOut, Level.INFO,  System.out), true));
    System.setErr(new PrintStream(new LoggerStream(loggerErr, Level.ERROR, System.err), true));
  }

  private static class LoggerStream extends OutputStream {
    private final Logger logger;
    private final Level logLevel;
    private final OutputStream outputStream;
    private StringBuilder sbBuffer;

    public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream) {
      this.logger = logger;
      this.logLevel = logLevel;
      this.outputStream = outputStream;
      sbBuffer = new StringBuilder();
    }

    @Override
    public void write(byte[] b) throws IOException {
      doWrite(new String(b));
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
      doWrite(new String(b, off, len));
    }

    @Override
    public void write(int b) throws IOException {
      doWrite(String.valueOf((char)b));
    }

    private void doWrite(String str) throws IOException {
      sbBuffer.append(str);
      if (sbBuffer.charAt(sbBuffer.length() - 1) == '\n') {
        // The output is ready
        sbBuffer.setLength(sbBuffer.length() - 1); // remove '\n'
        if (sbBuffer.charAt(sbBuffer.length() - 1) == '\r') {
          sbBuffer.setLength(sbBuffer.length() - 1); // remove '\r'
        }
        String buf = sbBuffer.toString();
        sbBuffer.setLength(0);
        outputStream.write(buf.getBytes());
        outputStream.write('\n');
        logger.log(logLevel, buf);
      }
    }
  } // inner class LoggerStream  

}

وأفترض أنك تسجيل stacktraces عبر e.printStackTrace()؟ يمكنك تمرير كائن استثناء في أساليب تسجيل Log4j وتلك سوف تظهر في السجل الخاص بك (انظر <لأ href = "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Category.html # خطأ٪ 28java.lang.Object،٪ 20java.lang.Throwable٪ 29 "يختلط =" نوفولو noreferrer "> Logger.error (كائن الكائنات، ر قابل للظهور) )

لاحظ أنه يمكنك تغيير System.out وSystem.err إلى آخر <لأ href = "http://java.sun.com/j2se/1.4.2/docs/api/java/io/PrintStream.html" يختلط = "نوفولو noreferrer"> PrintStream أن الموجهات إلى Log4j. ومن شأن ذلك أن يكون هناك تغيير بسيط ويوفر لك تحويل جميع البيانات الخاصة بك System.out.println().

تدار

وانتاج قياسي والخطأ تيارات من الحاويات الخاصة بك. على سبيل المثال يستخدم قط JULI لإخراج سجل والخطأ تيارات.

وتوصيتي هي أن تترك هذه كما هو. تجنب استخدام System.out.print في التطبيق الخاص بك. انظر هنا للآثار المكدس.

ووANSER من @ مايكل هو نقطة جيدة. ولكن تمتد PrintStream ليست لطيفة جدا، لأنه يستخدم طريقة void write(String) الداخلية لكتابة كل شيء إلى OutputStream.

وأنا أفضل أن استخدام LoggingOutputStream الطبقة من حزمة Log4J Contrib.

وبعد ذلك إعادة توجيه تيارات مثل هذا النظام:

public class SysStreamsLogger {
    private static Logger sysOutLogger = Logger.getLogger("SYSOUT");
    private static Logger sysErrLogger = Logger.getLogger("SYSERR");

    public static final PrintStream sysout = System.out;
    public static final PrintStream syserr = System.err;

    public static void bindSystemStreams() {
        // Enable autoflush
        System.setOut(new PrintStream(new LoggingOutputStream(sysOutLogger, LogLevel.INFO), true));
        System.setErr(new PrintStream(new LoggingOutputStream(sysErrLogger, LogLevel.ERROR), true));
    }

    public static void unbindSystemStreams() {
        System.setOut(sysout);
        System.setErr(syserr);
    }
}

وقبل استخدام طريقة System.setOut وSystem.setErr علينا أن إعادة تعيين الكائن java.util.logging.LogManager باستخدام إعادة تعيين طريقة ().

public static void tieSystemOutAndErrToLog() {

    try{

        // initialize logging to go to rolling log file
        LogManager logManager = LogManager.getLogManager();
        logManager.reset();

        // and output on the original stdout
        System.out.println("Hello on old stdout");
        System.setOut(createLoggingProxy(System.out));
        System.setErr(createLoggingProxy(System.err));

        //Following is to make sure whether system.out and system.err is redirecting to the stdlog.log file
        System.out.println("Hello world!");

        try {
            throw new RuntimeException("Test");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }catch(Exception e){
        logger.error("Caught exception at StdOutErrLog ",e);
        e.printStackTrace();
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top