2018년 10월 2일 화요일

자바 로그(log) 남기기 - log4j, log4j2, logback, slf4j (간단한 logback 실습)

로그란? (log)

애플리케이션의 상태를 관찰할 수 있도록 애플리케이션이 제공하는 정보 

log4j, logback, log4j2  셋 다 java 로깅 유틸리티이다.

스프링프레임워크에서는  예전에는 commons.logging을 기본으로 사용하였지만, 지금은 slf4j, log4j 를 기본으로 사용?
시간 순서로 보면 Log4j -> Logback -> Log4j2 인듯?
----------------------------------------------------------------------------------------------

Log4j ? (log for java) 

Apache에서 만든 오픈소스 라이브러리로 프로그램을 작성하는 도중에 로그를 남기기 위해 사용되는 자바 기반 로깅 유틸리티

- 구조
Logger - 로깅이 일어나는 부분을 그룹화해, 필요한 그룹의 로그만을 출력하거나, 카테고리에 우선순위를 부여함으로써, 여러가지 출력 방법을 지원함. 실제 로그 긴으을 수행하는 역할을 담당.

Appender - 로그의 출력 위치를 지정. 콘솔, 파일, outputstream, java.io.Writer, Email(STMP), Network 등이 있음.
 - ConsoleAppender : 콘솔에 로그 메세지를 출력한다.
 - FileAppender: 파일에 로그메시지리를 출력한다.
 - RollingFileAppender: 로그의 크기가 지정한 용량 이상이 되면 다른 이름의 파일을 출력한다.
 - DailyRollingFileAppender: 하루를 단위로 로그 메세지를 파일에 출력한다.
 - SMTPAppender: 로그 메세지를 이메일로 보낸다.
 - NTEventLogAppender: 윈도우의 이벤트 로그 시스템에 기록한다.

Layout - 로그의 출력 포맷을 지정.
 - %d : 로그의 기록시간
 - %p : 로깅의 레벨
 - %F : 로깅이 발생한 프로그램의 파일명
 - %M : 로깅이 발생한 메소드의 이름
 - %I : 호출지의 정보
 - %L : 로깅이 발생한 호출지의 라인 수
 - %t : 로깅이 발생한 Thread 명
 - %c : 로깅이 발생한 카테고리
 - %C : 로깅이 발생한 클래스명
 - %m : 로그 메세지
 - %% : % 출력
 - %r : 시작 이후로부터 로깅이 발생한 시점까지의 시간

----------------------------------------------------------------------------------------------

Log4j2 ? 

이 후에 나온 버전으로 성능과 메시지 처리량 및 대기 시간이 향상되었다고 한다.
log4j 는 xml과 properties를 이용해서 설정하지만, log4j2 는 properties는 지원하지 않는다고함.

-특징
 - 자동적인 로깅 구성설정(?) 리로딩
 - 속성 서포트: Log4j2는 시스템의 속성을 불러오고
 - 자바8: 람다식에서 로그 메시지를 래핑하는 API 제공
 - Log4j2에는 쓰레기 값이 거의 없다.
 - LMAX Disruptor를 사용하는 비동기 logger

----------------------------------------------------------------------------------------------

logback ?

log4j 를 토대로 새롭게 만들어진 로깅 라이브러리로 스프링 부트의 기본 로그 객체.
ERROR < WARN < INFO < DEBUG < TRACE
스프링이나 일반적인 자바프로그램의 경우 resources 디렉토리 안에 logback.xml 참조
(logback.groovy -> logback-test.xml -> logback.xml 순서로 찾는다고함..)
스프링 부트는 logback-spring.xml 파일을 참조

-구조
Log4j와 유사한구조

Logger - 실제 로깅을 수행하는 구성요소로 Level 속성을 통해서 출력할 로그의 레벨을 조절할 수있음.

Appender - 로그 메시지가 출력될 대상을 결정하는 요소
 - ConsoleAppender : 콘솔에 로그를 찍는 방법
 - FileAppender : 파일이 로그를 찍는 방법
 - RollingFileAppender: 여러개의 파일을 순회하면서 로그를 찍는 방법
(상당히 다양하게 쓸 수있는 듯.....)
 - SMTPAppender : 로그를 메일에 찍어 보내는 방법
 - DBAppender:  데이터베이스에 로그를 찍는 방법
Socket, SSLSocket 등이 있음

