Link
Today
Total
12-01 00:21
Archives
관리 메뉴

초보개발자 긍.응.성

Logback - 7. Filters 본문

Spring/Logback

Logback - 7. Filters

긍.응.성 2020. 10. 10. 17:29
반응형

logback

logback 홈페이지의 매뉴얼을 읽으며 내용들을 정리한 글입니다.

 

Logback Filters

Logback Filters는 임의로 생성한 복잡한 필터링 정책을 조립하고 연결합니다. 이번 장에서는 logback-classis에서 사용하는 Logback filter들에 대해 알아보겠습니다.

Logback Filters in logback-classic

logback-classic 모듈은 regular filters와 turbo filters 두 가지 타입의 필터를 제공합니다.

Regular filters

logback-classic의 Regular filters는 추상 클래스 Filter를 상속하며, ILoggingEvent를 파라미터로 받아오기 위한 decide() 메서드를 구현합니다. 등록된 Filter는 차례대로 decide(ILoggingEvent event) 메서드를 호출하며, enum 객체인 FilterReply를 반환합니다.

FilterReply는 DENY, NEUTRAL, ACCEPT 세 가지의 종류가 존재합니다. DENY가 반환되면, 로그 이벤트는 drop 되며 나머지 필터들에 대하여 검증과정을 거치치 않게 됩니다. 이때 검증과정을 거치치 않는다는, 말은 남은 등록된 Filters들에 대하여 다음 Filter가 decide() 메서드를 호출하지 않는다는 뜻입니다. NEUTRAL이 반환되면, 다음 필터에게 검증을 넘기게 됩니다. 만약 남아있는 Filter가 없다면 로그 이벤트는 정상적으로 동작하게 됩니다(append). ACCEPT이 반환되면, 남아있는 필터들에 대하여 decide 과정을 스킵하고 곧바로 동작하게 됩니다.

FilterReply Description
DENY 로그 이벤트 동작을 취소하며, 남아있는 Filter들에대하여 검증 하지 않는다.
NEUTRAL 남아있는 다음 Filter에게 검증을 넘긴다.
만약 남아있는 Filter가 없다면 로그 이벤트 정상적으로 동작된다.
ACCEPT 로그 이벤트를 정상적으로 동작시키며, 남아있는 Filter들에 대하여 검증하지 않는다.

Filter는 appender 인스턴스에 추가됩니다. 하나 이상의 filter를 appender에 추가함으로써, 로그 메시지 내용, 시간 또는 다른 임의의 기준으로 이벤트를 필터링할 수 있습니다.

Custom Filter 생성

Filter 추상 클래스를 상속하고 decide 메서드를 구현함으로써, 커스텀 필터를 제작할 수 있습니다. 아래의 SampleFilter는 "sample"이라는 문자열을 로그 메시지가 갖고 있을 때 동작하게 만든 필터입니다.

package chapters.filters;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class SampleFilter extends Filter<ILoggingEvent> {

  @Override
  public FilterReply decide(ILoggingEvent event) {    
    if (event.getMessage().contains("sample")) {
      return FilterReply.ACCEPT;
    } else {
      return FilterReply.NEUTRAL;
    }
  }
}

이렇게 만든 SampleFilter를 Configuration file에서 Appender 태그 하위에 넣어 추가해줍니다.

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

    <filter class="chapters.filters.SampleFilter" />

    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger - %msg%n
      </pattern>
    </encoder>
  </appender>
        
  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Joran Configurator는 appender 태그 하위에 filter 태그를 찾아 해당 appender의 filterList에 등록합니다.

AbstractMatcherFilter

Logback은 AbstractMatcherFilter 클래스를 제공합니다.

public abstract class AbstractMatcherFilter<E> extends Filter<E> {

    protected FilterReply onMatch = FilterReply.NEUTRAL;
    protected FilterReply onMismatch = FilterReply.NEUTRAL;

    final public void setOnMatch(FilterReply reply) {
        this.onMatch = reply;
    }

    final public void setOnMismatch(FilterReply reply) {
        this.onMismatch = reply;
    }

    final public FilterReply getOnMatch() {
        return onMatch;
    }

    final public FilterReply getOnMismatch() {
        return onMismatch;
    }
}

AbstractMatcherFilter는 onMatch, onMismatch 두 가지의 속성으로 일치/불일치에 대한 적절한 응답을 지정할 수 있는 골격을 제공합니다. 대부분의 regular filter들은 이 필터를 상속하여 만들어졌습니다.

LevelFilter

