CodeGym /Java Blog /무작위의 /로깅: 무엇을, 어떻게, 어디서, 무엇으로?
John Squirrels
레벨 41
San Francisco

로깅: 무엇을, 어떻게, 어디서, 무엇으로?

무작위의 그룹에 게시되었습니다
CodeGym 커뮤니티의 여러분 안녕하세요! 로깅: 무엇을, 어떻게, 어디서, 무엇으로?  - 1 오늘은 로깅에 대해 이야기해 보겠습니다.
  1. 그것이 무엇인지, 왜 존재하는지, 언제 사용해야 하는지, 언제 피해야 하는지.
  2. Java에서 사용할 수 있는 로깅 구현과 이러한 모든 로깅 옵션으로 수행해야 하는 작업
  3. 그리고 로그 수준. appender가 무엇인지, 올바르게 구성하는 방법에 대해 설명합니다.
  4. 모든 것이 원하는 방식으로 작동하도록 로깅 노드 및 노드를 올바르게 구성하는 방법.
이 자료는 광범위한 사용자를 대상으로 합니다. 이제 막 Java를 알게 된 사람은 물론 이미 작업 중이지만 탐색만 해본 사람도 이해할 수 있을 것입니다. logger.info("log something"); Let's go!

로깅이 필요한 이유는 무엇입니까?

로깅으로 문제를 해결할 수 있는 몇 가지 실제 사례를 살펴보겠습니다. 다음은 내 작업의 예입니다. 애플리케이션이 다른 서비스와 통합되는 지점이 있습니다. 저는 이러한 지점에서 로깅을 사용하여 일종의 "알리바이"를 설정합니다 . 통합이 작동하지 않으면 어느 쪽에 문제가 있는지 쉽게 파악할 수 있습니다. 데이터베이스에 저장된 중요한 정보를 기록하는 것도 바람직합니다. 예를 들어 관리자 생성이 있습니다. 이것은 정확히 기록하기에 좋은 종류입니다.

Java 로그인 도구

Java의 잘 알려진 로깅 솔루션 중에서 다음을 강조할 수 있습니다.
  • Log4j
  • 7월 — java.util.logging
  • JCL — 자카르타 커먼즈 로깅
  • 로그백
  • SLF4J — Java용 단순 로깅 파사드
우리는 그들 각각에 대한 개요를 제공할 것입니다. 그런 다음 실제 토론의 기초로 slf4j - log4j 바인딩을 사용합니다 . 이것은 지금 이상하게 보일 수 있지만 걱정하지 마십시오. 기사가 끝나면 모든 것이 명확해질 것입니다.

System.err.println

처음에는 System.err.println (콘솔에 로그 항목 표시)이 있었습니다. 오늘날에도 이 기술은 디버깅할 때 빠르게 로그하는 데 사용됩니다. 물론 여기서 논의할 설정은 없으므로 이 방법만 기억하고 넘어가도록 하겠습니다.

Log4j

이것은 개발자가 필요에 따라 만든 완벽한 솔루션입니다. 결과는 사용할 수 있는 정말 흥미로운 도구입니다. 다양한 상황으로 인해 이 솔루션은 JDK에서 끝나지 않았고 전체 커뮤니티를 크게 화나게 한 사실입니다. Log4j에는 패키지에서 로깅을 활성화 com.example.type하고 하위 패키지에서 비활성화할 수 있는 구성 옵션이 있습니다 com.example.type.generic. 이렇게 하면 기록할 필요가 없는 코드를 빠르게 제외할 수 있습니다. 여기에서 Log4j에는 1.2.x와 2.xx의 두 가지 버전이 있으며 서로 호환되지 않는다는 점에 유의하는 것이 중요합니다 . Log4j는 appender 의 개념을 추가했습니다.(로그를 작성하는 데 사용되는 도구) 및 레이아웃(로그 서식 지정). 이렇게 하면 필요한 항목만 기록하고 필요한 방식으로 기록할 수 있습니다. appender에 대해서는 잠시 후에 더 자세히 이야기하겠습니다.

7월 — java.util.logging

