log4j: SocketAppender 사용하기

Choog Yul Lee·2023년 1월 8일
0
post-thumbnail

🥗 Prologue

시스템을 잘 관리하기 위해서는 프로그램을 주기적으로 Restart 해주는 것이 좋다. 서버를 Restart하면 더 좋고! 하지만, 대부분의 시스템은 복잡하게 얽혀 있어 시스템을 재시작하는 건 간단하지 않다. 신경 쓸 것이 한 두개가 아니다.

그중에 가장 신경 써야 하는 건 고객들! 정해진 시간 동안 시스템에 접근할 수 없다고 고객에게 공지해야 한다. 그리고 정상적으로 연결 되었는지 확인하라고 요청해야 한다. 고객들에게 정중하게 메일을 보낸다.

"고객님, 시스템 휴지가 있습니다.
2시간 동안 시스템 접근이 불가능합니다."

문제가 발생하자 고객은 일단 메일을 받은 적이 없다고 우긴다.
결국, 우린 너무 고귀해서 모니터링 같은거 못하겠다고 한다. 시스템 모니터링은 너희가 해줘야 하는 서비스라고 한다.

고객님! 이러시면 안 되요! 👿

🔑 Problem

내가 관리하는 시스템은 서버 역할하고 고객 시스템은 클라이언트 역할을 한다. 서버와 클라이언트가 연결되어 있는 상태에서 서버를 재 시작한다. 서버는 어떤 클라이언트가 성공적으로 연결되었는지 알 수 있으나, 연결되지 않은 클라이언트가 어떤 상태인지는 알 수 없다.

  • 고객 시스템에 연결 상태를 알 수 없다.

💡 Idea

시스템 상태는 로그에 쓰여진다. 우린 로그만 있으면 고객 시스템의 상태를 확인 할 수 있다.

  • 원격지에 있는 EndPoint의 로그를 수집하자!

📝 Requirement

고객의 요구사항은 다음과 같다.

  • 시스템 변경을 최소화 해야 함.
    • 고객 시스템에 새로운 프로그램 설치 금지
    • 참조 Library 변경 최소화
    • Cross Platform 지원
    • Perform에 영향을 미치지 않을 것
  • Logstash Input plugins이 제공되는 Middleware를 사용해야 함.

✂️ Analyze

내가 관리하는 시스템의 로깅 환경부터 확인한다.

  • jdk1.7
  • log4j1.2.11

🍰 Solve

나는 이 문제를 SocketAppender를 이용해 풀어보려한다. 일단 컨셉일 뿐이고 대용량 시스템에 어떻게 적용해야 할지는 꽤나 많은 검증이 필요하다. 아래 소스코드는 Github 에서 확인 가능하다.

1. SocketAppender를 사용한다.

SocketAppender를 선택한 이유는 3가지 이다.

  • Log4j1.2.11에서 제공하는 기본적인 Appender
  • 현재 상태에서 추가되는 라이브러리 없음
  • Logstash 에서 SocketAppender를 위한 Input Plugins를 제공 함

SocketAppender는 고객 요구사항에 완벽하게 부합한다.

2. SimpleSocketServer 실행시키자!

SimpleSocketServer 는 특정 Port 로 부터 송신된 로그를 수신한다. 그리고 자체적으로 로그를 생성한다. 사용 방법은 매우 단순하며, log4j1.2 Javadoc에서 확인 할 수 있다.

Usage: java org.apache.log4j.net.SimpleSocketServer port configFile
where port is a part number where the server listens and
configFile is a configuration file fed to the PropertyConfigurator or to DOMConfigurator if an XML file.

SimpleSocketServer 가 사용하는 <Port>9999를 사용하기로 한다.
자제적으로 생성하는 로그는 <configFile>을 통해 설정하는데, 단순하게 콘솔화면으로 출력하도록 구성한다.

# log4j-server.properties
log4j.rootLogger=INFO,stdout

# stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%t :: %d :: %m%n

위 내용을 log4j-server.properties 파일로 적당한 위치에 저장한다. 나 같은 경우는 D:/log4j-socket-server에 저장하였다. 그리고 아래 명령으로 서버를 실행한다.

java -classpath d:/log4j-socket-server/Log4j-1.2.11.jar org.apache.log4j.net.SimpleSocketServer 9999 D:/log4j-socket-server/log4j-server.properties

3. SocketAppender 구성하자!

다음으로 SimpleSocketServer로 로그를 전송하는 SocketAppender를 구성하자. SocketAppenderLoggingEvent 객체를 원격 로그 서버로 전송하는 역할을 담당한다.

SocketAppender의 특성은 log4j1.2 Javadoc 에서 확인 할 수 있다.

내가 관리하는 시스템은 Programatically 하게 log4j 를 사용하므로 아래와 같이 Log4jSocketAppenderTest.java 를 작성하여 실행한다.

package com.choong.log4j.test;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.net.SocketAppender;

public class Log4jSocketAppenderTest {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Log4jSocketAppenderTest.class);

        PatternLayout patternLayout = new PatternLayout("%t :: %d :: %m%n");

        ConsoleAppender consoleAppender = new ConsoleAppender(patternLayout);
        SocketAppender socketAppender = new SocketAppender("localhost", 9999);

        logger.addAppender(consoleAppender);
        logger.addAppender(socketAppender);

        logger.info("Hello, ChoongYul!");
    }
}

4. SimpleSocketServer 출력결과

마지막으로 SimpleSocketServer 의 출력결과를 확인한다.

ouput:

D:\>java -classpath d:/log4j-socket-server/Log4j-1.2.11.jar org.apache.log4j.net.SimpleSocketServer 9999 D:/log4j-socket-server/log4j-server.properties
main :: 2023-01-08 12:57:10,386 :: Listening on port 9999
main :: 2023-01-08 12:57:10,417 :: Waiting to accept a new client.
main :: 2023-01-08 12:57:25,681 :: Connected to client at /127.0.0.1
main :: 2023-01-08 12:57:25,682 :: Starting new socket node.
main :: 2023-01-08 12:57:26,117 :: Waiting to accept a new client.
main :: 2023-01-08 12:57:25,774 :: Hello, ChoongYul!
Thread-0 :: 2023-01-08 12:57:26,385 :: Caught java.net.SocketException closing conneciton.
  • 9999 Port로 새로운 클라이언트가 연결되었고,
  • 클라이언트는 'Hello, ChoongYul!' 이라는 로그를 전송했다.
  • SimpleSocketServerlog4j-server.properties에서 설정한 ConsoleAppender를 통해 'Hello, ChoongYul!'을 출력하였다.

🛰️ Reference Site

0개의 댓글