LevelFilter지정한 level과 같은 level의 로그 이벤트를 필터링합니다. 로그 이벤트가 지정한 level과 같다면 onMatch, 같지 않다면 onMismatch에 따른 FilterReply로 처리됩니다. LevelFilter는 AbstractMatcherFilter를 상속하였기 때문에 onMatch와 onMismatch 프로퍼티를 지정해주어야 합니다.

<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger{30} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>

위의 예시에서 ConsoleAppender에 LevelFilter를 추가하였습니다. INFO 레벨에 대하여 필터링하도록 되어있고, 만약 이벤트의 level이 일치하면 ACCEPT, 그렇지 않으면 DENY로 FilterReply를 전달하도록 설정된 것을 확인할 수 있습니다.

ThresholdFilter

ThresholdFilter는 지정된 level 임계점(threshold)에 대하여 로그 이벤트를 필터링합니다. 로그 이벤트의 level이 지정한 임계점과 같거나 그 이상일 때 NEUTRAL을 전달하며, 그렇지 않다면 DENY를 전달합니다. 이 필터는 AbstractFilter를 상속하지 않았기에 onMatch나 onMismatch 프로퍼티를 지정하지 않음을 확인할 수 있습니다.

<configuration>
  <appender name="CONSOLE"
    class="ch.qos.logback.core.ConsoleAppender">
    <!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>INFO</level>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger{30} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>

위 예시에서는 임계점을 INFO 레벨로 설정했습니다. 그렇기에 INFO 하위의 레벨인 TRACE와 DEBUG 로그 이벤트에 대해서는 무시하게 됩니다.

TurboFilters

TurboFilter 객체들은 모두 추상 클래스 TurboFilter를 상속합니다. TurboFilter도 이전에 살펴본 다른 Filter들처럼 decide메서드를 구현하여 FilterReply를 반환하면서 동작하지만 크게 두 가지의 차이점이 존재합니다.

TurboFilter는 기존 Filter보다 더 넓은 scope를 가지고 있습니다. TurboFilter는 logging context와 연결되어 있습니다. 그렇기에 scope가 appender-attached가 아닌, 전체 로그 요청입니다.

더욱 중요한 것은, TurboFilter는 LoggingEvent 객체가 생성하기 이전에 호출됩니다. 즉 TurboFilter 객체가 로깅 요청을 필터링하기 위해 LoggingEvent를 인스턴스화 할 필요가 없습니다. 이는 TurboFilter가 로그 이벤트를 필터링을 더욱 빠르게 처리할 수 있도록 만들어졌기 때문입니다.

Custom TurboFilter 생성

TurboFilter 추상 클래스를 상속해서 커스텀 TurboFilter를 생성할 수 있습니다.

public class SampleTurboFilter extends TurboFilter {

	String marker;
	Marker markerToAccept;

	@Override
	public FilterReply decide(Marker marker, Logger logger, Level level,
    	String format, Object[] params, Throwable t) {

		if (!isStarted()) {
			return FilterReply.NEUTRAL;
		}

		if ((markerToAccept.equals(marker))) {
			return FilterReply.ACCEPT;
		} else {
			return FilterReply.NEUTRAL;
		}
	}

	public String getMarker() {
		return marker;
	}

	public void setMarker(String marker) {
		this.marker = marker;
	}

	@Override
	public void start() {
		if (marker != null && marker.trim().length() > 0) {
			markerToAccept = MarkerFactory.getMarker(marker);
			super.start();
		}
	}
}

TurboFilter는 지정된 marker에 대하여 이벤트를 확인하고 decide를 처리합니다. marker 변수는 getter, setter 메서드를 만들어 configuration file에서 marker 변수의 값을 지정할 수 있도록 합니다. 또한 marker가 잘 세팅되었는지 확인하기 위해 start 메서드를 implements 하였습니다.

아래는 Configuration 파일에 등록한 SampleTurboFilter입니다.

<configuration>
  <turboFilter class="chapters.filters.SampleTurboFilter">
    <Marker>sample</Marker>
  </turboFilter>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger - %msg%n
      </pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

TurboFilter는 전체 로그 이벤트에 대하여 필터링하기 때문에 appender 내부가 아닌 밖에 지정합니다. SampleTurboFilter 내 선언한 문자열 변수 marker의 값을 세팅해주기 위해 Marker 태그를 추가하여 "sample"이라는 값을 전달해 주었습니다. 이로써, marker의 이름이 "sample"인 로그 이벤트에 대해서는 모두 ACCEPT처리를 하고, 아닌 경우 NEUTRAL을 전달하도록 설정한 것을 확인할 수 있습니다.

반응형
Comments