본문 바로가기
개발이야기

[안드로이드] slf4j + logback로 로그파일과 logcat 출력하기

by 코저씨 2024. 8. 26.
728x90

안드로이드를 개발하면 logcat으로 로그를 확인하면서 에러를 찾고 수정하지만

디버그를 연결하지 않은 상태에서는 로그를 못 봐서 증상 구현을 못할 때가 많다.

만약 로그를 파일로 저장되어서 나중에 볼 수만 있다면 에러 해결에 큰 도움이 된다.

로그를 파일로 남기는 방법에 대해 3가지를 알아보자.


 

1. 파일로 직접 쓰기

로그를 저장할 파일을 선언하고 출력할 디버그 메시지를 파일로 쓰는 방법이다.

오래된 방법이긴 하지만 이미 구현된 라이브러리가 많은데 굳이 처음부터 구현할 필요는 없어 보인다.

(물론 이미 구현된 게 있다면 그편이 편하겠지만..)

2. log4j

현재 회사에서도 사용 중인 로그 관리 라이브러리이다. 오래전부터 사용되어서 사용방법이나 기능은 검증되어 공유되고 있지만 21년에 터진 Log4Shell 때문에 굳이 사용하는 건 찝찝하긴 하다.

(안드로이드는 상관없다고 하나 안드로이드 버전은 구 버전으로 업데이트가 되지 않고 있다.)

3. slf4j

SLF4J(Simple Logging Facade for Java)는 간단한 로그 관리 라이브러리로 사용방법은 어렵지 않다.

그냥 log.e, log.d와 같이 출력만 하면 된다. 그래서 이번 프로젝트부터는 이 라이브러리를 사용해 보기로 했다.


개발 순서

  1. app gradle에 dependencies 추가
implementation ("org.slf4j:slf4j-api:1.7.25")
implementation ("com.github.tony19:logback-android:2.0.0")

2. assert 폴더 생성 -> logback.xml 파일 생성

logback.xml은 아래와 같이 생성한다.

아래 xml은 로그 cat 출력 및 파일 저장(/data/data/<패키지>/files)을 하는 설정을 한다.

<configuration debug="true">
    <timestamp key="byDate" datePattern="yyMMdd"/>
    <!-- this is the app local data area so that we do not need storage permission to write there -->
    <property name="LOG_HOME" value="${DATA_DIR}" />

    <!-- Create a logcat appender -->
    <appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/app-${byDate}.log</file>
        <encoder>
            <pattern>[%d] [%F->line:%L] [%-5level] - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="logcat" />
        <appender-ref ref="FILE" />
    </root>

</configuration>

 

기본 로그 레벨은 DEBUG이며 아래 표대로 선언하면 원하는 로그만 나오게 할 수 있다.

자세한 건 SLF4J Manual에서 확인한다.

3. 로그 출력하기

Logger logger = LoggerFactory.getLogger("test");
for (int count = 1; count <= 10; count++) {
     logger.info("로그:  {}", count);
}
저장소 내 파일 생성 확인

 

저장소 내에 파일이 생성되는 것을 확인했다. 로그로 출력되고 있다.


xml 이 아닌 함수로 추가 설정하기

개발하다 보면 배포 버전은 어느 로그 레벨부터 로그를 남길지, 파일 관리를 어떻게 할지 등을 설정할 때가 있다.

그런데 매번 xml을 수정하는 건 관리상 어려운 점이 있다.

여기서는 내 프로젝트에 사용할 소스코드로 appender 설정 등 logback 설정하는 방법을 정리해 본다.

  1. 로그 출력 패턴 / 로그 파일명 / 로그 레벨 변경하기
private static Logger createLoggerFor(String string, String file) {

        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        PatternLayoutEncoder ple = new PatternLayoutEncoder();
        ple.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");

        ple.setContext(lc);
        ple.start();

        FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
        fileAppender.setFile(file);
        fileAppender.setEncoder(ple);
        fileAppender.setContext(lc);
        fileAppender.start();

        LogcatAppender logcatAppender = new LogcatAppender();
        logcatAppender.setEncoder(ple);
        logcatAppender.setContext(lc);
        logcatAppender.start();

        ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("test!");
        log.addAppender(fileAppender);
        log.addAppender(logcatAppender);
        log.setLevel(Level.DEBUG);//TRACE - DEBUG - INFO -WARN - ERROR
        log.setAdditive(false);

        return log;
    }

위 예제에서 사용한 Logger logger = LoggerFactory.getLogger("test"); 대신에

 
try{
      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd");
       Date nowDate = new Date(System.currentTimeMillis());
       String strNowDate = simpleDateFormat.format(nowDate);
       logger = createLoggerFor("LOG", "log_"+strNowDate+".log");
}catch (Exception e){
        e.printStackTrace();
}

와 같이 logger를 선언하고 사용하면 된다. log.addAppender(fileAppender);를 빼면 파일 저장을 안 하게 되니 배포 버전에 맞춰서 빌드 옵션을 주면 매번 xml을 바꿨는지 확인할 필요는 없어진다.

2. 로그 파일을 날짜별로 새로 생성하게 하기

내 프로젝트는 로그파일명을 날짜 yy-mm-dd로 나오게 했다.

다만 파일명은 최초 호출 시의 날짜로 계속 유지되기 때문에 재시작을 하기 전에는 파일명이 계속 유지가 된다.

이를 해결하기 위해 아래와 같이 재설정을 하게 해서 현재 날짜로 파일을 재 생성하게 하면 된다.

 
public void reset()
{
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    ContextInitializer ci = new ContextInitializer(lc);
    lc.reset();
    try {
        ci.autoConfig();
    } catch (JoranException e) {
        e.printStackTrace();
    }
}

예제소스는 아래에서 다운로드 해주세요

Song-G-Hun/Example: 강좌데모소스 (github.com)

 

 

 

728x90