2009-11-10 5 views
5

나는 여러 개별 프로그램의 컨테이너 역할을하는 응용 프로그램을 유지 관리합니다. 이러한 프로그램에는 전용 로그 기능이 있습니다. 즉, 로그하는 모든 것을 특수 로그 파일에 저장합니다.java에서 System.out에 대한 액세스 권한 제거

그럼에도 불구하고, 응용 프로그램 개발자는 System.out.println을 던져 사랑에 보인다 및 e.printStackTrace 컨테이너를 실행할 때이 불가능 깨끗한 콘솔을 유지하고, 모든 것을 호출합니다.

이러한 응용 프로그램이 System.outSystem.err을 오염시키는 것을 어떻게 막을 수 있습니까?


구현 노트 :

  • 응용 프로그램

    로깅의 log4j를 사용;
  • 컨테이너는 로깅을 위해 콘솔도 사용하지만, 수명주기 이벤트 및 문제를 위해 엄격하게 예약되어 있으므로 콘솔이 필요합니다.
  • 응용 프로그램은 사용자 정의 클래스 로더를 사용하여로드되지만 보안 검사는 적용되지 않습니다.

업데이트 :

단순히 모든 출력을 리디렉션, 그래서 이런 일이 실패 이후 System.out 작동하지 않을 리디렉션이 성공해야

System.setOut(new PrintStream(new OutputStream() { 

     @Override 
     public void write(int b) { 

      throw new Error("Not on my watch you don't"); 

     } 
    })); 

    Logger logger = Logger.getLogger(Runner.class); 
    logger.info("My log message"); 

.

업데이트 2 :

응용 프로그램이 Log4j의 시스템 클래스 로더에서로드

App app = new UrlClassLoader(...).loadClass(className)).newInstance(); 
app.setLogger(loggerForClass(app)); 

에 유사한 코드를 사용하여로드 및 구성됩니다.

+0

이것은 실제 답변이 아니지만 개발자가 로그 파일을 조사하는 것이 아니라 콘솔을 확인하는 것이 더 쉽기 때문에이 작업을 수행하는 경향이 있습니다. 그래서 체크인 할 때, 먼저 찾기/바꾸기 :'System.out' 검색 ('log.debug()'),'System.err' 검색 ('log.info()'),'printStackTrace' (delete)를 검색하십시오. 심지어 svn이 자동화 될 수도 있다고 생각합니다 (확실하지는 않지만 어떻게 할 수 있을지 생각합니다) – laura

+0

시스템 언어에서 관용구는'fork()'될 자식 프로세스의 stdout과 stderr를 리디렉션합니다. 그리고'exec()'를 사용하지만 자바 클래스 로더가 무엇인지 잘 모르겠습니다. 애플리케이션을 로딩하는 방법에 대해 더 자세히 설명해 주시겠습니까? – thirtyseven

+0

컨테이너가 log4j를 사용 중이거나 콘솔에 직접 인쇄 중입니까? – Fedearne

답변

2

여기에서 중요한 것은 출력 스트림을 리디렉션하는 전에 log4j 을 구성하는 것입니다.

5

혐오 요법을 사용하십시오. "The Inspectors"의 방문은 불쾌한 구문이 포함 된 코드를 확인할 때마다 예약됩니다.

Nice cubicle you got ere, be shame if anyfing appened to it. 
+0

음 ... 고마워요 .--) 생각할만한 가치가 있긴하지만. –

+0

와우,이 제안은 내 전혀 관련이없는 문제도 해결했습니다 ... 감사합니다! ;-) –

+0

또 다른 유용한 패턴이 있습니다 : "보상", 레드 와인, 파티 모자 및 "성가대"방문이 포함됩니다. "할렐루야!" – djna

6

Java는 표준 System.out 및 System.err을 정의하지만 사용자 스트림은이 스트림을 덮어 쓸 수 있습니다. http://www.devx.com/tips/Tip/5616

기본적으로 로깅으로 파이프하는 새 스트림을 설정하거나 데이터 플롯을 무효로 만들 수 있습니다. 필자가 선호하는 것은 후자 일 것이다. 개발자들이 System.out에 의존하는 것을 즉시 치료할 것이고, 거기에 쓰는 것이 사라지면 오류가 날 것이다.

** 업데이트 : 질문에 대한 귀하의 규정을 다시 읽었으며 여전히 컨테이너 애플리케이션 용 콘솔이 필요합니다.표준 스트림 주위에 래퍼를 작성하여 각 호출을 검사하고 부모 응용 프로그램 (또는 전달) 또는 하위 응용 프로그램 (또는 차단)에서 볼 수 있도록 래퍼를 작성하는 경우에도 여전히 작동 할 수 있습니다.

10

System.setOut()System.setErr()을 사용하여 stdoutstderrPrintStream의 인스턴스로 리디렉션하십시오.

+0

감사합니다. 내 업데이트를 참조하십시오. –

12

당신이 당신의 용기 출력을 사용하면 다음과 같은 작업을 수행 할 수 제어 할 수 있다고 가정 :

import java.io.*; 
public class SysOut { 
    public static void main(String[] args) throws Exception { 
      PrintStream pw = new PrintStream(new FileOutputStream("a.txt")); 
      PrintStream realout = System.out; 
      System.setOut(pw); 
      System.out.println("junk"); 
      realout.print("useful"); 
} 
} 

$ java SysOut 
useful 
$ cat a.txt 
junk 
+0

