JavaRush /Java Blog /Random-KO /Java 로그인: 무엇을, 어떻게, 어디서, 무엇으로?
Roman Beekeeper
레벨 35

Java 로그인: 무엇을, 어떻게, 어디서, 무엇으로?

Random-KO 그룹에 게시되었습니다
안녕하세요, JavaRush 커뮤니티 여러분! 오늘은 Java 로깅에 대해 이야기하겠습니다.
  1. 이게 뭐야, 왜 그래? 어떤 경우에 사용하는 것이 더 좋고, 어떤 경우에 사용하지 않는 것이 좋나요?
  2. Java에서 로그인의 다양한 구현은 무엇이며 이러한 다양성을 어떻게 해야 합니까?
  3. 로깅 수준. 어펜더(appender)가 무엇인지, 그리고 이를 올바르게 구성하는 방법에 대해 논의해 보겠습니다.
  4. 모든 것이 원하는 방식으로 작동하도록 로깅 노드와 노드를 올바르게 구성하는 방법.
이 자료는 광범위한 청중을 대상으로 작성되었습니다. Java에 이제 막 익숙해진 사람들과 이미 작업 중이지만 logger.info(“log something”); Let's Go!를 통해서만 알아낸 사람들 모두에게 분명할 것입니다.

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

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

자바 로깅 도구

로깅: 무엇을, 어떻게, 어디서, 무엇으로?  - 2Java 로그인에 대한 잘 알려진 솔루션은 다음과 같습니다.
  • log4j
  • 7월 - java.util.logging
  • JCL - 자카르타 커먼즈 로깅
  • 로그백
  • SLF4J - Java용 간단한 로깅 외관
각각을 간략히 살펴보고 자료의 실제 부분에서는 Slf4j - log4j 연결을 기초로 삼겠습니다 . 지금은 이상하게 보일 수도 있지만 걱정하지 마세요. 기사가 끝나면 모든 것이 명확해질 것입니다.

시스템.err.println

물론 처음에는 System.err.println (콘솔에 출력 기록)이 있었습니다. 디버깅 중에 로그를 빠르게 얻는 데 여전히 사용됩니다. 물론 여기서는 따로 설정에 대해 이야기할 필요가 없으니 그냥 기억하고 넘어가도록 하겠습니다.

Log4j

이는 이미 개발자의 요구에 따라 만들어진 본격적인 솔루션이었습니다. 그것은 사용하기에 정말 흥미로운 도구임이 밝혀졌습니다. 다양한 상황으로 인해 이 솔루션은 JDK에 적용되지 않았으며 이로 인해 전체 커뮤니티가 크게 혼란스러워졌습니다. log4j에는 패키지에서 로깅을 켜고 com.example.type하위 패키지에서 끌 수 있도록 구성 옵션이 있었습니다 com.example.type.generic. 이를 통해 기록해야 할 내용과 필요하지 않은 내용을 신속하게 분리할 수 있었습니다. 여기에서 log4j에는 1.2.x와 2.x.x의 두 가지 버전이 있으며 서로 호환되지 않는다는 점에 유의하는 것이 중요합니다 . log4j는 로그를 기록하는 도구인 어 펜더(appender )와 레이아웃(로그 형식 지정) 과 같은 개념을 추가했습니다 . 이를 통해 필요한 내용과 필요한 방법만 기록할 수 있습니다. 나중에 Appender에 대해 더 자세히 이야기하겠습니다.

7월 - java.util.logging

주요 장점 중 하나는 솔루션입니다. JUL은 JDK(Java 개발 키트)에 포함되어 있습니다. 안타깝게도 개발 과정에서 인기 있는 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을 사용하는 것은 좋은 생각이 아닙니다.

로그백

오픈소스의 길이 얼마나 험난한지... Logback은 log4j와 동일한 개발자가 그 후속작을 만들기 위해 작성했습니다. 아이디어는 log4j와 동일했습니다. 로그백의 차이점은 다음과 같습니다.
  • 향상된 성능;
  • 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, common-loggins 및 logback을 둘러싼 래퍼인 Java용 Simple Logging Facade인 slf4j를 만들었습니다. 보시다시피, 래퍼 위에 래퍼를 만드는 수준까지 진행되었습니다... 게다가 애플리케이션에서 사용되는 API와 다음과 같이 추가되는 구현의 두 부분으로 나뉩니다. 각 로깅 유형에 대한 별도의 종속성. 예를 들어, slf4j-log4j12.jar, slf4j-jdk14.jar. 올바른 구현을 연결하는 것만으로도 충분합니다. 전체 프로젝트가 이를 통해 작동합니다. Slf4j는 로깅을 위한 문자열 형식 지정과 같은 모든 새로운 기능을 지원합니다. 이전에도 그런 문제가 있었습니다. 로그 항목이 있다고 가정해 보겠습니다.
