동기의 도움 요청에 의해 기동 오류를 잡은 뒤 그 기록을 남겨보고자 한다.
적지 않은 시간을 삽질에 허비했지만, 소득이 없지 않았다.
100% 밑바닥까지 깊게 파내진 않았지만, 분명한 해결은 해내었고, 향후 비슷한 문제 발생 시
처음부터 더 나은 접근을 할 수 있는 근거가 생겨서 이를 남기기 위함이다.
오류는 다음과 같은 내용이었다.
심각: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
at org.apache.commons.logging.impl.SLF4JLocationAwareLog.error(SLF4JLocationAwareLog.java:194)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:331)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5110)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5633)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1700)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1690)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
스택 트레이스 읽어 보기
스택트레이스는 항상 첫번째줄부터, 그 중에서 에러 유형을 봐야 한다.
아래는 첫번째줄이다.
java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
첫번째로 알 수 있는 것은 찾고자 하는 메소드가 존재하지 않는다는 오류라는 것이다.
두번째로 알 수 있는 것은 slf4j 를 보아 로깅 관련 의존성에서 문제가 발생하고 있다는 것이다.
그럼 바로 다음 줄을 읽어보자.
at org.apache.commons.logging.impl.SLF4JLocationAwareLog.error(SLF4JLocationAwareLog.java:194)
첫번째줄에선 slf4j 쪽에서 없다는 거였는데, 두번째줄에선 apache commons logging이 나오고 있다.
로깅 관련 의존성에 대해선 정리되어 있는 다른 링크들을 참고하면 좋을 것 같다.
(현재 나도 정리가 안되어 있다..;; ㅠㅠ)
대략적으로 파악하기로는 로깅 관련해서는 여러 의존성이 복합적으로 작용하여 구현이 되고 있다는 것이다.
그 다음은 이제 직접 찾아가보는 것이다. 스택트레이스에서 말하는 저 경로를.
메소드가 없다니까. 뭐가 있고 뭐가 없는지 확인해보자.
눈으로 확인하기
스택트레이스 두번째줄에서 명시했던 그 곳에 왔다. apache-commons.jar 파일 내부였다.
일단 이 곳에는 SLF4JLocationAwareLog.class 라는 파일이 존재하긴 했다.
IntelliJ로 열어서 클래스 파일 내부를 확인해보자.
여기엔 error 메소드가 존재한다.
따라서 NoSuchMethod가 apache-commons.jar 안에 있는 SLF4JLocationAwareLog 안에 없어서 에러가 나는 건 아니다.
왜 버전을 안 써놓은 거야!
스택트레이스로 검색을하고 로깅 관련 의존성들에 대해 찾아보는 과정에서 복합적으로 사용해야하기도 하고
버전에 따른 호환성 문제가 있다는 것까지는 검색을 통해 확인했다.
그래서 검색 결과에서 나오는 log4jcore 등을 여러 버전으로 추가해보기도 했지만 여전했다.
apache-commons 내부에 있는 파일의 날짜가 2008년이라는 것에 힌트를 얻어
2008년 이전 버전들로 최대한 맞춰봤지만 여전했다.
그러다 발견한 것이 commons-logging-1.1.jar 가 같은 라이브러리에 또 들어있다는 것이었다.
그래서 둘을 비교해봤다.
왼쪽이 apache-commons.jar, 오른쪽이 commons-logging-1.1.1.jar 이다.
패키지를 보면 완전히 동일한 경로임을 알 수 있다.
한눈에 봐도 클래스 내용이 현저하게 다르다.
특히, commons-logging-1.1.1.jar에는 SLF4JLocationAwareLog 파일이 존재하지 않는다.
이쯤되니 누가 찐인지, apache-commons.jar는 대체 몇버전인지 확인하고 싶어졌다.
메이븐레포지토리, 아파치 공홈
메이븐 레포지토리에 검색해본 결과 apache-commons.jar는 찾을 수 없었다.
그 대신 apache-commons.jar 안에서 봤던 beanutils와 collections와 logging이 각각 쪼개져서
apache-beanutils, apache-collections, apache-logging으로 존재하고 있었다.
그래서 아파치 공홈을 찾아가봤다.
들어가자마자 목록에서 BeanUtils, Collections, Logging을 찾을 수 있었다.
그러나 그 셋을 묶어놓은 apache-commons.jar는 발견할 수 없었다.
여기까지 오고 나니 확신할 수 있었다.
메이븐 레포지토리와 아파치 공홈에서는 도저히 찾을 수 없었지만,
apache-commons.jar 파일은 Beanutils, Collections, Logging 셋을 묶어놓은 것에 불과하고,
각각의 jar파일을 넣어줘도 무리가 없으리라는 것.
그런데 놀랍게도... 기존 의존성 목록에 그 셋이 이미 모두 존재했다...;;;;;;;; 하......;;;;;;;
그래서 apache-commons.jar를 빼고 나니.... 잘 기동되었다.......
결론
아마도 SLF4J 의존성이 들어가 있고, 그게 apache-logging 을 가져와서 공통화하여 사용할 수 있게 해주는 과정에서,
인식할 수 없는 클래스와 메소드가 들어가 있어서 SLF4J에서 내뿜는 오류였을 것이라 생각된다.
어디서 나타난 녀석인지 모르겠지만 apache-commons.jar 파일에 있는 logging 의존성의 경우
좀 다르게 생겨먹어서 SLF4J가 인식할 수 없었던 것 같다.
메이븐레포지토리에도 없고 아파치 공홈에도 없으니 이녀석이 대체 어디서 튀어나온 건지 모르겠다.
그런데 검색하다보니 나오긴 했다;;;
Download apache-commons.jar : apache commons « a « Jar File Download
무튼.. 의존성으로 인한 문제가 발생했을 때 다음과 같은 내용들이 도움이 될 수 있을 것 같다.
1. 스택 트레이스에서 어떤 유형의 오류인지 탐지
2. 오류가 나오는 해당 패키지, 클래스 위치를 압축 파일을 열고 디컴파일해서 직접 확인
3. 메이븐 레포지토리나, 공식 홈페이지에 가서 관련 내용 확인
4. 해당 의존성을 이미 프로젝트에 추가된 다른 jar파일에서 참조하거나 지원하는지 확인
이래저래 삽질하며 대응 능력이 조금 향상된 것 같긴하지만 정말 불만스러웠다 ㅋㅋㅋ
왜 버전을 안 쓰는 거야! 로깅은 왜 버전이 다르고 여러개가 같이 있지 않으면 문제가 되는거야!ㅋㅋㅋㅋ
쩝쓰.
암튼 해결했다. 끄읏