패턴에 사용되는 요소
 - %Logger{length} : Logger name을 축약할 수 있음 {length}는 최대 자리 수
 - %thread : 현재 Thread 이름
 - %-5level : 로그 레벨, -5는 출력의 고정폭 값
 - %msg : 로그 메시지 ( =%message)
 - %n : new line
 - %highlight: 로그레벨에 따른 색을 줄 수 있는 듯 함

 - 나머지 log4j 와 비슷한 듯..


Encoder - Appender에 포함되어 사용자가 지정한 형식으로 표현 될 로그 메시지를 변환

*layout과 encoder의 차이점: 레이아웃은 들어오는 이벤트를 String으로 변환하고 에빈트가 기록될 때 제어할 수 없으며 이벤트를 일관처리로 집계한다. 반면에 encoder는 바이트를 소유하고 있는 appender가 관리하는 outputStream에 쓸 시간과 내용을 완전히 제어할 수 있음. 
FileAppender와 하위 클래스는 encoder를 필요로 하고 더 이상 layout은 사용하지 않는다.



-특징
1. log4j보다 약 10배 정도 빠름. 메모리 효율성 향상
2. 설정 파일을 변경하였을 경우, 서버 재기동 없이 변경 내용이 자동으로 갱신됨.
3. RollingFileAppender로 자동으로 오래된 로그를 지워줌.

----------------------------------------------------------------------------------------------

SLF4J ? (Simple Logging Facade for Java)

SLF4J 는 자바 로깅 유틸리티의 추상체 역할을 함. 인터페이스와 비슷한 역할을 하며, 사용하던 로깅 유틸리티가 변경되더라도 java소스의 변경을 방지해줌.

개발자는 어떤 상황에든 대처하고 확장될 수 있는 느슨하고 유연한 코드를 만들어야 합니다. 따라서 하나의 라이브러리에 너무 종속적이 되버리는 코드는 가급적 작성하지 않는쪽이 좋습니다. 그렇기에 어떤 라이브러리를 쓰든 동일하게 동작하는 코드를 만들어야하고 그것이 slf4j를 써야하는 이유입니다.


만약 log4j 에서 logback  으로 변경할 때 log4j를 import 하던 파일들을
다 logback 으로 바꿔줘야함.

1
2
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
cs
소스들 마다 박혀있는 log4j를 바꿔줘야함...


하지만 slf4j를 쓴다면 사용하지 않는 dependency만 제거하면 됨.
1
2
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
cs


======================================================

간단 실습

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
    <properties>
...
        <jcloverslf4j.version>1.7.6</jcloverslf4j.version>
        <logback.version>1.1.7</logback.version>
...
    </properties>
...
        <!-- Logback --> 
         <dependency>                                    
                  <groupId>org.slf4j</groupId>                
                  <artifactId>jcl-over-slf4j</artifactId>     
                  <version>${jcloverslf4j.version}</version>  
         </dependency>
         <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
                  <version>${logback.version}</version>
         </dependency>
...
cs


src/main/resources 
logback.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <!-- 로그파일 경로  -->
    <property name="LogFileDir" value="/logs/data.log" />
    <!-- CONSOLE appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern> %d{yyyy-MM-dd HH:mm:ss} [%-5p] [%F]%M\(%L\) : %m%n </pattern>
        </encoder>
    </appender>
    <!--  FILE appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LogFileDir}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LogFileDir}.%d{yyyy-MM-dd}</fileNamePattern>
            <maxHistory>30</maxHistory<!-- 보관의 기간 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5p] [%F]%M\(%L\) : %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.springframework" level="info"/>
    <logger name="org.hibernate" level="debug"/>
    <root level="debug">
        <appender-ref ref="CONSOLE"/<!-- Console에 로그를 출력하고자 할 때 사용 -->
        <appender-ref ref="FILE"/<!-- File로 로그를 남기고자 할 때 사용 -->
    </root>
</configuration>
cs

컨트롤러
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Controller
@RequestMapping("/")
public class HomeController {
...
    private static final Logger LOG = LoggerFactory.getLogger(HomeController.class);
...
    @RequestMapping("/")
    public ModelAndView Home(HttpSession session) throws Exception{
        LOG.debug("-------------------WebBoardList_Start--------------------");
  ...
LOG.debug("-------------------WebBoardList_End--------------------");
...
    }
cs


콘솔창



log파일
파일 내부



출처 및 참고 :






댓글 없음:

댓글 쓰기