감사합니다. 내 업데이트를 참조하십시오. –

1

가 System.out을하고 System.err에이 RuntimeException을 던질 특별한 구현에 스트림이 ("대신에 시스템의 로그를 사용하여 변환합니다. 아웃 ").

컨테이너가 중요한 경우, 그들은

+0

감사합니다. 내 업데이트를 참조하십시오. –

+0

그런 경우에는 원하는 출력과 원하지 않는 출력을 구별하는 방법에 대한 예를 들어주십시오. 일부 수업은 이것을 허용하고 다른 수업은 허용하지 않습니까? –

+0

컨테이너에 대한 소스가 있다면 리팩터링하여 원래의 스트림을 저장하고 사용하는 것이 좋습니다. 그런 다음 System.out 및 System.err을 대체 할 수 있습니까? –

1

은 내가 무슨 짓을하는 것은 System.out에 대한의 PrintStream를 리디렉션입니다 (;-) 대신 추가 보너스 던져에서 OutOfMemoryException 용) 꽤 빨리 생각 :

을 얻을 것이다 System.err은 각각 INFO 및 ERROR 레벨 로깅으로 commons-logging합니다.

일부 스레드를 콘솔에 쓸 수있게하거나 로그를 콘솔에 보내고 싶지만 수행 할 수있게하려면이 작업이 더 까다로워집니다.

+0

예, 저는 '까다로운'지역에 있습니다. –

+0

코드를 재 입력 할 수 있습니다. 즉 OutputStream.write가 호출 될 때 플래그를 설정합니다. 플래그가 설정되어 있지 않으면 로거에 인쇄하십시오. 설정되어 있으면 로거에서 가져온 것이므로 정상적으로 인쇄하십시오. –

+0

참고 : finally 블록에서 플래그를 설정 해제해야합니다. ;) –

0

우리는 log4j 트릭을 사용하지만 별도의 파일 (stdout.log, stderr.log)에 로그합니다. 로깅을 실제로 이해하는 부분과 출력이 섞여있는 것은 유용하지 않습니다 ...

1

실제로 교체하기 전에 System.out/err을 가져 와서 저장할 수 있습니다.

OutputStream out=System.getOut(); // I think the names are right 
System.setOut(some predefined output stream, null won't work); 
out.println("Hey, this still goes to the output"); 
System.out.println("Oh noes, this does not"); 

나는 코드베이스의 모든에서 System.out.println의를 차단하고 온 메소드 이름/행 번호와 함께 출력의 각 행을 앞에하려면이 옵션을 사용했습니다.

1

System.out 및 System.err 스트림을 닫습니다.

+0

감사합니다. 내 업데이트를 참조하십시오. –

+0

JVM이 이러한 스트림을 만들었으므로 [JVM이 스트림을 만들어야] (http://stackoverflow.com/a/7457737/545127) 논쟁의 여지가 있습니다. – Raedwald

3

머리가없는 빌드 메커니즘을 사용하는 경우, 개미 같은 경우 CheckStyle을 빌드에 추가하고 코드에서 System.out.println 또는 e.printStackTrace를 찾으면 빌드를 실패하도록 checkstyle을 구성 할 수 있습니다.

헤드리스 빌드가없는 경우 반복 빌드 가능 예측 가능한 빌드이므로 빌드를 권장합니다.

3

System.setOut은 출력을 모두 리디렉션합니다. 그러나 사용자가 제공 한 PrintStream은 출력 처리 방법을 결정할 수 있습니다. 따라서 응용 프로그램의 명령문 만 실제로 출력 할 수있는 스트림을 제공 할 수있을 것이라고 확신합니다.

유일한 까다로운 부분은 실제로 유효한 전화인지 아닌지를 감지 할 수 있습니다. 작동하지만 매우 느린 방법은 Thread.currentThread().getStackTrace()으로 전화하여 적어도 어떤 코드 (또는 패키지)가 사용자에게 전화하고 있는지 (유효하지 않은 경우 단순히 반환) 확인하는 것입니다. 성능이 떨어지면 엄청난 것이기 때문에 권장하지는 않습니다. 특히 모든 바이트를 읽을 때마다 이렇게하는 것이 좋습니다.

유효한 모든 컨테이너 스레드에서 ThreadLocal 플래그를 설정하는 것이 더 좋은 방법 일 수 있습니다.당신은 컨테이너 코드에 println의를 변경할 수 있다면

public class ThreadValidity extends ThreadLocal<Boolean> 
{ 
    private static final INSTANCE = new ThreadValidity(); 

    @Override Boolean initialValue() { return false; } 
    public static ThreadValidity getInstance() { return INSTANCE; } 
} 

class VerifyingPrintStream extends PrintStream 
{ 
    private boolean isValidThread() 
    { 
     return ThreadValidity.instance().get(); 
    } 

    public void println(String s) 
    { 
     if (!isValidThread()) return; 
     super.println(s); 
    } 

    public void println(Object o) 
    { 
     if (!isValidThread()) return; 
     super.println(o); 
    } 

    // etc 
} 

또한, 일을 더 쉽게 얻을 : 그럼 당신은 다음과 같은의 PrintStream 뭔가를 구현할 수 있습니다. 특정 작업자에게 모든 콘솔 기록을 전달할 수 있습니다. 실제 System.out을 no-op writer로 설정하면서 System.out (자체 필드에 저장하고 출력 작성을 위해 직접 사용)을 "도용"하도록하십시오.

관련 문제