대표적인 로그를 기록하는 자바 라이브러리
원랜 안드로이드용으로 나온 게 아닌데 안드로이드에서도 사용 할 수 있는 추가 라이브러리가 있어서 두 라이브러리를 모두 적용해 보았다.
Log4j
장점: 날짜별로 파일을 생성하는 기능 있음.
단점: 파일을 로테이션하며 덮어쓰는 기능은 없음. (Log4j2는 된다는데 안드로이드용 라이브러리를 못찾았다.)
Sl4j
장점: 최대 파일 갯수를 정해 놓고, 용량이 차면 로테이션 하는 방식으로 덮어씀.
단점: 날짜별로 파일을 생성하는 기능은 없음. (없는건지 내가 못찾는건지..)
포스트에서는 Log4j를 사용하여 날짜별로 로그를 기록하는 방법을 소개한다.
dependencies {
...
implementation "log4j:log4j:1.2+"
implementation "de.mindpipe.android:android-logging-log4j:1.0.3"
...
}
object LogHelper {
init {
configuration()
}
fun configuration(){
val patternLayout = createPatternLayout()
val rollingAppender = createDailyRollingLogFileAppender(patternLayout)
setAppenderWithRootLogger(rollingAppender)
}
}
라이브러리에 구현된 RootLogger에 PatternLayout과 DailyRollingLogFileAppender를 설정해줄 것이다.
private fun createPatternLayout(): PatternLayout {
val patternLayout = PatternLayout()
val conversionPattern = "[%d] %c %M - [%p] %m%n"
patternLayout.conversionPattern = conversionPattern
return patternLayout
}
보충자료
%d : 로그 발생 시간기록. (%d{yyyy MMM dd HH:mm:ss, SSS}같은 형태로 사용하며 SimpleDateFormat을 따른다.)
%c : 카테고리 출력.
%M : 로그를 기록한 메소드 명.
%p : debug, info, warn, error, fatal 등의 priority.
%m : 로그 메세지.
%n : 플랫폼 종속적인 개행문자 출력. (\r\n 또는 \n)
%t : 스레드 이름을 출력.
%% : % 문자를 출력하기 위해 사용.
%C : 클래스명 출력. (com.example.android.SomeClass일 경우, %C{2}는 android.SomeClass가 출력됨.)
%F : 프로그램 파일명 출력.
%l : 로깅이 발생한 caller의 정보.
%L : 로깅이 발생한 caller의 라인수.
%r : 어플리케이션 시작 이후 부터 로깅이 발생한 시점의 시간(milliseconds).
%x : 로깅이 발생한 thread와 관련된 NDC(nested diagnostic context)를 출력.
%X : 로깅이 발생한 thread와 관련된 MDC(mapped diagnostic context)를 출력.
private fun createDailyRollingLogFileAppender(patternLayout: PatternLayout): DailyRollingFileAppender {
val rollingAppender = DailyRollingFileAppender()
val path = makeDirectory()
val fileName = "$path/LogFile.log"
rollingAppender.file = fileName
rollingAppender.datePattern = "'.'yyyy-MM-dd"
rollingAppender.layout = patternLayout
rollingAppender.activateOptions()
return rollingAppender
}
private fun makeDirectory(): String? {
val path = Environment.getExternalStorageDirectory().absolutePath + "/log"
val logDir = File(path)
if (!logDir.exists()) {
try {
logDir.mkdir()
} catch (e: IOException) {
e.printStackTrace()
return Environment.getExternalStorageDirectory().absolutePath
}
}
return path
}
Environment.getExternalStorageDirectory().absolutePath
는 외부 스토리지 최상위 절대경로이다.
최상위 경로 아래 log폴더를 만들어 그 안에 LogFile.log를 저장하기로 했다.
rollingAppender.datePattern = "'.'yyyy-MM-dd"
는 날짜별로 log파일을 만드는 패턴형식이다.
테스트시 '.'yyyy-MM-dd-HH-mm 로 분단위로 생성되도록 설정하는것이 좋다.
일단위로 테스트를 하면 로그파일이 LogFile.log.2020-01-01 식으로 생성될텐데, 해당 파일은 1월 2일에 생성된다.
즉, 1월 1일날 테스트를 하면 내일에서야 로그파일이 생성되기때문에 처음엔 분단위로 테스트 하는 것이 좋다.
보충자료
'.'yyyy-MM 매달 첫번째날에 로그파일을 변경
'.'yyyy-ww 매주의 시작시 로그파일을 변경
'.'yyyy-MM-dd 매일 자정에 로그파일을 변경
'.'yyyy-MM-dd-a 자정과 정오에 로그파일을 변경
'.'yyyy-MM-dd-HH 매 시간의 시작마다 로그파일을 변경
'.'yyyy-MM-dd-HH-mm 매분마다 로그파일을 변경
private fun setAppenderWithRootLogger(rollingAppender: DailyRollingFileAppender) {
val rootLogger = Logger.getRootLogger()
rootLogger.level = Level.DEBUG
rootLogger.addAppender(rollingAppender)
}
fun getLogger(name: String?): Logger {
return Logger.getLogger(name)
}
RootLogger에 DailyRollingFileAppender를 적용한다.
private val logger = LogHelper.getLogger(this::class.simpleName)
fun writeLog() {
logger.debug("Log4j Log Test")
}
이런 형태로 Logger를 구현하면 된다.