이 많이 의 재료를 밖으로 이 예외의 스택 트레이스를 인쇄하는 것은 잘못된 방법입니다 제안합니다.
예를 들어 Checkstyle의 RegexpSingleline 확인에서 :
이 검사는 […] ex.printStacktrace () 호출과 같은 일반적인 나쁜 습관을 찾는 데 사용할 수 있습니다.
그러나 스택 추적이 예외의 원인을 추적하는 데 매우 유용하기 때문에 유효한 이유를 제공하는 곳을 찾기 위해 고심하고 있습니다. 내가 알고있는 것 :
-
최종 사용자에게 스택 추적이 표시되지 않아야합니다 (사용자 경험 및 보안 목적으로)
-
스택 추적 생성은 비교적 비싼 프로세스입니다 (대부분의 ‘예외적’환경에서는 문제가되지는 않지만)
-
많은 로깅 프레임 워크가 스택 추적을 인쇄합니다 (우리는 그렇지 않습니다. 쉽게 변경할 수 없습니다).
-
스택 추적을 인쇄한다고해서 오류가 처리되지는 않습니다. 다른 정보 로깅 및 예외 처리와 함께 사용해야합니다.
코드에 스택 추적을 인쇄하지 않는 다른 이유는 무엇입니까?
답변
Throwable.printStackTrace()
스택 추적을 System.err
PrintStream에 씁니다 . System.err
JVM 프로세스 의 스트림 및 기본 표준 “오류”출력 스트림은 다음을 통해 리디렉션 될 수 있습니다.
- 에서
System.setErr()
가리키는 대상을 변경하는 호출System.err
. - 또는 프로세스의 오류 출력 스트림을 리디렉션하여. 오류 출력 스트림이 파일 / 장치로 리디렉션 될 수 있습니다
- 직원이 내용을 무시할 수있는 경우
- 파일 / 장치는 로그 회전이 불가능할 수 있으며, 파일 / 장치의 기존 내용을 아카이브하기 전에 열린 파일 / 장치 핸들을 닫으려면 프로세스를 다시 시작해야한다고 가정합니다.
- 또는 파일 / 장치는의 경우와 같이 실제로 기록 된 모든 데이터를 버립니다
/dev/null
.
위에서 언급 한 것처럼, 호출 Throwable.printStackTrace()
은 유효한 (좋은 / 큰 것은 아닌) 예외 처리 동작을 구성합니다.
System.err
애플리케이션 수명 기간 동안 재 할당 되지 않은 경우 ,- 응용 프로그램이 실행되는 동안 로그 회전이 필요하지 않은 경우
- 응용 프로그램의 허용 / 설계 로깅 방법은
System.err
(및 JVM의 표준 오류 출력 스트림)에 기록하는 것입니다.
대부분의 경우 위의 조건이 충족되지 않습니다. JVM에서 실행되는 다른 코드를 인식하지 못하고 로그 파일의 크기 나 프로세스의 런타임 기간을 예측할 수 없으며 잘 설계된 로깅 방법은 “머신 분석 가능”로그 파일 작성을 중심으로 수행됩니다 (a 알려진 목적지에있는 로거의 선호하지만 선택적인 기능).
마지막으로,의 출력은 Throwable.printStackTrace()
다른 컨텐트에 쓰여질 것입니다 System.err
( System.out
둘 다 동일한 파일 / 장치로 리디렉션 된 경우 에도 ). 이는 예외 관련 데이터를 쉽게 구문 분석 할 수 없기 때문에 처리해야하는 성가심 (단일 스레드 앱의 경우)입니다. 게다가 다중 스레드 응용 프로그램은 Throwable.printStackTrace()
스레드로부터 안전하지 않기 때문에 매우 혼란스러운 로그를 생성 할 가능성이 높습니다 .
System.err
여러 스레드 Throwable.printStackTrace()
가 동시에 호출 될 때 스택 추적 쓰기를 동기화하는 동기화 메커니즘이 없습니다 . 이 문제를 해결하려면 실제로 코드와 관련된 모니터에서 System.err
(및 System.out
대상 파일 / 장치가 동일한 경우) 코드를 동기화 해야하므로 로그 파일 상태를 유지하는 데 비용이 많이 듭니다. 예를 들어, ConsoleHandler
및 StreamHandler
클래스는로 제공되는 로깅 기능에서 콘솔에 로그 레코드를 추가해야합니다 java.util.logging
. 로그 레코드 공개의 실제 조작이 동기화됩니다. 로그 레코드 공개를 시도하는 모든 스레드는 또한StreamHandler
예. System.out
/를 사용하여 인터리브되지 않은 로그 레코드를 System.err
보장하려면 동일한 메시지를 직렬화 가능한 방식으로 이러한 스트림에 게시해야합니다.
위의 모든 사항과 Throwable.printStackTrace()
실제로 유용한 매우 제한된 시나리오를 고려할 때 종종 호출하는 것이 나쁜 습관임을 알 수 있습니다.
이전 단락 중 하나에서 인수를 확장하면 Throwable.printStackTrace
콘솔에 쓰는 로거와 함께 사용하는 것도 좋지 않습니다. 이는 로거가 다른 모니터에서 동기화하는 반면 애플리케이션이 인터리브 된 로그 레코드를 원하지 않는 경우 다른 모니터에서 동기화하는 이유 때문입니다. 응용 프로그램에서 동일한 대상에 쓰는 두 개의 서로 다른 로거를 사용할 때도 인수가 유효합니다.
답변
여러 문제를 만지고 있습니다.
1) 스택 추적은 최종 사용자에게 보이지 않아야합니다 (사용자 경험 및 보안 목적으로)
예, 최종 사용자의 문제를 진단 할 수 있어야하지만 최종 사용자는 다음 두 가지 이유로이를 볼 수 없습니다.
- 그것들은 매우 모호하고 읽을 수 없으며 응용 프로그램은 사용자에게 친숙하지 않습니다.
- 최종 사용자에게 스택 추적을 표시하면 잠재적 인 보안 위험이 발생할 수 있습니다. 내가 틀렸다면 PHP를 수정하십시오 .PHP는 실제로 스택 추적에 함수 매개 변수를 인쇄합니다.
2) 스택 추적을 생성하는 것은 상대적으로 비용이 많이 드는 프로세스입니다 (그러나 대부분의 ‘예외’상황에서는 문제가되지는 않습니다)
스택 추적 생성은 예외가 생성 / 발생 될 때 발생합니다 (따라서 예외가 발생하면 가격이 함께 제공됨). 인쇄 비용이 그렇게 많이 들지 않습니다. 실제로 Throwable#fillInStackTrace()
사용자 정의 예외를 무시 하여 간단한 GOTO 문만큼 저렴하게 예외를 던질 수 있습니다 .
3) 많은 로깅 프레임 워크가 스택 추적을 인쇄합니다 (우리는 그렇지 않습니다. 쉽게 변경할 수는 없습니다)
아주 좋은 지적입니다. 여기서 주요 문제는 프레임 워크가 예외를 기록하는 경우 아무것도하지 않지만 (그렇지 않으면 확인하십시오!) 예외를 직접 로그하려면 Logback 또는 Log4J 와 같은 로깅 프레임 워크를 사용 하여 원시 콘솔에 두지 마십시오. 제어하기가 매우 어렵 기 때문입니다.
로깅 프레임 워크를 사용하면 스택 추적을 파일, 콘솔로 쉽게 리디렉션하거나 지정된 전자 메일 주소로 보낼 수도 있습니다. 하드 코드 printStackTrace()
를 사용하면와 함께 살아야합니다 sysout
.
4) 스택 추적 인쇄는 오류 처리를 구성하지 않습니다. 다른 정보 로깅 및 예외 처리와 함께 사용해야합니다.
다시 한 번 : SQLException
로깅 프레임 워크를 사용하여 전체 스택 추적으로 올바르게 기록하고 ” 미안합니다. 현재 요청을 처리 할 수 없습니다 “메시지를 표시하십시오. 사용자가 그 이유에 관심이 있다고 생각하십니까? StackOverflow 오류 화면을 보셨습니까? 매우 유머러스하지만 세부 사항을 밝히지 않습니다 . 그러나 사용자에게 문제를 조사 할 수 있습니다.
그러나 그는 합니다 즉시 전화하고 문제를 진단 할 수 있어야합니다. 따라서 적절한 예외 로깅과 사용자 친화적 인 메시지가 모두 필요합니다.
정리 : 항상 예외를 로깅 (바람직하게는 로깅 프레임 워크 사용 )하지만 최종 사용자에게 노출시키지 마십시오. GUI의 오류 메시지에 대해 신중하게 생각하고 개발 모드에서만 스택 추적을 표시하십시오.
답변
우선 printStackTrace () 는 예외가 발생할 때 스택 추적이 채워 지므로 상태가 비싸지 않습니다.
아이디어는 로거 프레임 워크를 통해 로그에 전달되는 모든 것을 전달하여 로깅을 제어 할 수 있도록하는 것입니다. 따라서 printStackTrace를 사용하는 대신 다음과 같은 것을 사용하십시오.Logger.log(msg, exception);
답변
나쁜 관행을 구성하지 않습니다 자체의 예외의 스택 트레이스를 인쇄하지만, 유일한 예외가 발생했을 때 스테이시 추적을 인쇄하는 것은 아마 여기에 문제 – 종종 그냥 스택 추적을 인쇄하는 것만으로는 충분하지 않습니다.
또한 catch
블록 에서 수행되는 모든 항목이 인 경우 적절한 예외 처리가 수행되지 않는 것으로 의심되는 경향 이 있습니다 e.printStackTrace
. 부적절한 처리는 문제가 무시되고 최악의 경우 정의되지 않거나 예기치 않은 상태로 계속 실행되는 프로그램을 의미 할 수 있습니다.
예
다음 예제를 보자.
try {
initializeState();
} catch (TheSkyIsFallingEndOfTheWorldException e) {
e.printStackTrace();
}
continueProcessingAssumingThatTheStateIsCorrect();
여기서는 초기화가 필요한 일부 처리를 계속하기 전에 초기화 처리를 수행하려고합니다.
위의 코드에서 프로그램 continueProcessingAssumingThatTheStateIsCorrect
이 문제를 일으킬 수 있는 방법으로 진행하지 못하도록 예외를 포착하고 올바르게 처리해야 합니다.
많은 경우에, e.printStackTrace()
어떤 예외가 삼켜지고 있으며 문제가 발생하지 않은 것처럼 처리가 진행될 수 있다는 표시입니다.
이것이 왜 문제가 되었습니까?
잘못된 예외 처리가 널리 보급 된 가장 큰 이유 중 하나는 Eclipse와 같은 IDE e.printStackTrace
가 예외 처리를 수행하는 코드를 자동 생성하는 방법 때문일 수 있습니다 .
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
(상기 실제 인 try-catch
자동 생성 된 처리 이클립스로 InterruptedException
하여 발생 Thread.sleep
).
대부분의 응용 프로그램에서는 스택 추적을 표준 오류로 인쇄하는 것만으로는 충분하지 않을 수 있습니다. 부적절한 예외 처리는 많은 경우 응용 프로그램이 예기치 않은 상태로 실행되어 예기치 않은 정의되지 않은 동작을 유발할 수 있습니다.
답변
이유 목록은 매우 포괄적 인 것 같습니다.
내가 두 번 이상 만난 특히 나쁜 예는 다음과 같습니다.
try {
// do stuff
} catch (Exception e) {
e.printStackTrace(); // and swallow the exception
}
위의 코드의 문제점은 처리가 전적으로printStackTrace
호출 로 구성된다는 것 입니다 . 예외는 실제로 제대로 처리되지 않거나 탈출 할 수 없습니다.
반면에 일반적으로 코드에 예기치 않은 예외가있을 때마다 항상 스택 추적을 기록합니다. 수년 동안이 정책으로 인해 많은 디버깅 시간이 절약되었습니다.
마지막으로, 하나님의 완전한 예외 에 대해 간략하게 설명 합니다.
답변
printStackTrace()
콘솔에 인쇄합니다. 프로덕션 환경에서는 아무도 그것을보고 있지 않습니다. Suraj가 맞습니다.이 정보를 로거에게 전달해야합니다.
답변
서버 애플리케이션에서 stacktrace는 stdout / stderr 파일을 폭파시킵니다. 일반적으로 컨텍스트와 타임 스탬프 등이 없기 때문에 점점 커지고 쓸모없는 데이터로 채워질 수 있습니다.
예 : 컨테이너로 바람둥이를 사용할 때 catalina.out