이 솔루션의 주요 이점 중 하나는 JUL이 JDK(Java Development Kit)에 포함되어 있다는 것입니다. 불행하게도 개발 당시 제작자는 인기 있는 Log4j 유틸리티를 기반으로 하지 않고 오히려 IBM의 솔루션을 기반으로 했습니다. 그 결정은 결과를 낳았습니다. 현실은 현재 아무도 JUL을 사용하지 않는다는 것입니다. JUL의 로그 수준은 Logback, Log4j 및 Slf4j의 로그 수준과 다릅니다. 이것은 그들이 서로를 이해하기 어렵게 만듭니다. 로거 생성은 다소 비슷합니다. 이렇게 하려면 가져오기를 수행해야 합니다.

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
클래스 이름이 전달되었으므로 로깅의 출처를 알 수 있습니다. Java 8부터 Supplier<String>. 이렇게 하면 이전과 같이 매번이 아니라 실제로 필요할 때만 줄을 읽고 만들 수 있습니다. Java 8이 출시되면서 개발자들은 마침내 중요한 문제를 해결하고 JUL을 진정으로 사용할 수 있게 만들었습니다. Supplier<String> msgSupplier즉, 아래와 같이 매개 변수가 있는 메서드입니다 .

public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL — 자카르타 커먼즈 로깅

오랫동안 로깅에 대한 업계 표준이 없었고 많은 사람들이 자체 사용자 정의 로거를 만들었기 때문에 다른 것 위에 사용할 수 있는 일반 래퍼인 JCL을 출시하기로 결정했습니다. 왜? 때때로 프로젝트에 추가된 종속성이 프로젝트에 있는 것과 다른 로거를 사용했습니다. 이로 인해 프로젝트에 전이적 종속성으로 추가되었으며, 이를 모두 통합하려고 할 때 실제 문제가 발생했습니다. 불행히도 래퍼는 그다지 기능적이지 않았고 아무 것도 추가하지 않았습니다. 모두가 JCL을 사용한다면 아마 편리할 것입니다. 그러나 그것은 일어난 일이 아니므로 현재로서는 JCL을 사용하는 것이 최선의 생각이 아닙니다.

로그백

오픈 소스 경로는 험난합니다... Log4j를 작성한 동일한 개발자가 후속 로깅 프레임워크로 Logback도 작성했습니다. Log4j와 동일한 아이디어를 기반으로 했습니다. Logback의 차이점은 다음과 같습니다.
  • 향상된 성능
  • Slf4j에 대한 기본 지원 추가
  • 확장된 필터링 옵션
기본적으로 Logback은 구성이 필요하지 않으며 DEBUG 수준 이상에서 모든 이벤트를 기록합니다. 일부 사용자 지정이 필요한 경우 XML 구성을 통해 얻을 수 있습니다.

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

SLF4J — Java용 단순 로깅 파사드

2006년 언젠가 Log4j의 창시자 중 한 명이 프로젝트를 떠나 Log4j, JUL, 공통 로깅 및 Logback용 래퍼인 Slf4j(Simple Logging Facade for Java)를 만들었습니다. 보시다시피 wrapper 위에 wrapper를 생성하는 단계까지 진행했습니다... 이 경우 애플리케이션에서 사용되는 API와 별도로 추가되는 구현의 두 부분으로 나뉩니다. 각 로깅 유형에 대한 종속성. 예를 들어, slf4j-log4j12.jarslf4j-jdk14.jar. 올바른 구현을 연결해야 합니다. 그게 전부입니다. 전체 프로젝트에서 이를 사용할 것입니다. Slf4j는 로깅을 위한 문자열 서식 지정과 같은 모든 최신 기능을 지원합니다. 예전에는 그런 문제가 있었습니다. 다음과 같은 로그 항목을 생성한다고 가정해 보겠습니다.

log.debug("User " + user + " connected from " + request.getRemoteAddr());
연결 연산자로 인해 user객체는 덕분에 자동으로 문자열이 됩니다 user.toString(). 시간이 걸리고 시스템 속도가 느려집니다. 응용 프로그램을 디버깅하는 경우 괜찮을 수 있습니다. 이 클래스의 로그 수준이 INFO 이상이면 문제가 발생하기 시작합니다. 즉, 이 로그 항목(INFO 이상)을 작성하면 안 되며 문자열 연결을 사용하면 안 됩니다. 이론적으로 로깅 라이브러리 자체가 이 문제를 해결해야 합니다. 공교롭게도 이것은 Log4j의 첫 번째 버전에서 가장 큰 문제로 판명되었습니다. 괜찮은 솔루션을 제공하지 않았지만 대신 다음과 같이 제안했습니다.

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
즉, 로깅을 위한 한 줄의 코드 대신 3! 로깅은 코드 변경을 최소화해야 하며 세 줄은 이러한 일반적인 접근 방식을 명백히 위반합니다. Slf4j는 JDK 및 API와의 호환성 문제가 없었으므로 즉시 멋진 솔루션이 나타났습니다.