log.debug("User " + user + " connected from " + request.getRemoteAddr());
문자열 연결로 인해 개체에 user암시적 변환이 있으며 user.toString(), 이 변환에는 시간이 걸리고 이로 인해 시스템 속도가 느려집니다. 그리고 애플리케이션을 디버깅하면 모든 것이 정상입니다. 이 클래스의 로깅 수준이 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. 올바른 동작이 확인된 경우 실행된 스레드(Thread)를 로그할 수 있습니다.

인기 있는 로깅 실수

미묘한 차이가 많이 있지만 다음은 몇 가지 일반적인 실수입니다.
  1. 과도한 로깅. 이론적으로 중요할 수 있는 모든 단계를 기록해서는 안 됩니다. 규칙이 있습니다. 로그는 10% 이하로 성능을 로드할 수 있습니다. 그렇지 않으면 성능 문제가 발생합니다.
  2. 모든 데이터를 하나의 파일에 기록합니다. 이로 인해 특정 시스템에 파일 크기 제한이 있다는 것은 말할 것도 없고 특정 지점에서 읽기/쓰기가 매우 어려워집니다.
  3. 잘못된 로깅 수준을 사용하고 있습니다. 각 로깅 수준에는 명확한 경계가 있으므로 이를 준수해야 합니다. 경계가 모호한 경우 어떤 수준을 사용할 것인지 합의할 수 있습니다.

로깅 수준

x: 보이는
치명적인 오류 경고하다 정보 디버그 추적하다 모두
끄다
치명적인 엑스
오류 엑스 엑스
경고하다 엑스 엑스 엑스
정보 엑스 엑스 엑스 엑스
디버그 엑스 엑스 엑스 엑스 엑스
추적하다 엑스 엑스 엑스 엑스 엑스 엑스
모두 엑스 엑스 엑스 엑스 엑스 엑스 엑스
로깅 수준이란 무엇입니까? 어떻게든 로그의 순위를 매기려면 특정한 지정과 구별을 부여하는 것이 필요했습니다. 이를 위해 로깅 수준이 도입되었습니다. 레벨은 애플리케이션에서 설정됩니다. 항목이 지정된 항목보다 낮은 수준에 속하는 경우 로그에 입력되지 않습니다. 예를 들어 애플리케이션을 디버깅하는 데 사용되는 로그가 있습니다. 일반적인 프로덕션 작업(애플리케이션이 의도된 목적으로 사용되는 경우)에서는 이러한 로그가 필요하지 않습니다. 따라서 로깅 수준은 디버깅 수준보다 높습니다. log4j를 예로 들어 레벨을 살펴보겠습니다. JUL을 제외한 다른 솔루션은 동일한 수준을 사용합니다. 다음은 내림차순입니다.
  • OFF: 로그가 기록되지 않으며 모두 무시됩니다.
  • FATAL: 애플리케이션이 더 이상 작동할 수 없고 중지되는 오류입니다(예: JVM 메모리 부족 오류).
  • ERROR: 해결해야 할 문제가 있을 때의 오류율입니다. 오류로 인해 애플리케이션이 전체적으로 중지되지는 않습니다. 다른 쿼리는 올바르게 작동할 수 있습니다.
  • WARN: 경고가 포함된 로그를 나타냅니다. 시스템이 요청을 거부하고 완료했음에도 불구하고 예상치 못한 작업이 발생했습니다.
  • INFO: 애플리케이션의 중요한 작업을 기록하는 로그입니다. 이는 오류나 경고가 아니며 시스템에서 예상되는 작업입니다.
  • DEBUG: 애플리케이션을 디버그하는 데 필요한 로그입니다. 시스템이 예상한 대로 정확하게 작동하는지 확인하거나 시스템의 동작을 설명하려면: "method1이 작동하기 시작했습니다."
  • TRACE: 로깅 수준이 가장 낮은 디버깅 우선 순위가 낮은 로그입니다.
  • ALL: 시스템의 모든 로그가 기록되는 수준입니다.
응용 프로그램의 특정 위치에서 INFO 로깅 수준이 활성화되면 INFO부터 FATAL까지 모든 수준이 기록됩니다. 로깅 수준이 FATAL인 경우 이 수준의 로그만 기록됩니다.

로그 기록 및 전송: Appender

log4j를 예로 들어 이 프로세스를 고려해 보겠습니다. 로그를 기록/전송할 수 있는 충분한 기회를 제공합니다.
  • 파일 쓰기용 - 솔루션 DailyRollingFileAppender ;
  • 애플리케이션 콘솔로 데이터 수신 - ConsoleAppender ;
  • 데이터베이스에 로그를 작성하려면 - JDBCAppender ;
  • TCP/IP를 통한 전송 제어 - TelnetAppender ;
  • 로깅이 성능에 영향을 미치지 않도록 하기 위해 - AsyncAppender .
