[Issues]Log4j 2.17 Update

👻·2021년 12월 28일
0

Issues

목록 보기
1/4
post-thumbnail

📌 개요

Log4j 취약점 이슈로 인해 업데이트를 할 일이 생겼다.
현재 사용중이던 Log4j 버전은 1.2버전으로 최신버전인 2.17버전과는 상당히 차이가 심했다.

Property 파일을 통해 Log4j 설정을 해주고,
Log를 표출하는 것에 대한 클래스를 따로 관리 중이였다.
로그 표출에 대한 내용은 클래스를 따로 관리하기에 변경할 필요가 없고,
라이브러리를 참조하고 나서
2.x 버전대와 Logger 사용법이 다르기에 맞춰주기만 하면 되는 상황이였다.


📌 개발환경

  • Windows 10 Pro
  • Eclipse Mars 2.0 (x32)
  • Java 8
  • Log4j v1.2 / v2.17
  • Log4j Property

📌 해결방안

📃 Library Build Path

1.2의 경우 라이브러리가 하나만 존재한다.
2.17을 apachi에서 다운받을 시 상당히 많은 라이브러리가 포함되있어서 혼동되었다.
https://logging.apache.org/log4j/2.x/download.html

아파치 Log4j 다운로드에 보면 사용해야할 것이 무엇인지 알려준다.

Class Path에 추가하려면 이 두가지를 사용하면 된다고 한다.
다운로드 받은 76개의 jar 파일 중 두가지만 참조해보자.

** BuildPath 설정은 생략하겠다.

📃 Property File Path Setting

1.2에서 사용중이던 property 파일 호출 방식과 2.17의 property 파일 호출 방식은 달랐다.
다음은 v1.2 에서 사용중이던 방식이다.

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

PropertyConfigurator.configure("YourPropertyFilePath");
  • log4j-api-2.17.0.jar
  • log4j-core-2.17.0.jar
    위의 두 라이브러리 참조 시 PropertyConfigurator이라는 객체는 지원하지 않는다.
    다른 방법으로 property 파일을 참조한다.
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관련 폴더에 넣어주고 싶어서 찾아봤었다.)

📃 Logger 호출

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를 호출하면 된다는 말이다.

📃 Property file

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와 많이 친해지게 된 계기가 된 것 같다..🙂

profile
Software Developer

0개의 댓글