2014-12-03 27 views
5

Chúng tôi sử dụng log4j 1.2.x để đăng nhập vào sản phẩm của chúng tôi và đang tìm cách di chuyển sang log4j 2.x trong tương lai gần. Một trong những chức năng chúng tôi đã thực hiện là ghi nhật ký thông tin hệ thống và các thông số quan trọng khác trên mỗi tệp nhật ký cuộn mới được tạo. Cách chúng tôi thực hiện trong log4j 1.2.x là chúng ta đã mở rộng RollingFileAppender lớp log4j và đã ghi đè phương pháp rollOver(), dưới đây là đoạn một phần của việc thực hiệnLàm thế nào để tùy chỉnh log4j2 RollingFileAppender?

@Override 
public void rollOver() { 

    super.rollOver(); //We are not modifying it's default functionality but as soon as rollOver happens we apply our logic 

    // 
    // Logic to log required system properties and important parameters. 
    // 

} 

Bây giờ khi chúng ta muốn di chuyển đến log4j2 chúng tôi xem xét một giải pháp mới để đạt được chức năng tương tự. Nhưng như tôi thấy mã nguồn cho log4j2 nó rất khác với mã nguồn cũ hơn. Lớp RollingFileAppender không chứa phương thức rollover() vì nó đã được chuyển đến RollingManagerhelper và nó đã được đặt thành private là tốt.

Phát triển một gói hoàn chỉnh mới và mở rộng/triển khai một số lớp trừu tượng/trợ giúp từ log4j2 là một trong những giải pháp khả thi cho chúng tôi, nhưng đòi hỏi nhiều mã hóa/sao chép vì chúng tôi không sửa đổi những gì RollingFileAppender. mở rộng nhỏ cho nó. Có một giải pháp đơn giản cho nó?

CẬP NHẬT

Tôi tạo ra một tra cứu tùy chỉnh theo gợi ý trong câu trả lời và dưới đây là cách tôi tạo ra nó;

@Plugin(name = "property", category = StrLookup.CATEGORY) 
public class CustomLookup extends AbstractLookup { 

private static AtomicLong aLong = new AtomicLong(0); 

@Override 
public String lookup(LogEvent event, String key) { 

    if (aLong.getAndIncrement() == 0) { 
     return "this was first call"; 
    } 
    if (key.equalsIgnoreCase("customKey")) { 
     return getCustomHeader(); 
    } else { 
     return "non existing key"; 
    } 
} 

private static String getCustomHeader() { 

    // Implementation of custom header 
    return "custom header string"; 

}} 

Nhưng điều này không hoạt động như đã đề cập; điều này luôn in this was first call trong tiêu đề. Tôi cũng đã thử đặt breakoint vào điều kiện if đầu tiên và những gì tôi nhận thấy là nó chỉ được gọi một lần. Vì vậy, những gì tôi lo sợ là lớp customLookup chỉ được khởi tạo khi khởi động khi log4j2 khởi tạo thuộc tính của nó từ cấu hình xml. Tôi không biết làm cách nào khác tôi có thể triển khai lớp tra cứu tùy chỉnh này.

CẬP NHẬT 2

Sau khi thực hiện ở trên tôi đã thử nó trong bit cách khác đó là như sau;

private static AtomicLong aLong = new AtomicLong(0); 

@Override 
public String lookup(LogEvent event, String key) { 
    return getCustomHeader(key); 
} 

private static String getCustomHeader(final String key) { 

    if (aLong.getAndIncrement() == 0) { 
     return "this was first call"; 
    } 
    if (key.equalsIgnoreCase("customKey")) { 
     // Implementation for customKey 
     return "This is custom header"; 
    } else { 
     return "non existing key"; 
    } 
} 

Nhưng điều này cũng giống như vậy. log4j2 tạo ra các tiêu đề trong khi khởi tạo từ tập tin cấu hình xml của nó và sau đó sử dụng các tiêu đề từ bộ nhớ. Giá trị return bị ghi đè lookup() phương pháp không thể thay đổi động vì nó chỉ được gọi trong khi khởi tạo. Mọi trợ giúp thêm sẽ được đánh giá cao.

+0

Nếu bạn muốn sử dụng thay thế biến thời gian chạy sử dụng đôi $$ khi chỉ định khóa biến trong tệp thuộc tính log4j2. – TrueCurry

Trả lời

5

Cách khác để sử dụng tra cứu tích hợp là tạo tra cứu tùy chỉnh. Điều này có thể được thực hiện trong một vài dòng mã với một plugin log4j2. Tra cứu tùy chỉnh của bạn sau đó cung cấp giá trị chính xác mà bạn muốn hiển thị trong tiêu đề tệp ở mỗi lần cuộn qua.

Mã plugin sẽ giống như thế này:

package com.mycompany; 
import org.apache.logging.log4j.core.LogEvent; 
import org.apache.logging.log4j.core.config.plugins.Plugin; 
import org.apache.logging.log4j.core.lookup.AbstractLookup; 
import org.apache.logging.log4j.core.lookup.StrLookup; 

/** 
* Looks up keys from a class SomeClass which has access to all 
* information you want to provide in the log file header at rollover. 
*/ 
@Plugin(name = "setu", category = StrLookup.CATEGORY) 
public class SetuLookup extends AbstractLookup { 

