Làm thế nào để gửi một stacktrace đến log4j?


152

Giả sử bạn bắt một ngoại lệ và nhận thông tin sau về đầu ra tiêu chuẩn (như, giả sử, bàn điều khiển) nếu bạn thực hiện e.printStackTrace () :

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)

Bây giờ tôi muốn gửi cái này thay cho một logger như, giả sử, log4j để có được những điều sau:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)

Tôi có thể làm cái này như thế nào?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}

Câu trả lời:


262

Bạn chuyển ngoại lệ trực tiếp đến logger, vd

try {
   ...
} catch (Exception e) {
    log.error( "failed!", e );
}

Nó lên đến log4j để hiển thị dấu vết ngăn xếp.


32
Trình ghi nhật ký lấy một đối tượng cho đối số đầu tiên của nó và sẽ toString () nó. Tuy nhiên, đối số thứ hai phải là một throwable và hiển thị dấu vết ngăn xếp.
Peter Lawrey

1
Tôi không bao giờ biết những gì để nhét vào Chuỗi đầu tiên, thông thường tôi chỉ làm điều log.error(e.getLocalizedMessage(), e)đó là hoàn toàn dư thừa. Nó có xử lý null cho đối số đầu tiên không?
Mark Peters

5
@Mark: Cố gắng cung cấp cho nó một thông điệp phù hợp với bối cảnh hơn thông điệp của ngoại lệ, ví dụ như thực sự nó đang cố gắng làm gì vào lúc đó?
skaffman

2
@Mark Peters, Một ví dụ điển hình có thể là ghi nhật ký các đối số vào phương thức hiện tại dưới dạng thông báo hoặc - ngoại trừ FileNotFound tên đầy đủ của đường dẫn đã được mở. Bất cứ điều gì có thể giúp bạn tìm ra những gì sai - chỉ cần nghĩ rằng bạn không thể gỡ lỗi tình huống.
Thorbjørn Ravn Andersen

1
@skaffman: Thật ra tôi đang sử dụng log4j-1.2.8.jarvà tôi muốn in tất cả stackTracetrên tệp nhật ký của mình nên tôi đã thử như bạn đã đề cập ở trên nhưng chỉ in trên tệp nhật ký của tôi nullPointerException. Tôi đã được sử dụng trên mã của tôi e.printStackTrace()nó in tất cả dấu vết. Tại sao Kolavery này?
Yubaraj

9

Nếu bạn muốn đăng nhập stacktrace mà không liên quan đến ngoại lệ, chỉ cần làm điều này:

String message = "";

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
    message = message + System.lineSeparator() + stackTraceElement.toString();
}   
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);

3
+1 cho System.lineSeparator (), điều này đã giúp tôi in một stacktrace mà tôi nhận được dưới dạng phản hồi từ một dịch vụ từ xa
Stephanie

1
những gì tôi đã tìm kiếm, nhưng bạn nên sử dụng StringBuilder tại đây
Xerus

9

Bạn cũng có thể lấy theo dõi ngăn xếp dưới dạng chuỗi thông qua ExceptionUtils.getStackTrace.

Xem: ExceptionUtils.java

Tôi chỉ sử dụng nó cho log.debug, để giữ cho log.errorđơn giản.


4

Chỉ vì nó xảy ra với tôi và có thể hữu ích. Nếu bạn làm điều này

try {
   ...
} catch (Exception e) {
    log.error( "failed! {}", e );
}

bạn sẽ nhận được tiêu đề của ngoại lệ chứ không phải toàn bộ stacktrace. Bởi vì bộ ghi sẽ nghĩ rằng bạn đang truyền Chuỗi. Làm điều đó mà không {}như skaffman nói


1
Chắc chắn bạn sẽ nhận được toàn bộ dấu vết ngăn xếp ở đây, tuy nhiên {} cũng sẽ được in nguyên văn (không có bất kỳ sự thay thế nào)?
k1eran

1
đừng quá chắc chắn bạn của tôi! Nó không hoạt động với tôi, tôi chỉ có tiêu đề. Nó có thể phụ thuộc vào phiên bản của log4j
iberbeu

@iberbeu đúng vì Throwable.toString()không trả về stacktrace. (Giả sử bạn đang sử dụng một trình ghi nhật ký biết phải làm gì với '{}'.)

3

