exception.printStackTrace()가 잘못된 관행으로 간주되는 이유는 무엇입니까?
예외의 스택 트레이스를 인쇄하는 것은 나쁜 관행임을 시사하는 자료가 많이 있습니다.
예: Checkstyle의 RegexpSingleline 체크:
이 체크는 [...]를 사용하여 ex.printStacktrace()를 호출하는 등의 일반적인 잘못된 방법을 찾을 수 있습니다.
그러나 스택 트레이스가 예외의 원인을 추적하는 데 매우 유용하기 때문에 타당한 이유를 알 수 있는 장소를 찾는 데 어려움을 겪고 있습니다.내가 알고 있는 것:
스택 트레이스는 최종 사용자에게 표시되지 않습니다(사용자 경험 및 보안 목적).
스택 트레이스 생성은 비교적 비용이 많이 드는 프로세스입니다(대부분의 '예외적인' 상황에서는 문제가 되지 않습니다).
많은 로깅 프레임워크가 스택 트레이스를 인쇄합니다(스택 트레이스는 인쇄하지 않습니다.또, 간단하게 변경할 수 없습니다).
스택 트레이스를 인쇄한다고 해서 에러 처리가 되는 것은 아닙니다.다른 정보 로깅 및 예외 처리와 결합해야 합니다.
코드로 스택 트레이스를 인쇄하지 않아도 되는 다른 이유는 무엇입니까?
Throwable.printStackTrace()
스택 트레이스의 기입처System.err
프린트 스트림그System.err
스트림 및 JVM 프로세스의 기본 표준 "오류" 출력 스트림을 리다이렉트할 수 있습니다.
- 행선지가 가리키는 변경을 호출한다.
System.err
. - 또는 프로세스의 에러 출력 스트림을 리다이렉트 합니다.오류 출력 스트림이 파일/디바이스로 리디렉션될 수 있습니다.
- 직원들에 의해 무시될 수 있는 내용입니다.
- 파일/디바이스는 로그 회전이 불가능할 수 있습니다.이는 파일/디바이스의 기존 콘텐츠를 아카이브하기 전에 열려 있는 파일/디바이스 핸들을 닫기 위해 프로세스를 재시작해야 함을 의미합니다.
- 또는 파일/디바이스는 실제로 파일/디바이스에 기록된 모든 데이터를 폐기합니다.
/dev/null
.
위에서 추론하여 호출하다Throwable.printStackTrace()
유효한(불량/대단하지 않은) 예외 처리 동작을 구성합니다.
- 만약 없다면
System.err
응용 프로그램 수명 기간 동안 재할당됩니다. - 애플리케이션 실행 중에 로그 순환이 필요하지 않은 경우
- 또한 어플리케이션의 로그 작성 방법을 승인/설계한 경우,
System.err
(및 JVM의 표준 오류 출력 스트림).
대부분의 경우 위의 조건이 충족되지 않습니다.JVM에서 실행 중인 다른 코드를 인식하지 못할 수 있으며 로그 파일의 크기나 프로세스의 런타임 기간을 예측할 수 없습니다.또한 잘 설계된 로깅 방법은 지원을 지원하기 위해 알려진 대상에 "머신 구문 분석 가능" 로그 파일(로거에 있는 선호되지만 옵션 기능)을 쓰는 것입니다.
마지막으로, 사람들은 의 산출물이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
콘솔에 쓰는 로거와 함께 사용합니다.이는 부분적으로 로거가 다른 모니터에서 동기화되는 반면 응용 프로그램은 다른 모니터에서 동기화되기 때문입니다(인터리브 로그 레코드를 원하지 않는 경우).이 인수는 어플리케이션에서 같은 수신처에 쓰는2개의 다른 로거를 사용하는 경우에도 유효합니다.
여기서는 여러 가지 문제를 다루고 있습니다.
1) 스택 트레이스는 최종 사용자에게 보이지 않도록 한다(사용자 경험 및 보안 목적)
네, 최종 사용자의 문제를 진단할 수 있어야 하지만 다음 두 가지 이유로 인해 최종 사용자에게 문제가 나타나지 않아야 합니다.
- 그것들은 매우 모호하고 읽을 수 없기 때문에 어플리케이션은 매우 사용자 친화적이지 않습니다.
- 스택 트레이스를 최종 사용자에게 표시하면 잠재적인 보안 위험이 발생할 수 있습니다.틀렸다면 정정해 주세요.PHP는 실제로 스택 트레이스에서 함수 파라미터를 출력합니다.훌륭하지만 매우 위험합니다.데이터베이스 접속 중에 예외가 발생하면 스택 트레이스에서 무엇을 할 것 같습니까?
2) 스택 트레이스 생성은 비교적 비용이 많이 드는 프로세스입니다(대부분의 '예외' 상황에서는 문제가 되지 않습니다).
스택 트레이스를 생성하는 것은 예외가 생성/스루닝될 때 발생합니다(따라서 예외가 발생하면 비용이 발생합니다). 인쇄 비용은 그다지 높지 않습니다.실제로, 이 기능을 무효로 쓸 수 있습니다.Throwable#fillInStackTrace()
커스텀 예외로 인해 예외 투척은 GOTO 스테이트먼트만큼 저렴하게 할 수고를 덜 수 있습니다.
3) 많은 로깅 프레임워크가 스택 트레이스를 인쇄합니다(스택 트레이스를 인쇄하지 않습니다.그것은 쉽게 변경할 수 없습니다).
아주 좋은 지적입니다.여기서 중요한 문제는 프레임워크가 예외를 기록할 경우 아무것도 하지 않는다는 것입니다(그러나 반드시 기록해야 합니다).예외를 직접 기록하는 경우 Logback이나 Log4J 등의 로깅 프레임워크를 사용하여 제어가 매우 어렵기 때문에 원시 콘솔에 배치하지 마십시오.
로깅 프레임워크를 사용하면 스택 트레이스를 파일, 콘솔 또는 지정된 전자 메일 주소로 쉽게 리다이렉트할 수 있습니다.하드코드 포함printStackTrace()
당신은 그 사람들과 함께 살아야 한다.sysout
.
4) 스택 트레이스 인쇄는 에러처리에 해당하지 않습니다.다른 정보 로깅 및 예외 처리와 결합해야 합니다.
다시: 로그SQLException
(풀 스택트레이스를 사용하여 로깅 프레임워크를 사용하여) "Sorry, we can't processing your request" 메시지가 표시됩니다.사용자가 정말로 그 이유에 관심이 있다고 생각하십니까?Stack Overflow 에러 화면이 표시되었습니까?그것은 매우 유머러스하지만, 어떤 세부 사항도 드러내지 않는다.단, 사용자가 문제를 조사할 수 있도록 합니다.
하지만 그가 즉시 당신에게 전화를 할 것이고 당신은 문제를 진단할 수 있어야 합니다.따라서 적절한 예외 로깅과 사용자에게 친숙한 메시지 둘 다 필요합니다.
정리: 예외는 항상 로그에 기록합니다(가능하면 로깅 프레임워크 사용). 단, 최종 사용자에게 공개하지 마십시오.GUI 에러 메시지를 주의 깊게 생각해 주세요.개발 모드에서만 스택트레이스를 표시합니다.
우선 printStackTrace()는 스택트레이스가 생성되었을 때 채워지기 때문에 설명하신 것처럼 비용이 많이 들지 않습니다.
로그로 전송되는 모든 것을 로거 프레임워크를 통해 전달하여 로깅을 제어할 수 있도록 합니다.따라서 printStackTrace를 사용하는 대신 다음과 같은 기능을 사용합니다.Logger.log(msg, exception);
예외의 스택 트레이스를 인쇄하는 것 자체가 나쁜 방법은 아니지만, 예외가 발생했을 때 스테이스 트레이스를 인쇄하는 것만 문제가 될 수 있습니다.대부분 스택 트레이스를 인쇄하는 것만으로는 충분하지 않습니다.
또, 모든 예외처리가 정상적으로 실행되고 있지 않다고 의심하는 경향도 있습니다.catch
블록은 a입니다.e.printStackTrace
부적절한 처리는 기껏해야 문제가 무시되고, 최악의 경우 정의되지 않은 상태 또는 예기치 않은 상태에서 프로그램이 계속 실행되는 것을 의미합니다.
예
다음 예를 살펴보겠습니다.
try {
initializeState();
} catch (TheSkyIsFallingEndOfTheWorldException e) {
e.printStackTrace();
}
continueProcessingAssumingThatTheStateIsCorrect();
여기에서는 초기화가 필요한 처리를 계속하기 전에 초기화 처리를 실시합니다.
위의 코드에서는 예외가 검출되어 적절히 처리되어 프로그램이 다음 순서로 진행되지 않도록 해야 합니다.continueProcessingAssumingThatTheStateIsCorrect
문제를 일으킬 수 있는 방법이라고 가정할 수 있습니다.
많은 경우,e.printStackTrace()
는 어떤 예외가 삼켜지고 모든 문제가 발생하지 않은 것처럼 처리가 진행됨을 나타냅니다.
왜 이것이 문제가 되었나요?
이클립스와 같은 IDE가 이클립스를 실행하는 코드를 자동 생성하기 때문에 부적절한 예외 처리가 보편화된 가장 큰 이유 중 하나가 될 수 있습니다.e.printStackTrace
예외 처리의 경우:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
(상기는 실제입니다.try-catch
Eclipse에 의해 자동으로 생성되어InterruptedException
에 의해 던져진Thread.sleep
.)
대부분의 어플리케이션에서는 스택트레이스를 표준 에러로 인쇄하는 것만으로는 충분하지 않을 수 있습니다.대부분의 경우 부적절한 예외 처리는 예기치 않은 상태에서 응용 프로그램이 실행되어 예기치 않은 정의되지 않은 동작을 일으킬 수 있습니다.
당신의 이유 리스트는 꽤 포괄적인 것 같아요.
특히 몇 번이고 접한 나쁜 예는 다음과 같습니다.
try {
// do stuff
} catch (Exception e) {
e.printStackTrace(); // and swallow the exception
}
위의 코드의 문제는 핸들링이 완전히 다음 코드로 구성되어 있다는 것입니다.printStackTrace
call: 예외가 제대로 처리되지 않고 탈출이 허용되지 않습니다.
한편, 통상은, 코드에 예기치 않은 예외가 있는 경우는, 항상 스택 트레이스를 로그에 기록합니다.수년간 이 정책을 통해 디버깅 시간을 크게 절약할 수 있었습니다.
마지막으로, 좀 더 가볍게 말하면, '신의 완벽한 예외'입니다.
printStackTrace()
콘솔에 인쇄합니다.프로덕션 환경에서는 아무도 그것을 보고 있지 않습니다.Suraj가 맞습니다. 이 정보를 로거에 전달해야 합니다.
PrintStackTrace()에 뭔가 문제가 있어서가 아니라 코드 냄새이기 때문입니다.대부분의 경우 PrintStackTrace() 콜은 누군가가 예외를 적절하게 처리하지 못했기 때문에 존재합니다.일단 이 예외를 적절하게 처리하면 StackTrace에 대해 더 이상 신경 쓰지 않습니다.
또한 stderr에 stacktrace를 표시하는 것은 일반적으로 디버깅 시에만 도움이 됩니다.stderr이 작동하지 않는 경우가 많기 때문입니다.기록하는 게 더 말이 돼요그러나 PrintStackTrace()를 로그로 대체하는 것만으로 어플리케이션은 실패했지만 아무 일도 없었던 것처럼 계속 실행됩니다.
서버 애플리케이션에서는 stacktrace에 의해 stdout/stderr 파일이 파기됩니다.일반적으로 컨텍스트나 타임스탬프 등이 없기 때문에 이 데이터는 점점 더 커지고 쓸모없는 데이터로 채워질 수 있습니다.
예를 들어 카탈리나.tomcat을 컨테이너로 사용할 경우 out
여기서 이미 언급한 것처럼 문제는 예외적으로 삼키고 있다는 겁니다 전화만약에 당신이 전화했을 때를 대비해서요.e.printStackTrace()
에서catch
차단. 스레드 실행을 중지하지 않고 일반 상태처럼 시도 블록 후에도 계속됩니다.
Instead of that you need either try to recover from the exception (in case it is recoverable), or to throw RuntimeException
, or to bubble the exception to the caller in order to avoid silent crashes (for example, due to improper logger configuration).
ReferenceURL : https://stackoverflow.com/questions/7469316/why-is-exception-printstacktrace-considered-bad-practice
'programing' 카테고리의 다른 글
JDBC DatabaseMetaData#getTables()가 반환됨: ERROR 1463(42000):HAVING 절에 그룹화되지 않은 필드 'TABLE_TYPE'이 사용됩니다. (0) | 2022.09.12 |
---|---|
Jersey와 Jax-r의 차이점은 무엇입니까? (0) | 2022.09.12 |
MySQL: mysql에 대한 원격 연결을 허용하는 방법 (0) | 2022.09.12 |
Java 시스템에서 표 형식으로 출력합니다.나가. (0) | 2022.09.12 |
MySQL 삽입 위치...값 및 선택 (0) | 2022.09.12 |