    /** 
    * Looks up the value of the specified key by invoking a 
    * static method on SomeClass. 
    * 
    * @param event The current LogEvent (ignored by this StrLookup). 
    * @param key the key to be looked up, may be null 
    * @return The value of the specified key. 
    */ 
    @Override 
    public String lookup(final LogEvent event, final String key) { 
     return com.mycompany.SomeClass.getValue(key); 
    } 
} 

Sau đó, trong cấu hình của bạn, bạn có thể sử dụng các tiêu đề của cách bố trí hoa văn với đầu ra này ở mọi rollover:

<RollingFile name="RollingFile" fileName="logs/app.log" 
      filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz"> 

    <!-- use custom lookups to access arbitrary internal system info --> 
    <PatternLayout header="${setu:key1} ${setu:key2}"> 
    <Pattern>%d %m%n</Pattern> 
    </PatternLayout> 
    <Policies> 
    <TimeBasedTriggeringPolicy /> 
    </Policies> 
</RollingFile> 

Các log4j2 hướng dẫn sử dụng có chi tiết về việc xây dựng/triển khai custom plugins. Tóm tắt ngắn gọn:

Cách dễ nhất là xây dựng bình của bạn với Maven; điều này sẽ gây ra bộ xử lý chú thích log4j2 để tạo ra một tệp chỉ mục nhị phân trong jar để plugin của bạn có thể được tìm thấy nhanh chóng bằng log4j2.

Cách khác là để xác định tên gói của lớp plugin của bạn trong packages thuộc tính cấu hình log4j2.xml của bạn:

<Configuration status="warn" packages="com.mycompany"> 
    ... 

UPDATE: Lưu ý rằng trong thực hiện tra cứu của bạn, bạn có thể nhận được như sáng tạo khi cần thiết . Ví dụ:

package com.mycompany; 

public class SomeClass { 
    private static AtomicLong count = new AtomicLong(0); 

    public static String getValue(final String key) { 
     if (count.getAndIncrement() == 0) { // is this the first call? 
      return ""; // don't output a value at system startup 
     } 
     if ("FULL".equals(key)) { 
      // returns info to shown on rollover, nicely formatted 
      return fullyFormattedHeader(); 
     } 
     return singleValue(key); 
    } 
    .... 
} 
+0

Tất nhiên cảm thấy tự do để sử dụng một tên plugin khác với 'setu'. :-) –

+0

có vẻ đầy hứa hẹn. sẽ thử nó – Setu

+0

Tôi đã thử nhưng hai vấn đề là khóa trong thuộc tính tiêu đề cần được định dạng hoàn toàn theo yêu cầu để được ghi lại, ví dụ: nếu sử dụng nhiều hơn một khóa trong tiêu đề thì không có cách nào để phân tách trong các dòng khác nhau. Thứ hai là vấn đề lớn, yêu cầu là in các thuộc tính hệ thống khi bắt đầu tệp rollover mới không phải lúc bắt đầu thực hiện chương trình. tiêu đề được ghi lại ở đầu mỗi lần thực hiện và tại mỗi lần rollover mà chỉ đơn giản là không có ý nghĩa. – Setu

2

Điều này có thể được thực hiện bằng cấu hình. Bạn có thể sử dụng tiêu đề của bố cục mẫu cho thông tin đầu ra. Điều này sẽ được bao gồm trong mỗi lần rollover.

<RollingFile name="RollingFile" fileName="logs/app.log" 
      filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz"> 

    <!-- use built-in lookups for system info or system properties --> 
    <PatternLayout header="${java:runtime} - ${java:vm} - ${java:os}"> 
    <Pattern>%d %m%n</Pattern> 
    </PatternLayout> 
    <Policies> 
    <TimeBasedTriggeringPolicy /> 
    </Policies> 
</RollingFile> 
+0

Cảm ơn bạn đã phản hồi @Remko nhưng một câu hỏi. Sản phẩm chúng tôi có là rất lớn và chúng tôi thiết lập nhiều thuộc tính hệ thống trong thời gian chạy, về cơ bản nó là một công cụ chạy liên tục trên máy chủ và tương tác với webservice, công cụ gui và db tại backend. sử dụng cách tiếp cận này, chúng ta cần phải viết tất cả các tên thuộc tính một cách chính xác trong tiêu đề. Có cách nào sử dụng một số loại vòng lặp để bao gồm tất cả các thuộc tính hệ thống trong tiêu đề. – Setu

+0

Bạn có thể định cấu hình một thuộc tính hệ thống trong tiêu đề và cập nhật chương trình giá trị của thuộc tính đó bằng cách nối thêm các giá trị của tất cả các thuộc tính hệ thống khác mà bạn quan tâm, điều đó có hoạt động không? –

+0

Cảm ơn bạn đã đề xuất; Tôi sẽ phải cung cấp cho nó một thử nhưng điều đó có nghĩa là bất cứ khi nào trong mã của tôi tôi thiết lập bất kỳ tài sản hệ thống, tôi sẽ phải thêm nó vào tài sản hệ thống này. Âm thanh như nó sẽ làm việc nhưng tôi nghĩ rằng điều này sẽ được coi là giải pháp thay thế bằng cách quản lý và không phải là một giải pháp thực tế. cảm ơn cho đề nghị của bạn anyway – Setu

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