Logging하는 습관
학습 레벨이 아닌 Production 레벨의 개발자의 역할을 하게 되면 로깅은 필수, 아니 몸에 배어 있어야 한다. 이해관계자 간 또는 협업 개발자들과의 의견 충돌, 이슈 발생 등의 상황에서의 근거는 로그 밖에 없기 때문이다.
주로 로그의 raw 데이터를 남긴다기보다는 그 raw 데이터를 기반으로 summarizing한 통계적 데이터를 아카이빙한다고 한다.
내가 자주 쓰는 단순 try-catch문 처리만 한다면 로그 기록을 알 수 없기 때문에 언어 또는 프레임워크에서 제공하는 로거 모듈을 사용하는 방식이 권장된다. Java에서는 log4j
, Python에서는 logger
가 있다.
좋지 않은 try-catch문, 아니 뻘짓하는 try-catch문
try {
...
} catch(Exception e) {
...
} catch(IOException ie) {
...
} catch(...) {
...
} ...
try-catch문은 순차적으로 처리하는데 첫 catch문에 바로 Exception을 걸어버리고 다음 catch문부터 IOException 등 하위 Exception을 핸들링하는 코드이다. Exception에서 모든 예외가 처리되기 때문에 그 아래 코드들은 아예 사용이 되지 않아 쓸모가 없어져버리게 되는데 이렇게 짜는 케이스가 꽤 많다고 한다.
try-catch문은 이렇게
try {
...
} catch(IOException ie) {
...
} catch(...) {
} catch(Exception) {
...
}
가장 최소 단위의 Exception으로 시작해서 항상 최종 단계에서 울며 겨자먹기로 Exception을 거는 방식이 가장 최적의 방법이다. 특정 메소드의 각 기능에 대해 1:1로 예외처리를 하고 싶을 때가 있다. 아니, 웬만하면 그렇게 해야 한다.
이렇게 한다면 혹시나 내가 놓친 기능의 Exception을 최종 Exception에서 처리할 수 있기 때문에 일종의 보험을 둘 수 있는 것이다.
대부분 로그를 파일로 기록하는데 당연히 디스크 용량 문제가 발생한다. 때문에 일정 기간이 지나면 로그를 삭제하는 등, 각 로거 모듈의 rotate를 설정하고 원론적으로 생각해보자면 로그에 어떤 데이터를 남길지, 남기지 않을 것인지에 대한 정책 수립이 사전적으로 수행되어야 한다. 물론 남길 데이터에 대한 정책은 보안과도 관련이 있다.
더 나아가면 로그 메시지의 포맷도 고려해야 한다. Plain 텍스트인지, JSON인지, XML인지 명시해야 할 필요가 있다. 왜냐! 사람만 읽을 줄 알면 무슨 소용인가. 이 로그 메시지를 리포팅에도 사용하고 제 3의 용도로도 사용할텐데 파싱이 가능한 상태가 전제되어 있어야 가능하다는 의미이다. 결국 로그 메시지도 기계가 읽고 처리할 수 있는 형태여야 한다.