log.debug("User {} connected from {}", user, request.getRemoteAddr());
여기서 {}메서드에 전달된 인수에 대한 자리 표시자를 나타냅니다. 즉, 첫 번째는 {}에 해당 user하고 두 번째는 {}에 해당합니다 request.getRemoteAddr(). 이렇게 하면 로그 수준에서 로그 항목을 작성해야 하는 경우에만 문자열 연결을 수행합니다. 그 후 Sjf4j는 빠르게 인기를 끌기 시작했습니다. 현재로서는 최상의 솔루션입니다. 따라서 바인딩을 이용한 로깅에 대해 살펴보자 slf4j-log4j12.

기록해야 할 사항

물론 모든 것을 기록해서는 안 됩니다. 이것은 종종 필요하지 않으며 때로는 위험하기도 합니다. 예를 들어 누군가의 개인 데이터를 기록했는데 어떻게든 유출되면 특히 서구 시장에 초점을 맞춘 프로젝트에서 실제 문제가 발생할 것입니다. 그러나 반드시 기록해야 하는 사항 도 있습니다 .
  1. 응용 프로그램의 시작/종료. 애플리케이션이 실제로 예상대로 시작되고 종료되었는지 여부를 알아야 합니다.
  2. 보안 문제들. 여기에서 다른 사람의 비밀번호를 추측하려는 시도, 관리자가 로그인하는 경우 등을 기록하는 것이 좋습니다.
  3. 특정 애플리케이션 상태 . 예를 들어 비즈니스 프로세스에서 한 상태에서 다른 상태로의 전환입니다.
  4. 해당 로그 수준과 함께 특정 디버그 정보 .
  5. 특정 SQL 스크립트. 이것이 필요한 실제 사례가 있습니다. 그러나 로그 수준을 능숙하게 조정하면 뛰어난 결과를 얻을 수 있습니다.
  6. 제대로 작동하는지 확인할 때 실행 중인 스레드를 기록할 수 있습니다.

로깅에서 자주 발생하는 오류

여기에는 많은 뉘앙스가 있지만 몇 가지 일반적인 실수에 대해 특별히 언급하겠습니다.
  1. 과도한 로깅. 이론적으로 중요할 수 있는 모든 단계를 기록해서는 안 됩니다. 여기에 좋은 경험 법칙이 있습니다. 로그는 로드의 10%를 초과해서는 안 됩니다. 그렇지 않으면 성능 문제가 발생합니다.
  2. 모든 데이터를 하나의 파일에 기록합니다. 어느 시점에서 이것은 특정 시스템이 파일 크기에 제한이 있다는 사실은 말할 것도 없고 로그를 읽고 쓰는 것을 매우 어렵게 만들 것입니다.
  3. 잘못된 로그 수준을 사용합니다. 각 로그 수준에는 명확한 경계가 있으며 이를 준수해야 합니다. 경계가 명확하지 않은 경우 사용할 수준에 대해 합의할 수 있습니다.

로그 수준

