파란하늘의 지식창고
반응형

서버 개발자가 로그를 보는건 그냥 서버들어가서 확인하면 된다.

하지만 프론트 개발자와 협업을 하는 경우 서버 로그 확인 요청을 받는 경우가 종종 있다.

이런 경우 웹에서 바로 로그를 확인하면 좋을 것 같아 만들어보았다.

Logback의 appender를 사용한 방법이다.

logback은 appender로 로그를 처리하는 방식을 관리한다.

여러가지 방식의 appender를 logback이 제공해주지만 기본 제공해주는 appender 중엔 웹 요청으로 응답을 처리하는 appender는 없다.

custom appender를 하나 만들어준다.

public class BlueskyLogbackAppender<E> extends UnsynchronizedAppenderBase<E> { 	 	private BlueskyLogbackAppenderService<E> blueskyLogbackAppenderService; 	 	@Setter 	private Encoder<E> encoder; 	 	public BlueskyLogbackAppender(BlueskyLogbackAppenderService<E> blueskyLogbackAppenderService) { 		this.blueskyLogbackAppenderService = blueskyLogbackAppenderService; 	}  	@Override 	protected void append(E eventObject) { 		if (!isStarted()) { 			return; 		} 		blueskyLogbackAppenderService.addLog(eventObject, new String(encoder.encode(eventObject))); 	}  }

해당 appender는 append 실행 시 지정된 service의 메소드를 수행한다.

해당 서비스를 구현한다.

public class BlueskyLogbackAppenderService<E> { 	 	private static final int queueSize = 500;  	@Getter 	private Queue<LogObject<E>> logQueue = new LinkedBlockingQueue<>(queueSize); 	 	public void addLog(E eventObject, String logMessage) { 		if (logQueue.size() >= queueSize) { 			logQueue.remove(); 		} 		logQueue.offer(new LogObject<E>(eventObject, logMessage)); 	} 	 	@Data 	@AllArgsConstructor 	public static class LogObject<E> { 		E eventObject; 		String logMessage; 	} } 

해당 서비스는 로컬 queue에 로그 내용을 담는 기능을 제공하고 500개가 초과하면 가장 오래된 로그를 비우고 추가하는 식으로 동작한다.

이제 기존 logback 설정에 위 custom appender를 추가한다.

@Configuration public class BlueskyLogbackConfig implements InitializingBean { 	 	@Bean 	public BlueskyLogbackAppenderService<ILoggingEvent> blueskyLogbackAppenderService() { 		return new BlueskyLogbackAppenderService<ILoggingEvent>(); 	}  	@Override 	public void afterPropertiesSet() throws Exception { 		LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();  		BlueskyLogbackAppender<ILoggingEvent> blueskyLogbackAppender = new BlueskyLogbackAppender<>(blueskyLogbackAppenderService());  		blueskyLogbackAppender.setContext(loggerContext); 		blueskyLogbackAppender.setName("blueskyLogbackAppender"); 		RollingFileAppender<ILoggingEvent> appender = (RollingFileAppender<ILoggingEvent>) loggerContext.getLogger("ROOT").getAppender("FILE"); 		blueskyLogbackAppender.setEncoder(appender == null ? new PatternLayoutEncoder() : appender.getEncoder()); 		 		blueskyLogbackAppender.start(); 		loggerContext.getLogger("ROOT").addAppender(blueskyLogbackAppender); 		 	}  	 }

위의 경우 logback.xml에 FILE이란 이름의 appender가 있는 경우 해당 appender의 encoder를 사용하는 설정이다.

파일로 남기는 로그의 로그 패턴을 그대로 사용하기 위해 가져왔다.

이제 log 가 발생할 때마다 blueskyLogbackAppenderService에 queue가 쌓이게 된다.

쌓아놓은 queue를 확인하는 호출 주소를 추가한다.

@RestController public class BlueskyLogbackDevCheckController {  	@Autowired 	private BlueskyLogbackAppenderService<ILoggingEvent> blueskyLogbackAppenderService; 	 	@GetMapping(value = "/logView", produces = MediaType.APPLICATION_JSON_VALUE) 	public List<String> logview() { 		return blueskyLogbackAppenderService.getLogQueue().stream().map(queue -> queue.getLogMessage().replaceAll(CoreConstants.LINE_SEPARATOR, "").replaceAll("\t", "")).collect(Collectors.toList()); 	}  } 

json으로 응답하는 것으로 설명을 했지만 appender는 이벤트 기반이기 때문에 특정 로그가 발생하면 메일로 알려준다거나 하는 식의 모니터링을 만들어 사용하는 방법이 실제론 더 효율적인 사용이 되지 않을까 싶다.

반응형
profile

파란하늘의 지식창고

@Bluesky_

도움이 되었다면 광고를 클릭해주세요