몇 가지 다른 구현이 있습니다. 전체 목록은 여기에서 찾을 수 있습니다 . 그런데 필요한 어펜더를 사용할 수 없는 경우에는 문제가 되지 않습니다. log4j만 허용하는 Appender 인터페이스 를 구현하여 자신만의 어펜더를 작성할 수 있습니다 .

로깅 노드

데모를 위해 우리는 slf4j 인터페이스와 log4j의 구현을 사용할 것입니다. 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 log4j.properties. Please, provide them");
logger.error("Connection refused to host = {}", host);
클래스를 전달한다고는 하지만 결국 기록되는 것은 패키지가 포함된 클래스의 전체 이름입니다. 이렇게 하면 로깅을 노드로 나누고 각 노드에 대한 로깅 수준과 어펜더를 구성할 수 있습니다. 예를 들어, 클래스 이름은 다음과 같습니다. com.github.romankh3.logginglecture.MainDemo- 해당 클래스에 로거가 생성되었습니다. 그리고 이렇게 로깅 노드로 나눌 수 있습니다. 기본 노드는 null RootLogger 입니다 . 전체 애플리케이션의 모든 로그를 수신하는 노드입니다. 나머지는 아래와 같이 설명할 수 있습니다. 로깅: 무엇을, 어떻게, 어디서, 무엇으로?  - 4Appender는 로깅 노드에서 작업을 구체적으로 구성합니다. 이제 log4j.properties를 예로 들어 이를 구성하는 방법을 살펴보겠습니다.

Log4j.properties의 단계별 구성

이제 모든 것을 단계별로 설정하고 수행할 수 있는 작업을 살펴보겠습니다.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
이 줄은 org.apache.log4j.ConsoleAppender 구현을 사용하는 CONSOLE 어펜더를 등록하고 있음을 나타냅니다. 이 어펜더는 콘솔에 데이터를 씁니다. 다음으로 파일에 쓸 또 다른 어펜더를 등록해 보겠습니다.
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
어펜더를 계속 구성해야 한다는 점에 유의하는 것이 중요합니다. 이미 어펜더를 등록한 후에는 노드에 어떤 로깅 수준을 적용할지, 어떤 어펜더를 사용할지 결정할 수 있습니다.

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

  • log4j.rootLogger는 모든 로그가 포함된 기본 노드를 구성한다는 의미입니다.
  • 등호 뒤의 첫 번째 단어는 로그가 기록될 수준 및 그 이상을 나타냅니다(이 경우 DEBUG).
  • 그런 다음 쉼표 뒤에 사용될 모든 어펜더가 표시됩니다.
특정 로깅 노드를 구성하려면 다음 항목을 사용해야 합니다.
log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
여기서는 log4j.logger.특정 노드를 구성하는 데 사용됩니다. com.github.romankh3.logginglecture. 이제 CONSOLE 어펜더 설정에 대해 이야기해 보겠습니다.
# CONSOLE appender customisation
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
여기서 우리는 어펜더가 처리할 레벨을 설정할 수 있음을 알 수 있습니다. 실제 상황: 정보 수준의 메시지가 로깅 노드에 의해 수신되어 이에 할당된 어펜더에 전달되었지만 경고 수준 이상의 어펜더가 이 로그를 수락했지만 아무 작업도 수행하지 않았습니다. 다음으로 메시지에 어떤 템플릿을 포함할지 결정해야 합니다. 예제에서는 PatternLayout을 사용하고 있지만 거기에는 많은 솔루션이 있습니다. 이 기사에서는 공개하지 않습니다. FILE 어펜더 설정의 예:
# File appender customisation
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 사용에 대한 지식이 있으면 사용하고, 그렇지 않은 경우에는 라이브러리 연결 방법을 설명하는 기사 링크를 제공합니다 .

요약하자면

  1. 우리는 Java에 어떤 솔루션이 있는지 이야기했습니다.
  2. 거의 모든 알려진 로깅 라이브러리는 한 사람의 통제하에 작성되었습니다 :D
  3. 우리는 기록해야 할 것과 기록하지 말아야 할 것을 배웠습니다.
  4. 우리는 로깅 수준을 알아냈습니다.
  5. 우리는 로깅 노드에 대해 알게 되었습니다.
  6. 우리는 어펜더(appender)가 무엇이고 무엇을 위한 것인지 살펴보았습니다.
  7. log4j.proterties 파일을 단계별로 구성했습니다.

추가 자료

  1. JavaRush: 로깅. stectrace 공 풀기
  2. JavaRush: 로거 강의
  3. Habr: Java 로깅. 안녕하세요 세상
  4. Habr: Java 로깅: 악몽의 이야기
  5. 유튜브: 골로바흐 강좌. 벌채 반출. 1부 , 2부 , 3부 , 4부
  6. Log4j: 어펜더
  7. Log4j: 레이아웃
내 다른 기사도 참조하십시오.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION