2010-07-12 34 views
30

Ứng dụng của tôi có nhiều câu lệnh System.out.println().Chuyển hướng System.out.println

Tôi muốn nhận thư từ println và gửi chúng đến bộ ghi chuẩn (Log4j, JUL, v.v.).

Làm cách nào để thực hiện điều đó?

+0

thể trùng lặp của [Xóa quyền truy cập đến System.out trong java] (http://stackoverflow.com/question/1710914/remove-access-to-system-out-in-java) –

+0

Trong khi có sự giao nhau trong các câu trả lời cho điều đó, tôi không nghĩ nó đủ gần để xứng đáng một trận đấu. Nó đòi hỏi nhiều hơn cách để chặn hoàn toàn đầu ra - cái này là để chụp nó ở nơi khác. – paxdiablo

Trả lời

33

Lớp Hệ thống có setOutsetErr có thể được sử dụng để thay đổi dòng đầu ra, ví dụ, một mới PrintStream với sự ủng hộ File hoặc, trong trường hợp này, có lẽ một dòng trong đó sử dụng hệ thống phụ đăng nhập của bạn lựa chọn.


Hãy nhớ rằng bạn có thể gặp rắc rối nếu bạn định cấu hình thư viện ghi nhật ký thành đầu ra hoặc lỗi chuẩn (có thể là kiểu đệ quy vô hạn).

Nếu trường hợp đó xảy ra, bạn có thể chỉ cần chuyển và thay thế các câu lệnh kiểu số System.out.print bằng ghi nhật ký thực.

+0

Để làm cho giải pháp của bạn hoàn thành, tôi đề nghị bạn thêm hướng dẫn về cách hoàn nguyên đầu ra tiêu chuẩn bình thường khi đã chặn tất cả mọi thứ cần thiết, tức là System.setOut (new PrintStream (new FileOutputStream (FileDescriptor.out))); –

+0

@VicSeedoubleyew sẽ không tốt hơn nếu lưu trữ bản gốc 'PrintStream' và khôi phục nó sau đó - nếu cái gì khác cũng đang chuyển hướng' System.out', điều này sẽ không nhất thiết phải khôi phục lại chính xác. – neuralmer

+0

@neuralmer chắc chắn, hoạt động tốt –

8

Giải pháp tốt hơn là thực hiện và thay đổi tất cả các câu lệnh println để sử dụng thư viện ghi nhật ký thích hợp. Những gì bạn đang cố gắng làm là một hack lớn.

+0

Có thể anh ta đang cố gắng chuyển hướng Hệ thống.cho một Logger ;-) – Riduidel

+1

+1: toàn bộ * điểm * của khung đăng nhập là có thể trừu tượng nơi bạn đang ghi đầu ra, bạn nên gọi phương thức ghi nhật ký của nó là đầu ra "dứt khoát" của bạn từ mã. Chưa kể, chuyển hướng 'System.out' để gọi trình ghi nhật ký * xuất hiện * để hoạt động; ngay đến điểm mà trong đó một ngày bạn định cấu hình trình ghi nhật ký để xuất thành stdout và ** bam ** - stack overflow. –

+0

Và đây không phải là * điều đó * khó. +1 – Nivas

28

Tôi có nhu cầu tương tự một lần. Tôi cần thiết để chặn đầu ra của một số thành phần bên thứ 3 và phản ứng trên một thông báo lỗi. Khái niệm trông giống như sau:

private class Interceptor extends PrintStream 
{ 
    public Interceptor(OutputStream out) 
    { 
     super(out, true); 
    } 
    @Override 
    public void print(String s) 
    {//do what ever you like 
     super.print(s); 
    } 
} 
public static void main(String[] args) 
{ 
    PrintStream origOut = System.out; 
    PrintStream interceptor = new Interceptor(origOut); 
    System.setOut(interceptor);// just add the interceptor 
} 
+2

Ý tưởng hay. Cảm ơn giải pháp – Jacky

-1

Tôi đã áp dụng ý tưởng cơ bản về điều này và nó hoạt động tốt. Không cần thay đổi tất cả System.out. ### và System.err. ### stuff.

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