Câu trả lời từ skaffman chắc chắn là câu trả lời đúng. Tất cả các phương pháp logger như error(), warn(), info(), debug()lấy Throwable như một tham số thứ hai:

try {
...
 } catch (Exception e) {
logger.error("error: ", e);
}

Tuy nhiên, bạn cũng có thể trích xuất stacktrace dưới dạng String. Đôi khi nó có thể hữu ích nếu bạn muốn tận dụng tính năng định dạng bằng cách sử dụng trình giữ chỗ "{}" - xem phương thức void info(String var1, Object... var2);Trong trường hợp này nói rằng bạn có một stacktrace là String, thì bạn thực sự có thể làm một cái gì đó như thế này:

try {
...
 } catch (Exception e) {
String stacktrace = TextUtils.getStacktrace(e);
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
}

Điều này sẽ in thông báo tham số và stacktrace ở cuối giống như cách thực hiện đối với phương thức: logger.error("error: ", e);

Tôi thực sự đã viết một thư viện mã nguồn mở có Tiện ích để trích xuất stacktrace dưới dạng String với tùy chọn lọc thông minh một số nhiễu ra khỏi stacktrace. Tức là nếu bạn chỉ định tiền tố gói mà bạn quan tâm đến stacktrace được trích xuất của bạn sẽ được lọc ra khỏi một số phần không liên quan và để lại cho bạn thông tin rất hợp lý. Dưới đây là liên kết đến bài viết giải thích những tiện ích mà thư viện có và nơi để có được nó (cả dưới dạng tạo tác maven và nguồn git) và cách sử dụng nó. Thư viện Java mã nguồn mở với bộ lọc theo dõi ngăn xếp, bộ chuyển đổi Unicode phân tích chuỗi im lặng và so sánh phiên bản Xem đoạn " Bộ lọc nhiễu Stacktrace "


Một câu trả lời chôn cất nhưng tốt đẹp.
payne

Cảm ơn, @payne. Tôi đánh giá cao một phản hồi tốt
Michael Gantman

2

Câu trả lời này có thể không liên quan đến câu hỏi được hỏi nhưng liên quan đến tiêu đề của câu hỏi.

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable("Created at main()");
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        createdBy.printStackTrace(pw);
        try {
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.debug(os.toString());
    }
}

HOẶC LÀ

public static String getStackTrace (Throwable t)
{
    StringWriter stringWriter = new StringWriter();
    PrintWriter  printWriter  = new PrintWriter(stringWriter);
    t.printStackTrace(printWriter);
    printWriter.close();    //surprise no IO exception here
    try {
        stringWriter.close();
    }
    catch (IOException e) {
    }
    return stringWriter.toString();
}

HOẶC LÀ

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTrace: stackTraceElements){
    logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
}

1

Trong Log4j 2, bạn có thể sử dụng Logger.catching () để ghi nhật ký ngăn xếp từ một ngoại lệ đã bị bắt.

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }

0

đây sẽ là lỗi log4j tốt / ghi nhật ký ngoại lệ - có thể đọc được bằng cách tách / ghi nhật ký / giám sát khác s / w. tất cả mọi thứ là hình thức của cặp khóa-giá trị. log4j sẽ nhận được dấu vết ngăn xếp từ Exception obje

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), e});
    }

0
Try this:

catch (Throwable t) {
    logger.error("any message" + t);
    StackTraceElement[] s = t.getStackTrace();
    for(StackTraceElement e : s){
        logger.error("\tat " + e);
    }   
}

-1

Bạn có thể sử dụng mã dưới đây:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class LogWriterUtility {
    Logger log;

    public LogWriterUtility(Class<?> clazz) {
        log = LogManager.getLogger(clazz);
    }

public void errorWithAnalysis( Exception exception) {

        String message="No Message on error";
        StackTraceElement[] stackTrace = exception.getStackTrace();
        if(stackTrace!=null && stackTrace.length>0) {
            message="";
            for (StackTraceElement e : stackTrace) {
                message += "\n" + e.toString();
            }
        }
        log.error(message);


    }

}

Ở đây bạn chỉ có thể gọi: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Nó sẽ in stackTrace vào nhật ký của bạn.


-2

Tạo cái này class:

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) {
            logger.info(string);
        }
        public void println(final String string) {
            logger.info(string);
        }
    };
}
}

Gọi đây trong mã của bạn

StdOutErrLog.tieSystemOutAndErrToLog();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.