2011-08-15 5 views
5

로그 된 모든 정보를 Java 문자열로 리디렉션하도록 slf4j을 어떻게 구성 할 수 있습니까?slf4j를 문자열로 리디렉션

이것은 단위 테스트에 유용합니다. 서블릿을로드 할 때 아무런 경고도 출력되지 않거나 금단의 SQL 테이블이 절대로 사용되지 않도록 테스트합니다.

+1

단위 테스트에서 로그 리디렉션을했는데 다른 방법은 형식이 지정된 메시지를 String/StringBuffer에 추가하는 대신 단순히'레코드'자체를'List'에 추가하는 것입니다. –

+0

@AlistairIsrael, 좋은 생각, 고마워. 그것들을'List '로 추론하는 것이 훨씬 쉬울 것입니다. –

답변

3

나는 그것을 볼 수있는 두 가지 옵션이 있습니다.

먼저 각 기록 된 문을 StringBuffer에 추가하는 사용자 정의 Appender (사용중인 slf4j 구현에 따라 다름)를 구현할 수 있습니다. 이 경우에는 테스트 클래스가 액세스 할 수 있도록 StringBuffer에 대한 정적 참조를 보유해야합니다.

둘째, ILoggerFactory 및 Logger의 고유 한 구현을 작성할 수 있습니다. 다시 말하지만 로거는 모든 메시지를 내부 StringBuffers에 추가합니다.이 경우 로그 수준마다 하나씩 여러 개의 버퍼가있을 수 있습니다. 이 방법을 사용하면 Logger 인스턴스를 배포하는 공장을 소유하고 있기 때문에 Logger 인스턴스를 쉽게 검색 할 수 있습니다. 단위 테스트, 당신은 단지 표준 출력을 통해 로그를 구성하고 로깅 대상을 실행에 그 전에 캡처 할 수있을 때 로깅 구성으로

0

모든 로그를 별도의 로그 파일로 리디렉션하는 것이 좋지 않습니까? 그렇게하면 로깅의 이점을 잃지 않고 원하는 컨트롤 (원하는 경우 테스트를 실행하기 전에 로그 파일을 삭제하고 파일이 언제든지 만들어 졌는지 확인할 수 있음) (출력을 문자열로 리디렉션하면 메모리 누수가 발생할 수 있음) 덜 성과)

+0

단위 테스트로만 실행됩니다. 그리고 디스크를 만지지 않는 단위 테스트가 훨씬 빠릅니다. –

3

조금 늦게,하지만 여전히 ...

교체가 용이해야한다. 그런 다음 테스트중인 주제를 제외한 모든 항목에 대해 로거를 자동으로 설정하십시오.

@Test 
public void test() 
{ 
    String log = captureStdOut(() -> { 
     // ... invoke method that shouldn't log 
    }); 
    assertThat(log, is(emptyString())); 
} 



public static String captureStdOut(Runnable r) 
{ 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    PrintStream out = System.out; 
    try { 
     System.setOut(new PrintStream(baos, true, StandardCharsets.UTF_8.name())); 
     r.run(); 
     return new String(baos.toByteArray(), StandardCharsets.UTF_8); 
    } catch (UnsupportedEncodingException e) { 
     throw new RuntimeException("End of the world, Java doesn't recognise UTF-8"); 
    } finally { 
     System.setOut(out); 
    } 
} 

그리고 테스트에서의 log4j 이상 SLF4J를 사용하는 경우, 간단한 log4j.properties :

log4j.rootLogger=OFF, out 
log4j.category.com.acme.YourServlet=INFO, out 
log4j.appender.out=org.apache.log4j.ConsoleAppender 
log4j.appender.out.layout=org.apache.log4j.PatternLayout 
log4j.appender.out.layout.ConversionPattern=%-5p %c{1}:%L - %m%n 

아니면 단위 테스트에서 외부 의존성으로 싫어 구성, 다음 프로그램의 log4j를 구성하는 경우 :

//... 

static final String CONSOLE_APPENDER_NAME = "console.appender"; 

private String pattern = "%d [%p|%c|%C{1}] %m%n"; 
private Level threshold = Level.ALL; 
private Level defaultLevel = Level.OFF; 

//... 

public void configure() 
{ 
    configureRootLogger(); 
    configureConsoleAppender(); 
    configureCustomLevels(); 
} 