import de.msg.pm.designer.services.simulation.junit.base.Defines; 

public class Interceptor extends PrintStream 
{ 
    /** the logger */ 
    private Logger log; 
    /** the origin output stream */ 
    PrintStream orig; 

    /** 
    * Initializes a new instance of the class Interceptor. 
    * 
    * @param out the output stream to be assigned 
    * @param log the logger 
    */ 
    public Interceptor(OutputStream out, Logger log) 
    { 
    super(out, true); 
    this.log = log; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    protected void finalize() throws Throwable 
    { 
    detachOut(); 
    super.finalize(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void print(String s) 
    { 
    //do what ever you like 
    orig.print(s); 
    log.logO(s, true); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void println(String s) 
    { 
    print(s + Defines.LF_GEN); 
    } 

    /** 
    * Attaches System.out to interceptor. 
    */ 
    public void attachOut() 
    { 
    orig = System.out; 
    System.setOut(this); 
    } 

    /** 
    * Attaches System.err to interceptor. 
    */ 
    public void attachErr() 
    { 
    orig = System.err; 
    System.setErr(this); 
    } 

    /** 
    * Detaches System.out. 
    */ 
    public void detachOut() 
    { 
    if(null != orig) 
    { 
     System.setOut(orig); 
    } 
    } 

    /** 
    * Detaches System.err. 
    */ 
    public void detachErr() 
    { 
    if(null != orig) 
    { 
     System.setErr(orig); 
    } 
    } 
} 


public class InterceptionManager 
{ 
    /** out */ 
    private Interceptor out; 

    /** err */ 
    private Interceptor err; 

    /** log */ 
    private Logger log; 

    /** 
    * Initializes a new instance of the class InterceptionManager. 
    * 
    * @param logFileName the log file name 
    * @param append the append flag 
    */ 
    public InterceptionManager(String logFileName, boolean append) 
    { 
    log = new Logger(); 
    log.setLogFile(logFileName, append); 
    this.out = new Interceptor(System.out, log); 
    this.out.attachOut(); 
    this.err = new Interceptor(System.err, log); 
    this.err.attachErr(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    protected void finalize() throws Throwable 
    { 
    if(null != log) 
    { 
     log.closeLogFile(); 
    } 
    super.finalize(); 
    } 
} 

này vài dòng sẽ cho phép khai thác gỗ mà không cần thay đổi mã thêm:

if(writeLog) 
    { 
    this.logFileName = this.getClassName() + "_Log.txt"; 
    this.icMan = new InterceptionManager(this.logFileName, false); 
    System.out.format("Logging to '%s'\n", this.logFileName); 
    } 
2

Dưới đây là làm thế nào để chụp bản in để System.out, và sau đó đặt mọi thứ trở lại trật tự:

// Start capturing 
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
System.setOut(new PrintStream(buffer)); 

// Run what is supposed to output something 
... 

// Stop capturing 
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); 

// Use captured content 
String content = buffer.toString(); 
buffer.reset(); 
1

mở rộng PrintStream là một giải pháp tồi vì bạn sẽ phải ghi đè tất cả các phương thức print()println(). Thay vào đó, bạn có thể nắm bắt các dòng:

public class ConsoleInterceptor { 

    public interface Block { 
     void call() throws Exception; 
    } 

    public static String copyOut(Block block) throws Exception { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     PrintStream printStream = new PrintStream(bos, true); 
     PrintStream oldStream = System.out; 
     System.setOut(printStream); 
     try { 
      block.call(); 
     } 
     finally { 
      System.setOut(oldStream); 
     } 
     return bos.toString(); 
    } 
} 

Bây giờ bạn có thể nắm bắt nó như thế này:

String result = ConsoleInterceptor.copyOut(() ->{ 
     System.out.print("hello world"); 
     System.out.print('!'); 
     System.out.println(); 
     System.out.println("foobar"); 
    }); 
    assertEquals("hello world!\nfoobar\n", result); 
+0

Nice * reusable *. Ngoài ra tôi nghĩ giao diện Block có thể được thay thế bằng Runnable. –