×: 보인다
치명적인 오류 경고하다 정보 디버그 추적하다 모두
끄다
치명적인 엑스
오류 엑스 엑스
경고하다 엑스 엑스 엑스
정보 엑스 엑스 엑스 엑스
디버그 엑스 엑스 엑스 엑스 엑스
추적하다 엑스 엑스 엑스 엑스 엑스 엑스
모두 엑스 엑스 엑스 엑스 엑스 엑스 엑스
로그 수준이란 무엇입니까? 어떻게든 로그 항목의 계층 구조를 생성하려면 특정 규칙과 구분이 필요합니다. 이것이 로그 수준이 도입된 이유입니다. 수준은 응용 프로그램에서 설정됩니다. 항목이 지정된 수준보다 낮으면 기록되지 않습니다. 예를 들어 애플리케이션을 디버깅할 때 사용하는 로그가 있습니다. 정상적인 작동 중에는(애플리케이션이 의도한 용도로 사용되는 경우) 이러한 로그가 필요하지 않습니다. 따라서 로그 수준은 디버깅보다 높습니다. Log4j를 사용하여 로그 수준을 살펴보겠습니다. JUL 외에도 다른 솔루션은 동일한 로그 수준을 사용합니다. 다음은 내림차순입니다.
  • OFF: 로그 항목이 기록되지 않습니다. 모든 것이 무시됩니다.
  • 치명적: 응용 프로그램이 계속 실행되지 못하게 하는 오류입니다. 예: "JVM 메모리 부족 오류".
  • 오류: 이 수준의 오류는 해결해야 할 문제를 나타냅니다. 오류로 인해 응용 프로그램이 전체적으로 중지되지는 않습니다. 다른 요청은 올바르게 작동할 수 있습니다.
  • WARN: 경고를 나타내는 로그 항목입니다. 예상치 못한 일이 발생했지만 시스템이 대처할 수 있었고 요청을 이행했습니다.
  • 정보: 애플리케이션에서 중요한 작업을 나타내는 로그 항목입니다. 이는 오류나 경고가 아닙니다. 예상되는 시스템 이벤트입니다.
  • 디버그: 애플리케이션을 디버그하려면 로그 항목이 필요합니다. 응용 프로그램이 예상한 대로 정확하게 작동하는지 확인하거나 응용 프로그램에서 수행한 작업을 설명하기 위해(예: "Entered method1").
  • TRACE: 디버깅을 위한 우선 순위가 낮은 로그 항목입니다. 가장 낮은 로그 수준입니다.
  • ALL: 애플리케이션의 모든 로그 항목을 쓰기 위한 로그 수준입니다.
INFO 로그 수준이 애플리케이션 어딘가에서 활성화되면 INFO에서 FATAL까지 모든 수준의 항목이 기록됩니다. FATAL 로그 수준이 설정된 경우 해당 수준의 로그 항목만 기록됩니다.

로그 로깅 및 전송: Appender

로그를 작성/전송할 수 있는 충분한 기회를 제공하는 Log4j를 사용할 때 이 모든 것이 어떻게 작동하는지 살펴보겠습니다.
  • 파일에 쓰기 —DailyRollingFileAppender
  • 콘솔에 정보 쓰기 —ConsoleAppender
  • 데이터베이스에 로그 쓰기 —JDBCAppender
  • TCP/IP를 통한 전송 로그 관리 —TelnetAppender
  • 로깅이 성능에 부정적인 영향을 미치지 않도록 —AsyncAppender
몇 가지 구현이 더 있습니다. 여기에서 전체 목록을 볼 수 있습니다 . 그건 그렇고, 필요한 appender가 존재하지 않더라도 문제가 되지 않습니다. Log4j가 지원하는 Appender 인터페이스를 구현하여 자체 Appender를 작성할 수 있습니다 .

로깅 노드

데모 목적으로 Log4j의 구현과 함께 Slf4j 인터페이스를 사용합니다. 로거를 만드는 것은 매우 간단합니다. 일부 로깅을 수행할 이라는 클래스에 MainDemo다음을 추가해야 합니다.

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
그러면 로거가 생성됩니다. 로그 항목을 만들기 위해 사용할 로그 수준을 반영하는 이름을 가진 몇 가지 방법이 있습니다. 예를 들어:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
클래스를 전달하고 있지만 최종 이름은 패키지를 포함한 클래스의 전체 이름입니다. 이는 나중에 로깅을 노드로 나누고 각 노드에 대한 로깅 수준 및 어펜더를 구성할 수 있도록 수행됩니다. 예를 들어, 로거는 클래스에서 생성되었습니다 com.github.romankh3.logginglecture.MainDemo. 이름은 로깅 노드의 계층 구조를 만들기 위한 기반을 제공합니다. 기본 노드는 최상위 RootLogger 입니다 . 이것은 전체 애플리케이션에 대한 모든 로그 항목을 수신하는 노드입니다. 나머지 노드는 아래와 같이 나타낼 수 있습니다. 로깅: 무엇을, 어떻게, 어디서, 무엇으로?  - 삼어펜더는 특정 로깅 노드에 대해 구성됩니다. 이제 log4j.properties 파일을 살펴보고 이를 구성하는 방법의 예를 살펴보겠습니다.