private void configureConsoleAppender() 
{ 
    ConsoleAppender console = new ConsoleAppender(); 
    console.setName(CONSOLE_APPENDER_NAME); 
    console.setLayout(new PatternLayout(pattern)); 
    console.setThreshold(threshold); 
    console.activateOptions(); 
    Logger.getRootLogger().addAppender(console); 
} 


private void configureRootLogger() 
{ 
    Logger.getRootLogger().getLoggerRepository().resetConfiguration(); 
    Logger.getRootLogger().setLevel(defaultLevel); 
} 
+0

나는 이것을하기위한 간단한 모듈을 썼다. [io.earcam.utilitarian.log.slf4j] (http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io. earcam.utilitarian % 22 % 20and % 20a % 3A % 22io.earcam.utilitarian.log.slf4j % 22) 여기에 간략히 설명되어 있습니다. https://utilitarian.earcam.io/log/slf4j/ – earcam

0

콘솔에 로그인하는 간단한 방법은 다음과 같습니다.

import org.slf4j.LoggerFactory; 
import ch.qos.logback.classic.BasicConfigurator; 
import ch.qos.logback.classic.LoggerContext; 

private void LogToConsole() { 
    BasicConfigurator bc = new BasicConfigurator(); 
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 
    lc.reset(); 
    bc.configure(lc); 
} 
0

정확히 무엇을하고 있는지 알지 못하지만 특정 로그 문을 주장 할 수있는 LogInterceptingTestHarness을 작성했습니다. 당신은 비슷한 것을 사용하여 (또는 이와 비슷한) 특정 레벨에서 아무 것도 기록되지 않았다는 것을 주장 할 수 있습니다.

import static org.junit.Assert.assertEquals; 
import static org.mockito.Mockito.doReturn; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.times; 
import static org.mockito.Mockito.verify; 

import java.util.List; 

import org.apache.logging.log4j.Level; 
import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.core.Appender; 
import org.apache.logging.log4j.core.LogEvent; 
import org.apache.logging.log4j.core.Logger; 
import org.junit.After; 
import org.junit.Before; 
import org.mockito.ArgumentCaptor; 

import lombok.Getter; 

/** 
* Use this class to intercept logs for the purposes of unit testing  log output. 
* <p> 
* On {@link Before} of the unit test, call {@link #initHarness(Class, Level)} or {@link #initHarness(Class, Level, String)} to get a new harness and hold onto reference to it in a class-level 
* variable of your unit test 
* <p> 
* On {@link After} of the unit test, you MUST call {@link #teardown()} in order to remove the mocked {@link #appender} 
* 
* @author jeff.nelson 
* 
*/ 
@Getter 
public class LogInterceptingTestHarness { 

private final Appender appender; 
private final ArgumentCaptor<LogEvent> logEventCaptor; 
private final Logger itsLogger; 

private LogInterceptingTestHarness(Class<?> classInterceptLogsFor, Level logLevel, String appenderName) { 
    logEventCaptor = ArgumentCaptor.forClass(LogEvent.class); 

    appender = mock(Appender.class); 
    doReturn("testAppender").when(appender).getName(); 
    doReturn(true).when(appender).isStarted(); 

    itsLogger = (Logger) LogManager.getLogger(classInterceptLogsFor); 
    itsLogger.addAppender(appender); 
    itsLogger.setLevel(logLevel); 
} 

public void teardown() { 
    itsLogger.removeAppender(appender); 
} 

public List<LogEvent> verifyNumLogEvents(int numEvents) { 
    verify(appender, times(numEvents)).append(logEventCaptor.capture()); 
    return logEventCaptor.getAllValues(); 
} 

public LogEvent verifyOneLogEvent() { 
    return verifyNumLogEvents(1).get(0); 
} 

public void assertLoggedMessage(String message) { 
    assertLogMessage(message, logEventCaptor.getValue()); 
} 

public void assertLoggedMessage(String message, int messageIndex) { 
    assertLogMessage(message, logEventCaptor.getAllValues().get(messageIndex)); 
} 

public static void assertLogMessage(String message, LogEvent event) { 
    assertEquals(message, event.getMessage().getFormattedMessage()); 
} 

public static LogInterceptingTestHarness initHarness(Class<?> classInterceptLogsFor, Level logLevel) { 
    return initHarness(classInterceptLogsFor, logLevel, "testAppender"); 
} 

public static LogInterceptingTestHarness initHarness(Class<?> classInterceptLogsFor, Level logLevel, String appenderName) { 
    return new LogInterceptingTestHarness(classInterceptLogsFor, logLevel, appenderName); 
} 
} 
관련 문제