2009-09-28 22 views
38

Nhiều khung khai thác gỗ (tiếng thở dài) cho Java đều thực hiện tốt công việc hiển thị số dòng của tên tệp nguồn cho phương pháp đã tạo thông điệp tường trình:Ghi nhật ký Java: hiển thị số dòng nguồn của người gọi (không phải là phương thức trợ giúp ghi nhật ký)

log.info("hey"); 

[INFO] [Foo:413] hey 

Nhưng nếu có phương thức trợ giúp ở giữa, người gọi thực tế sẽ là phương thức trợ giúp và không quá thông tin.

log_info("hey"); 

[INFO] [LoggingSupport:123] hey 

Có cách nào để báo cho hệ thống ghi nhật ký xóa một khung khỏi khung gọi khi tìm vị trí nguồn để in?

Tôi cho rằng đây là triển khai cụ thể; những gì tôi cần là Log4J thông qua Commons Logging, nhưng tôi muốn nghe về các lựa chọn khác.

+1

+1 câu hỏi thú vị. – KLE

+0

Liên quan: [Gọi phương thức log của log4j gián tiếp (từ phương thức trợ giúp)] (http://stackoverflow.com/questions/23880055/calling-log4js-log-methods-indirectly-from-a-helper-method) –

Trả lời

4

Xin lưu ý rằng cho số dòng là một cái gì đó rất tốn kém, hoặc cho những gì bạn nhận được một cách tự nhiên từ Log4j hoặc sau. Bạn phải chấp nhận chi phí mà ...

Bạn có thể sử dụng các API sau:

StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace(); 
    StackTraceElement stackTraceElement = ...; 
    stackTraceElement.getLineNumber(); 

Cập nhật:

Bạn sẽ phải tính toán nó cho mình. Vì vậy:

  • hỏi log4j không ra nó (ở định dạng đăng nhập của bạn),
  • và chèn cho mình số explicitement dòng vào đầu thông điệp của bạn (String bạn gửi đến log4j).

Tùy vào cách bạn thích logger của bạn, phương pháp helper của bạn có thể:

  • sử dụng một Logger rõ ràng (thông qua như là một tham số tôi đoán), khi thích hợp (đôi khi chúng ta định nghĩa logger cụ thể cho bối cảnh cụ thể, ví Ví dụ, chúng ta có một logger để gửi các yêu cầu cơ sở dữ liệu của chúng ta, cho dù chúng ta có lớp gì đi chăng nữa, điều này cho phép chúng ta giảm một nơi các thay đổi được thực hiện cho tập tin cấu hình của chúng ta, khi chúng ta muốn (de-) kích hoạt chúng ...)
  • sử dụng Trình ghi nhật ký cho lớp gọi: trong trường hợp này, thay vì chuyển tham số, bạn có thể suy ra cuộc gọi er class name tương tự như vậy ...
+1

Tôi giả sử rằng Log4J đang làm một cái gì đó như thế này. Những gì tôi muốn làm là yêu cầu nó bỏ qua một khung khác trong tính toán của nó. Tôi có thể tự mình làm tất cả các phép tính, nhưng tôi vẫn cần bằng cách nào đó chuyển thông tin này vào hệ thống ghi nhật ký, nếu không thì tùy chọn định dạng nhật ký sẽ không nhận ra số dòng ưa thích của tôi. – Thilo

+0

Có, bạn sẽ phải tự mình tính toán. Vì vậy, yêu cầu log4j không để xuất nó (trong định dạng đăng nhập của bạn), và chèn cho mình dòng số rõ ràng trong phần đầu của tin nhắn của bạn (String bạn gửi đến log4j). (Tôi thêm điều này vào câu trả lời) – KLE

+0

Chi phí ít hơn nhiều trong JVM hiện đại. –

1

Không thể thoát khỏi hộp này. Điều tốt nhất bạn có thể làm trong trường hợp này là tạo logger trong người gọi và chuyển nó đến phương thức util. Bằng cách này, bạn có thể ít nhất có được một ý tưởng mà cuộc gọi đến từ đâu.

+0

Có, điều đó sẽ cho tôi tên loại nhật ký chính xác (nhưng vẫn là số dòng sai). Đó là một sự cải tiến ... – Thilo

+0

Tôi nghĩ rằng có lẽ tôi nên có phương pháp trợ giúp chỉ cần tạo thông điệp tường trình (chuỗi), và sau đó gọi logger trực tiếp: log.info (getLogMessage ("hey")) – Thilo

+1

Điều này bây giờ có thể sử dụng cơ sở trình bao bọc logger của log4j2, và phương thức logIfEnabled, có thể tra cứu dấu vết ngăn xếp cho một tên lớp FQCN được chỉ định đầy đủ, xem câu trả lời của tôi và liên kết ở trên –

2

Thêm chi tiết vào câu trả lời KLE. (xin lỗi, người dùng noob, không biết cách nào tốt hơn là tạo câu trả lời riêng)

Thay vì dán số dòng vào thư, bạn có thể đặt nó vào ngữ cảnh MDC. Xem org.apache.log4j.MDC

Ví dụ:

StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace(); 
StackTraceElement stackTraceElement = ...; 
int l = stackTraceElement.getLineNumber(); 

MDC.put("myLineNumber", l); 

đó cho phép người dùng sử dụng mylineNumber trong tập tin cấu hình log4j họ

<layout class="org.apache.log4j.PatternLayout"> 
    <param name="ConversionPattern" 
      value="Line(%X{myLineNumber})- %m%n"/> 
</layout> 

Lưu ý: cho phép người dùng kiểm soát ở đâu và như thế nào số dòng xuất hiện trong thông điệp. Tuy nhiên, kể từ khi nhận được stacktrace là rất tốn kém, bạn vẫn cần phải tìm một cách để tắt tính năng này.

29

Câu trả lời thay thế.

Có thể hỏi log4j để loại trừ các lớp helper bằng cách sử dụng phương pháp này

Category.log (String callerFQCN, mức độ ưu tiên, thông điệp Object, t Throwable)

và xác định các lớp helper như ' callerFQCN '.

Ví dụ ở đây là một lớp học sử dụng một helper:

public class TheClass { 
    public static void main(String...strings) { 
     LoggingHelper.log("Message using full log method in logging helper."); 
     LoggingHelper.logNotWorking("Message using class info method"); 
}} 

và mã của helper:

public class LoggingHelper { 
private static Logger LOG = Logger.getLogger(LoggingHelper.class); 

public static void log(String message) { 
    LOG.log(LoggingHelper.class.getCanonicalName(), Level.INFO, message, null); 
} 

public static void logNotWorking(String message) { 
    LOG.info(message); 
} } 

Phương pháp đầu tiên sẽ ra kết quả mong đợi của bạn.

 
Line(TheClass.main(TheClass.java:4)) Message using full log method in logging helper. 
Line(LoggingHelper.logNotWorking(LoggingHelper.java:12)) Message using class info method 

Khi sử dụng phương pháp này, Log4j sẽ hoạt động như bình thường, tránh tính toán dấu vết ngăn xếp nếu không cần thiết.

+0

Tôi cũng tìm giải pháp này, nhưng theo như tôi có thể nói phương pháp bạn mô tả là dành cho [log4j1.2 API] (https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Category.html), cung cấp Category.log (String callerFQCN, Mức độ ưu tiên , Object message, Throwable t). Dường như không tương đương với [Logger trong API log4J 2.5] (https://logging.apache.org/log4j/2.0/log4j-api/apidocs/index.html). Ai có thể đưa ra câu trả lời tương thích với việc sử dụng trực tiếp Log4J 2.x? –

+0

[Nhật ký Java: Log4j Version2.x: hiển thị phương thức của người gọi (không phải là phương thức trợ giúp ghi nhật ký trung gian)] (http://stackoverflow.com/questions/35360887/java-logging-log4j-version2-x-show- phương pháp-of-the-caller-not-an-intermedia) –

1

Nếu bạn có phương pháp tiện ích ghi nhật ký riêng, bạn có thể thêm lanh và tên tệp vào danh sách đối số ghi nhật ký và thực hiện tuyến đường cpp. nghĩa là Tiền xử lý bạn phải thay thế các thẻ như _ LINE _ và _ FILE _ trước khi bạn biên dịch. Như là một tiền thưởng thêm này sẽ không mất nerly như nhiều nguồn lực như figuring ra tại thời gian chạy.

+0

Java có cơ sở tiền xử lý như vậy không? – Thilo

+0

Viết trình nạp lớp hoặc chỉ tiền xử lý tệp jar quét các lớp để ghi nhật ký và thay thế trình giữ chỗ tương ứng. –

0

lẽ bạn có thể thực hiện các chức năng đăng nhập helper sử dụng các yếu tố vết đống, lấy số dòng, và bỏ qua các khung với phương pháp với một số chú thích cụ thể, như,

public @interface SkipFrame {} 

// helper function 
@SkipFrame // not necessary on the concrete log function 
void log(String... message) { 
    // getStackTrace()... 
    int callerDepth = 2; // a constant number depends on implementation 
    StackTraceElement callerElement = null; 
    for (StackTraceElement e: stackTrace) { 
     String className, methodName = e.getClassName, getMethodName()... 
     Class callClass = Class.forName(className); 
     // since there maybe several methods with the same name 
     // here skip those overloaded methods 
     Method callMethod = guessWhichMethodWithoutSignature(callClass, methodName); 
     SkipFrame skipFrame = callMethod.getAnnotation(SkipFrame.class); 
     if (skipFrame != null) 
      continue; // skip this stack trace element 
     if (callerDepth-- == 0) { 
      callerElement = e; 
      break; 
     } 
    } 
    assert callerDepth == 0; 
    assert callerElement != null; 
    Log4j.info(callerElement.getLineNumber()... + "message... "); 
} 

@SkipFrame 
void logSendMail(Mail mailObject) { 
    log("Send mail " + mailObject.getSubject()); 
} 

Như vậy, nếu chức năng helper là lồng nhau, hoặc có nhiều chức năng trợ giúp được sử dụng, chỉ cần đánh dấu chú thích SkipFrame trên tất cả chúng và bạn sẽ nhận được số dòng nguồn chính xác những gì bạn thực sự muốn.

2

Comes ra rằng có một giải pháp rất đơn giản, chỉ cần thêm FQCN (Lớp wrapper tên lớp đầy đủ) để logger helper của bạn:

public class MyLogger extends Logger { 

private static final String FQCN = MyLogger.class.getName() + "."; 

protected MyLogger(String name) { 
    super(name); 
} 

public void info(final Object msg) { 
    super.log(FQCN, Level.INFO, msg, null); 
} 

//etc... 

Trong giai cấp công nhân của bạn, bạn chỉ cần làm:

public class MyClass { 

private static final Logger LOG = MyLogger.getLogger(); 

private void test() 
{ 
    LOG.info("test"); 
} 

} 
+1

Làm cách nào để bạn nhận được số dòng? –

+0

@SamuelEdwinWard Khung đăng nhập sẽ tìm ra số dòng. Chuỗi FQCN sẽ chỉ cho trình ghi nhật ký biết có bao nhiêu khung ngăn xếp để bỏ qua. –

2

Đối với Log4j2 câu trả lời được cung cấp hoàn toàn bằng cách sử dụng trình bao gói nhật ký như được mô tả trong sổ tay Log4j2 theo Example Usage of a Generated Logger Wrapper. Người ta có thể tạo ra một cách đơn giản (bằng cách sử dụng org.apache.logging.log4j.core.tools.Tạo các công cụ $ ExtendedLogger được minh họa ở đó) một trình bao logger với một mức STUB duy nhất, và sau đó điều chỉnh để tạo các phương thức ghi tùy chỉnh bắt chước việc sử dụng logIfEnabled (FQCN, LEVEL, Marker, message, Throwable) - có thể bỏ qua mức STUB và sử dụng thường xuyên - sau đó nếu muốn, xóa hoặc bình luận ra mức STUB và các phương thức của nó). Với mục đích này, FormattedMessage có thể hữu ích. Dòng mã nguồn, trong khi đắt tiền, sau đó có thể dễ dàng được hiển thị như một phần của thông tin vị trí đầy đủ bằng cách sử dụng phần tử mẫu chuyển đổi vị trí% l trong cấu hình PatternLayout được đưa ra trong cấu hình hoặc cụ thể hơn bằng cách sử dụng số dòng% L và/hoặc chuyển đổi phương thức% M.

Bây giờ với ví dụ hoàn chỉnh tại: Java Logging: Log4j Version2.x: show the method of an end-client caller (not an intermediate logging helper method)

Các vấn đề liên quan