log4j.properties 파일에 대한 단계별 가이드

모든 것을 한 번에 한 단계씩 설정하고 무엇이 가능한지 살펴보겠습니다.

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
이 행은 org.apache.log4j.ConsoleAppender 구현을 사용하는 CONSOLE 어펜더를 등록하고 있음을 나타냅니다. 이 어펜더는 콘솔에 정보를 기록합니다. 다음으로 다른 appender를 등록합니다. 이것은 파일에 쓸 것입니다:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
어펜더 자체는 여전히 구성해야 한다는 점에 유의해야 합니다. appender를 등록하면 노드에서 사용할 로그 수준과 appender를 결정할 수 있습니다.

log4j.rootLogger=디버그, 콘솔, 파일

  • log4j.rootLogger는 모든 로그 항목을 포함하는 루트 노드를 구성하고 있음을 의미합니다.
  • 등호 뒤의 첫 번째 단어는 기록할 최소 로그 수준을 나타냅니다(이 경우 DEBUG).
  • 쉼표 다음에 사용할 모든 어펜더를 나타냅니다.
보다 구체적인 로깅 노드를 구성하려면 다음과 같은 항목을 사용합니다.

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
여기서 는 log4j.logger.특정 노드를 참조하는 데 사용됩니다. 우리의 경우 com.github.romankh3.logginglecture. 이제 CONSOLE 어펜더 구성에 대해 이야기하겠습니다.

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
여기서 우리는 어펜더가 작업을 시작할 특정 수준을 설정할 수 있음을 알 수 있습니다. 실제로 발생하는 예는 다음과 같습니다. INFO 수준의 메시지가 로깅 노드에서 수신되어 할당된 어펜더로 전달된다고 가정합니다. 어펜더의 임계값이 WARN으로 설정된 경우 로그 항목을 수신하지만 아무 작업도 수행하지 않습니다. 다음으로 메시지에서 사용할 레이아웃을 결정해야 합니다. 예제에서는 PatternLayout을 사용하지만 다른 많은 옵션이 있습니다. 이 문서에서는 다루지 않습니다. FILE 어펜더 구성의 예:

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
다음 행에서 볼 수 있듯이 로그 항목이 기록될 특정 파일을 구성할 수 있습니다.

log4j.appender.FILE.File=./target/logging/logging.log
항목이 파일에 기록됩니다 logging.log. 파일 크기 문제를 방지하기 위해 최대값(이 경우 1MB)을 구성할 수 있습니다. MaxBackupIndex그러한 로그 파일이 몇 개 있는지 나타냅니다. 이보다 더 많은 파일을 만들어야 하는 경우 첫 번째 파일이 삭제됩니다. 로깅이 구성된 실제 예를 보려면 GitHub의 공개 리포지토리 로 이동할 수 있습니다 .

우리가 논의한 내용을 강화하십시오.

우리가 설명한 모든 것을 직접 해보십시오.
  • 위의 예와 유사한 자신의 프로젝트를 만드십시오.
  • Maven 사용법을 알고 있다면 Maven을 사용하십시오. 그렇지 않은 경우 라이브러리 연결 방법을 설명하는 이 자습서를 읽으십시오.

요약하자면

  1. Java에 존재하는 로깅 솔루션에 대해 이야기했습니다.
  2. 거의 모든 잘 알려진 로깅 라이브러리는 한 사람이 작성했습니다 :D
  3. 기록해야 할 것과 기록하지 말아야 할 것을 배웠습니다.
  4. 우리는 로그 수준을 파악했습니다.
  5. 우리는 로깅 노드를 소개받았습니다.
  6. 우리는 appender가 무엇이고 무엇을 위한 것인지 살펴보았습니다.
  7. 단계별로 log4j.proterties 파일을 만들었습니다.

추가 자료

  1. CodeGym: 로거 레슨
  2. Weekly Geekly: 자바 로깅. 안녕하세요 세계
  3. 코딩 공포: 로깅 문제
  4. YouTube: Java 로깅 지옥 이해 - 기본 사항. Java 로깅 지옥 및 이를 피하는 방법
  5. Log4j: 어펜더
  6. Log4j: 레이아웃
또한 내 다른 기사를 참조하십시오.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION