2011-10-13 39 views
13

Vì lý do bảo mật, tôi cần xem mọi thư đã đăng nhập trong ứng dụng của mình và có thể sửa đổi nó trước khi nó đi vào tệp nhật ký. Tôi figured tôi có thể viết một appender tùy chỉnh (mở rộng DailyRollingFileAppender) và ghi đè lên subAppend (LoggingEvent sự kiện). Vấn đề là, không có setter cho văn bản tin nhắn trong LoggingEvent, và tin nhắn là một thuộc tính riêng. Tôi có thể tạo một LoggingEvent mới với thông điệp đã được sửa đổi của tôi, nhưng API không làm cho nó dễ dàng sao chép qua phần còn lại của LoggingEvent ban đầu. Tất cả dường như được thiết kế để ngăn cản việc can thiệp vào thông điệp trong một ứng dụng tùy chỉnh.LOG4J: Sửa đổi thông báo đã đăng nhập bằng cách sử dụng tùy biến appender

Tùy chọn duy nhất khác mà tôi có thể thấy là sửa đổi hàng trăm câu lệnh ghi nhật ký để gọi một phương thức toàn cầu mới có thể sửa đổi văn bản trước và sau đó thực hiện cuộc gọi Log4J. Tôi không muốn!

Có ai khác có nhu cầu sửa đổi thông điệp đã đăng nhập trong ứng dụng tùy chỉnh không?

Trả lời

0

Tôi muốn tạo lớp đại biểu cho Logger và thay đổi tất cả các mục nhập từ org.apache.log4j.Logger thành your.own.Logger. Đó là một quá trình đơn giản và tự động — vì bạn xem xét việc thay đổi các cuộc gọi nhật ký trong mã, tôi cho rằng bạn có toàn quyền truy cập vào mã nguồn. Trong đại biểu, bạn sẽ gọi chính xác các phương thức từ log4j Logger, nhưng can thiệp bằng các chuỗi đầu tiên vào nội dung trái tim của bạn.

Tôi đã duyệt qua mã và trước phiên bản 1.2.15 tạo mới LoggingEvent từ hiện tại là không thể mà không cần đào qua một nửa thư viện. Từ 1.2.15 trên không có vấn đề với nó.

11

Tôi không hoàn toàn chắc chắn lý do tại sao tạo một LoggingEvent mới là rất quan trọng. Điều này dường như làm việc cho tôi:

package test.logging; 

import org.apache.log4j.DailyRollingFileAppender; 
import org.apache.log4j.spi.LoggingEvent; 

public class MyDailyRollingFileAppender extends DailyRollingFileAppender { 

    @Override 
    protected void subAppend(LoggingEvent event) { 
     String modifiedMessage = String.format("**** Message modified by MyDailyRollingFileAppender ****\n\n%s\n\n**** Finished modified message ****", event.getMessage()); 
     LoggingEvent modifiedEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getTimeStamp(), event.getLevel(), modifiedMessage, 
                 event.getThreadName(), event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(), 
                 event.getProperties()); 

     super.subAppend(modifiedEvent); 
    } 

} 

Với xét nghiệm này:

package test; 

import org.apache.log4j.Logger; 

public class TestLogging { 

    public static void main(String[] args) { 
     Logger log = Logger.getLogger(TestLogging.class); 
     log.info("I am testing my logging"); 
     log.info("Here is an exception", new Exception()); 
    } 

} 

và cấu hình này:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 

    <appender name="MyDailyRollingFileAppender" class="test.logging.MyDailyRollingFileAppender"> 
     <param name="Append" value="true"/> 
     <param name="datePattern" value="'.'yyyy-MM-dd"/> 
     <param name="File" value="mine.log"/> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p (%x) [%t] %c{1} - %m%n" /> 
     </layout> 
    </appender> 

    <root> 
     <priority value="debug"/> 
     <appender-ref ref="MyDailyRollingFileAppender"/> 
    </root> 

</log4j:configuration> 

Tôi nhận được kết quả như sau:

2011-10-14 10:09:09,322 INFO () [main] TestLogging - **** Message modified by MyDailyRollingFileAppender **** 

I am testing my logging 

**** Finished modified message **** 
2011-10-14 10:09:09,333 INFO () [main] TestLogging - **** Message modified by MyDailyRollingFileAppender **** 

Here is an exception 

**** Finished modified message **** 
java.lang.Exception 
    at test.TestLogging.main(TestLogging.java:10) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 

Mặc dù tôi đã làm điều gì đó simila r này, tôi sử dụng một cách tiếp cận hơi khác nhau. Thay vì viết các lớp con của mỗi loại Appender Tôi muốn sử dụng, tôi đã tạo một Appender kết thúc các đối tượng Appender khác và sửa đổi thông báo trước khi gửi đến gói Appender s. Một cái gì đó như thế này:

package test.logging; 

import org.apache.log4j.Appender; 
import org.apache.log4j.AppenderSkeleton; 
import org.apache.log4j.spi.AppenderAttachable; 
import org.apache.log4j.spi.LoggingEvent; 

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Enumeration; 
import java.util.Iterator; 
import java.util.List; 

public class MyAppenderWrapper extends AppenderSkeleton implements AppenderAttachable { 

    private final List<Appender> appenders = new ArrayList<Appender>(); 

    public void close() { 
     synchronized (appenders) { 
      for (Appender appender : appenders) { 
       appender.close(); 
      } 
     } 
    } 

    public boolean requiresLayout() { 
     return false; 
    } 

    public void addAppender(Appender appender) { 
     synchronized (appenders) { 
      appenders.add(appender); 
     } 
    } 

    public Enumeration getAllAppenders() { 
     return Collections.enumeration(appenders); 
    } 

    public Appender getAppender(String name) { 
     synchronized (appenders) { 
      for (Appender appender : appenders) { 
       if (appender.getName().equals(name)) { 
        return appender; 
       } 
      } 
     } 
     return null; 
    } 

    public boolean isAttached(Appender appender) { 
     synchronized (appenders) { 
      for (Appender wrapped : appenders) { 
       if (wrapped.equals(appender)) { 
        return true; 
       } 
      } 
      return false; 
     } 
    } 

    public void removeAllAppenders() { 
     synchronized (appenders) { 
      appenders.clear(); 
     } 
    } 

    public void removeAppender(Appender appender) { 
     synchronized (appenders) { 
      for (Iterator<Appender> i = appenders.iterator(); i.hasNext();) { 
       if (i.next().equals(appender)) { 
        i.remove(); 
       } 
      } 
     } 
    } 

    public void removeAppender(String name) { 
     synchronized (appenders) { 
      for (Iterator<Appender> i = appenders.iterator(); i.hasNext();) { 
       if (i.next().getName().equals(name)) { 
        i.remove(); 
       } 
      } 
     } 
    } 

    @Override 
    protected void append(LoggingEvent event) { 
     String modifiedMessage = String.format("**** Message modified by MyAppenderWrapper ****\n\n%s\n\n**** Finished modified message ****", event.getMessage()); 
     LoggingEvent modifiedEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getTimeStamp(), event.getLevel(), modifiedMessage, 
                 event.getThreadName(), event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(), 
                 event.getProperties()); 

     synchronized (appenders) { 
      for (Appender appender : appenders) { 
       appender.doAppend(modifiedEvent); 
      } 
     } 
    } 

} 

nào bạn có thể cấu hình như:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 

    <appender name="StdOut" class="org.apache.log4j.ConsoleAppender"> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p (%x) [%t] %c{1} - %m%n" /> 
     </layout> 
    </appender> 

    <appender name="FileAppender" class="org.apache.log4j.DailyRollingFileAppender"> 
     <param name="Append" value="true"/> 
     <param name="datePattern" value="'.'yyyy-MM-dd"/> 
     <param name="File" value="mine.log"/> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p (%x) [%t] %c{1} - %m%n" /> 
     </layout> 
    </appender> 

    <appender name="AppenderWrapper" class="test.logging.MyAppenderWrapper"> 
     <appender-ref ref="StdOut"/> 
     <appender-ref ref="FileAppender"/> 
    </appender> 

    <root> 
     <priority value="debug"/> 
     <appender-ref ref="AppenderWrapper"/> 
    </root> 

</log4j:configuration> 

Bằng cách đó thông điệp vẫn còn được gửi đến appenders gốc nhưng với thông điệp thay đổi.

+2

Nó hoạt động vì bạn đang sử dụng phiên bản 1.2.15+. Các phiên bản log4j trước đó không có một số phương pháp bạn sử dụng trong các ví dụ của bạn, do đó sự cố của tác giả. Nhiều dự án sử dụng phiên bản 1.2.14, vì nó từng là phiên bản mới nhất trong một thời gian dài. – MaDa

+1

Tôi đã nâng cấp lên 1.2.16 và có thể sử dụng ví dụ của bạn để tạo LoggingEvent mới. Cảm ơn đã giúp đỡ! – user993719

4

Tùy chọn khác là tùy chỉnh Bố cục được người dùng ứng dụng của bạn sử dụng. Kể từ khi bố trí chịu trách nhiệm cho serializing sự kiện đăng nhập vào một chuỗi, tôi muốn kiểm tra nếu twitching bố trí là ít phức tạp hơn thay đổi appender và các sự kiện đi qua. Chỉ là một ý tưởng ...

+0

Có! Đó là âm thanh giống như một cách tiếp cận thích hợp thay vì sửa đổi các ứng dụng. Một bố trí tùy chỉnh có thể được sử dụng thay cho nhiều ứng dụng – hellojava

3

Thats làm thế nào tôi đã làm kể từ khi tôi đang làm việc với phiên bản cũ của log4j

Thay vì tùy appender, tôi tùy chỉnh cách bố trí và gọi đó bố trí ở bất cứ appender tôi cần tính năng này

public class LogValidatorLayout extends PatternLayout { 

    public LogValidatorLayout() { 
     super(); 
    } 

    public LogValidatorLayout(String pattern) { 
     super(pattern); 
    } 

    @Override 
    public String format(LoggingEvent event) { 

     // only process String type messages 
     if (event.getMessage() != null && event.getMessage() instanceof String) { 

      String message = event.getMessage().toString(); 
      message = StringUtils.trim("Some custom text --->>"+message); 

      // earlier versions of log4j don't provide any way to update messages, 
      // so use reflections to do this 
      try { 
       Field field = LoggingEvent.class.getDeclaredField("message"); 
       field.setAccessible(true); 
       field.set(event, message); 
      } catch (Exception e) { 
       // Dont log it as it will lead to infinite loop. Simply print the trace 
       e.printStackTrace(); 
      } 

     } 

     return super.format(event); 
    } 

} 

Và trong log4j.properties hoặc xml của bạn, hãy đăng ký Giao diện này

log4j.appender.STDOUT.layout=a.b.c.package.LogValidatorLayout 
Các vấn đề liên quan