Whiteship's Note

자바 System.out.println 콘솔 출력 가로채기

Java : 2010.01.25 16:49


public class Sout {

    public void hi(){
        System.out.println("hi");
    }

}

이렇게 콘솔에 어떤 메시지를 출력하는 경우가 있을 때 저걸 애플리케이션에서 캡춰할 수 있는 걸 만들어 보는 과제가 떨어졌다.

public class SoutTest {

    SoutInterceptor soutInterceptor = new SoutInterceptor();

    @Test
    public void sout() throws IOException {
        soutInterceptor.active();

        Sout sout = new Sout();
       sout.hi();

        assertThat(soutInterceptor.getMessages(), is("hi"));
    }

}

간단하게 테스트를 만들고 돌려보기 시작했다. 캡춰한 메시지를 어떻게 가져올지가 고민이었는데 그냥 생각난 가장 단순한 방법으로 가져오게했다. 이제 남은건 SoutInterceptor라는 녀석을 만드는 일이다. 뭘 어찌해야 한담 @_@;

가장 먼저 떠오른 방법은 콘솔을 모니터링 하는것이다. 그런데.. 넘 복잡할 것같고 막연하다. 다음으로 떠오른게 AOP. out.println()을 할 때 가로챌 수 있지 않을까? 하지만 힌트가 전달됐다. out을 교체할 수 있단다. 크헉.. 이건 뭐 거의 정답 수준의 힌트이지만 그렇게 간단하지는 않다고 한다. 좋아 해보자.

코딩은 구글신과 함께.. (또는 사부님 말씀대로 이클립스 코드를 뒤지면 나올지도 모른다. 사부님은 이미 뒤져본 것 같다. 자신이 생각한 방법과 동일한 방법을 사용했다고 한다. 어떤 건지는 안 찾아봐서 모르겠다;; 수천 수만 개나 되는 소스 코드를 받아오기도 귀찮고 그걸 IDE에 로딩하는데 엄청 오래 걸릴 것이며 잘못해서 뻑나거나 빌드가 안되고 컴파일 에러잡고 그러면서 삼천포로 가고 싶진 않았다.)

public class SoutInterceptor {

    private PipedInputStream pipedInputStream;
    private PrintStream originalPrint;

    public SoutInterceptor() {
        originalPrint = System.out;
        this.pipedInputStream = new PipedInputStream();
    }

    public String getMessages() throws IOException {
        byte[] messages = new byte[pipedInputStream.available()];
        pipedInputStream.read(messages, 0, messages.length);
        return new String(messages);
    }

    public void active() throws IOException {
        final PipedOutputStream pipedOutputStream = new PipedOutputStream(pipedInputStream);
        PrintStream saveStream = new PrintStream(pipedOutputStream) {
            @Override
            public void println(String x) {
                try {
                    pipedOutputStream.write(x.getBytes());
                } catch (IOException e) {
                    System.out.println("error");
                }
                originalPrint.println(x);
            }
        };
        System.setOut(saveStream);
    }

}

오호.. 잘 돌아간다.. +_+.

테스트를 좀 더 해보자.

        sout.hello();
       
        assertThat(soutInterceptor.getMessages(), is("hello"));

아래에 이렇게 추가하고 hello() 메서드 안에서는 hello를 출력하게 했다. 또 테스트가 잘 돌아간다. 흠.. 이제 맞게 한건가?

println(Stirng x)를 재정의 했는데 print(int), println(boolean) 를 호출할 때도 잘 동작한다. 왜그럴까?

top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2010.01.25 21:15 PERM. MOD/DEL REPLY

    넘 배낀티가...

    기선 2010.01.26 08:21 PERM MOD/DEL

    검색하니까 자바 API 문서밖에;;@_@;

  2. Favicon of http://lf.hisfy.com/ BlogIcon 엽우 2010.01.26 01:36 PERM. MOD/DEL REPLY

    print(int) 계열 메서드가 내부에서 print(String)을 호출하는 게 아닐까요?

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.26 17:02 신고 PERM MOD/DEL

    PrintStream 클래스 내부에선 전부 write() 쪽을 호출했던것 같은데 write()는 private이라 재정의할 수가 없더군요

  3. Favicon of http://blog.lckymn.com BlogIcon Kevin 2010.01.26 16:34 PERM. MOD/DEL REPLY

    "println(Stirng x)를 재정의 했는데 print(int), println(boolean) 를 호출할 때도 잘 동작한다. 왜그럴까?"
    정말 잘 동작하나요?ㅡ_ㅡ?
    테스트는 통과할지도 모르지만, 콘솔에는 안 찍힐것 같은데요.
    메세지 가로채는게 되는거는, PrintStream 생성할때 넘기신 PipedOutputStream 때문이겠죠. :)
    JDK쪽 코드를 검토하지는 않았지만, PrintStream 내부의 Writer 등이 새로 만들어 넣으신
    OutputStream을 포함/이용 하는 Wrtier로 생성되어서 그럴껍니다.
    (궁극적으로는 PipedOutputStream 의 write 메소드가 호출될때
    PipedOutputStream 오브젝 생성시 집어넣은 PipedInputStream 에 메세지 내용이 기록되겠죠).
    그럼 굳이 print계열 메소드를 override 하지 않아도 메세지는 가로채지겠죠.
    근데 콘솔에는 아무것도 안 찍히니, print계열 메소드를
    override 해서 원래 있던 System의 PrintStream을 가지고 결과를 찍어주는
    코드를 넣어 줘야겠죠.
    (try-catch블록을 아예 없애고 super.println(x); 로 대체해도 메세지는 가로채집니다만,
    e.g.
    super.println(x);
    originalPrint.println(x);
    println 같이 줄바꿈까지 하는 메소드의 경우는
    가로챈 메세지 뒤에 "\n" 까지 더해지겠죠).

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.26 17:10 신고 PERM MOD/DEL

    앗.. 그렇군요. PrintStream이 바뀌면서 그 안의 Writer가 아얘 바뀐거로군요.

    확인해본 결과 Kevin님께서 말씀해주신것처럼 동작했습니다. println(Stinrg)으로 호출한 것만 콘솔에 찍히더라구요.

    흐흣.. 감사합니다. :)

  4. J.U. 2012.06.08 01:51 PERM. MOD/DEL REPLY

    프로그래밍 중 콘솔 출력 메시지를 가로채올 일이 있었는데, 포스팅이 정말 큰 도움이 되었습니다. 감사합니다!!

Write a comment.




: 1 : ··· : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 31 : ··· : 140 :