Log4j 취약점 이슈로 인해 업데이트를 할 일이 생겼다.
현재 사용중이던 Log4j 버전은 1.2버전으로 최신버전인 2.17버전과는 상당히 차이가 심했다.
Property 파일을 통해 Log4j 설정을 해주고,
Log를 표출하는 것에 대한 클래스를 따로 관리 중이였다.
로그 표출에 대한 내용은 클래스를 따로 관리하기에 변경할 필요가 없고,
라이브러리를 참조하고 나서
2.x 버전대와 Logger 사용법이 다르기에 맞춰주기만 하면 되는 상황이였다.
1.2의 경우 라이브러리가 하나만 존재한다.
2.17을 apachi에서 다운받을 시 상당히 많은 라이브러리가 포함되있어서 혼동되었다.
https://logging.apache.org/log4j/2.x/download.html
아파치 Log4j 다운로드에 보면 사용해야할 것이 무엇인지 알려준다.
Class Path에 추가하려면 이 두가지를 사용하면 된다고 한다.
다운로드 받은 76개의 jar 파일 중 두가지만 참조해보자.
** BuildPath 설정은 생략하겠다.
1.2에서 사용중이던 property 파일 호출 방식과 2.17의 property 파일 호출 방식은 달랐다.
다음은 v1.2 에서 사용중이던 방식이다.
import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; PropertyConfigurator.configure("YourPropertyFilePath");
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); File log4jProperties = new File("YourPropertyFilePath"); loggerContext.setConfigLocation(log4jProperties.toURI());
LoggerConetxt를 통해 ConfigLocation을 지정할 수 있다.
사실 property 파일을 프로젝트의 "/src" root 경로에 넣으면 따로 설정할 필요 없이 호출 된다.
하지만, 내 강박에 의해 그 방법보단 경로를 따로 지정해주고 싶었다.
(config관련 폴더에 넣어주고 싶어서 찾아봤었다.)
property 파일의 참조는 정상적으로 되었지만, Logger 객체의 호출에 있어 문제가 발생했다.
다음은 v1.2에서의 Logger 객체 호출이다.
import org.apache.log4j.Logger; Logger.getLogger(Log.class).info("YourLogMessage");
일단 api, core 두 라이브러리에서의 Logger 객체와 v1.2의 Logger 객체는 다르다.
다음은 v2.17에서의 Logger 객체 호출이다.
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; Logger logger = LogManager.getLogger(Log.class);
같은 Logger 객체지만, import한 부분을보면 다르다.
(캐스팅 해보면 다른 것을 확실히 알 수 있다.)
사실상 v1.2 방식으로 사용 시 이클립스 자체에서 실행 시 문제가 되지 않았다.
왜냐하면 log4j-1.2-api-2.17.0.jar을 참조해놓고 쓰던 상태였기 때문이다.
log4j-1.2-api-2.17.0.jar 참조 시 v1.2방식대로 사용이 가능했다.
하지만, 실행파일을 만들어 실행할 시 오류가 발생했다.
LoggerContext로 property 경로를 설정할 때 LogManager를 사용하는데,
그쪽 LogManager랑 v1.2쪽 Logger이랑 서로 다른 객체여서 충돌이 나는 것 같았다.
검색해보니 플러그인 캐시?가 다른 두 가지를 사용해서 그렇다고 하는데
사실 잘 이해가 가지는 않았다.
어쨋든 log4j-1.2-api-2.17.0.jar를 참조하지 않고, LogManager를 통해 Logger 객체를 호출하는 식으로 변경하였고 실행파일에서도 로그가 정상적으로 출력되었다.
Logger logger = LogManager.getLogger(Log.class);
결론은 이 방식으로 Logger를 호출하면 된다는 말이다.
v1.2와 v2.x의 property file의 문법이 조금 다르다.
알기쉽게 두 차이를 적어보겠다.
일단 나는 현재 property 파일에서 로그의 형식을 지정하지 않는다.
Log 클래스에서 따로 형식을 편하게 지정하는게 더 낫다고 생각한다. (익숙하지 않아서 그런가보다.)
이 property 예제에서는 콘솔 로그를 출력하고, 매일 00시 마다 로그 파일을 지정한 패턴대로 저장하게 만든다.
일단 v1.2 방식이다.
<log.properties>
log4j.rootLogger = DEBUG, stdout, dailyfile log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout = org.apache.log4j.PatternLayout #log4j.appender.stdout.layout.ConversionPattern=[%5p] Caller:%t(), [File:%F-Function:%M():Line:%L] [%d] -----> [Message : %m]%n log4j.appender.stdout.layout.ConversionPattern=%m%n log4j.logger.java.sql.Connection=WARN log4j.logger.java.sql.Statement=WARN log4j.logger.java.sql.PreparedStatement=WARN log4j.logger.java.sql.ResultSet=WARN log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=WARN log4j.appender.dailyfile.Threshold = DEBUG log4j.appender.dailyfile = org.apache.log4j.DailyRollingFileAppender log4j.appender.dailyfile.File = ./logfiles/logfile.log log4j.appender.dailyfile.DatePattern='.'yyyy-MM-dd log4j.appender.dailyfile.layout = org.apache.log4j.PatternLayout #log4j.appender.dailyfile.layout.ConversionPattern=[%5p] Caller:%t(), [File:%F-Function:%M():Line:%L] [%d] -----> [Message : %m]%n log4j.appender.dailyfile.layout.ConversionPattern=%m%n
다음은 v2.x 방식이다.
status = warn name = Log4j2PropertiesConfig # Console appender configuration appender.console.type = Console appender.console.name = LogToConsole # Rotate log file appender.rolling.type = RollingFile appender.rolling.name = LogToRolling appender.rolling.fileName= logfiles/logfile.log appender.rolling.filePattern= logfiles/logfile.log.%d{yyyy-MM-dd} appender.rolling.policies.type = Policies # RollingFileAppender rotation policy appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.time.interval = 1 appender.rolling.policies.time.modulate = true rootLogger.appenderRefs = RollingFile rootLogger.appenderRef.rolling.ref = LogToRolling rootLogger.level = info rootLogger.appenderRef.stdout.ref = LogToConsole
맥락은 비슷하지만 문법이 조금 다르다.
검색하면 자료가 많이 나오니 찾아보고 원하는 형식을 찾길 바란다.
생각보다 빠르게 해결방안을 찾았었으나,
Logger 객체의 충돌로 인한 오류에만 꽤 많은 시간이 걸렸다.
충돌을 해결하는 방법을 찾는 것에 얽매여서 해결하지 못했었다.
옳은 방법도 아닌 것 같다.
다음 날 생각해보니 충돌이 나는 것 자체가 문제일 것이라는 생각이 들었고
충돌이 나지 않도록 import한 부분에 대해 차분하게 정리하고 생각했다.
곧바로 원인을 찾았고 해결되었다.
간단히 생각하면 한두시간 안에 해결될 이슈였지만, 여전히 나는 부족하다.
그래도 이번 이슈를 계기로 Log4j와 많이 친해지게 된 계기가 된 것 같다..🙂