ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TCP 네트워킹과 log4j2 사용방법(로그를 찍어보자!)
    JAVA 2022. 4. 6. 22:13

    우리가 일상 생활에서 보통 말하는 "인터넷"은,
    네트워크 용어로 "TCP/IP 네트워크" 라고 한다.
    여기서, TCP와 IP는 통신규약(protocol)을 의미한다.

    TCP 네트워킹

     

    특징

    연결 지향적 프로토콜이다. 클라이언트와 서버가 서로 연결된 상태에서 데이터를 주고받는다!

    네트워킹이 이루어지는 순서는 다음과 같다.

    1. 클라이언트가 서버에 연결 요청

    2. 서버가 클라이언트의 요청 수락 (통신 선로 고정)

    3. 통신 선로를 통해 데이터 주고받기

     

    요청을 통해 고정된 통신 선로를 통해서 데이터를 주고받기 때문에 안정적이고 정확하다는 장점이 있다.

    반대로, 연결이 되어야지만 데이터를 보낼 수 있다는 점에서 시간이 소요되고 전송 속도가 느릴 수 있다는

    단점이 있다.

     


    java는 Old I/O 기반 네트워킹 프로그래밍을 위해 java.net 패키지를 제공한다.
    > java.net.ServerSocket / java.net.Socket

    (1) ServerSocket 클래스 ---- for server
    Socket 클래스       ---- for server
    (2) Socket 클래스       ---- for client
    (1),(2) : 연결통로를 만들어주는 행위
    (3) InputStream/OutputStream/Reader/Writer/모든 보조스트림 : 실제로 데이터를 주고받는 모든 행위
    (4) InetAddress(IP주소 + 호스트명) /InetSocketAddress(InetAdress + Port)

    * New I/O (= NIO) 기반으로는 <Ditto.>를 사용한다.
    > java.nio 패키지

     


    log4j2

     

    log를 찍어주는 라이브러리 : log4j 2

    최근 log4j의 보안이 취약하다는 문제가 기사화 될 정도로 알려지면서, log4j는 사용하지 않게 되었다.

    이를 보안해서 새로 나온 것이 log4j2이다.

     

    log4j2는 롬복 어노테이션 사용이 가능하다!

     

    log4j2 설치방법

     

    해당 사이트 (https://logging.apache.org/log4j/2.x/)에서 다운 가능하다.

    왼쪽 메뉴에서 Download 클릭 후 binary파일 중 원하는 압축형태로 내려받으면 된다.

    (Mirrors에 있는 목록을 다운받는다.)

     

    다운받으면 파일이 엄청 많은데, 모든 파일의 압축을 풀 필요는 없고

    log4j-api-2.17.2.jar
    log4j-core-2.17.2.jar
    파일만 해제해서 사용하면 된다.
    (압축파일 열기에서 해당 파일을 드래그앤드롭하면 해당파일만 압축해제할 수 있다.)

     

    이클립스 이용 시,
    해당 jar파일을 이클립스의 워크스페이스 폴더에 넣은 후, 이클립스에서 classpath로 경로를 설정한다.

     

    그 후, xml 파일을 생성해서 사용할 프로젝트의 src폴더 안에 넣어주어야 하는데, 소스코드는 

    다음과 같이 작성한다.

    <?xml version="1.0" encoding="UTF-8"?>
    
    
    <Configuration status="WARN">
    
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} %5p --- [%-15.40t] %-1.50c{1.}.%M - %m%n%ex"/>
            </Console>
        </Appenders>
    
    
        <Loggers>
            
    
            <Root level="trace">
                <AppenderRef ref="Console"/>
            </Root>
        </Loggers>
    
    </Configuration>

    xml 파일은 상황에 따라 설정을 변경하면서 사용하면 된다.

    매우매우 많은 옵션이 있는데, 여기서 <Loggers>블록만 설명하자면,

    Loggers는 로깅 작업에 대한 설정을 할 수 있다.

    <Loggers> 안에는 <Root>와 <logger>이 존재한다.

    <Root> : 일반적인 로그정책에 대한 정의. 반드시 하나만 존재해야 한다.

    <Logger> : 여러개 정의가 가능하다. 패키지 범위를 지정할 수도 있다.

    <AppenderRef> : <Appenders>의 참조를 지정한다. <Root>와 <Logger>태그 안에서만 사용이 가능하다.

     

    간혹 xml 파일을 src에 넣었는데 로그 자체가 찍히지 않는 경우,

    Loggers 태그 내 설정이 잘못되어있을 경우가 많다.

     

    여기서 level에 대해 알고 넘어가면 좋은데,

    level은 log4j2에서 기본으로 제공하는 로그의 수준과 메세지를 정의하는 옵션이다.

    심각도에 따라 레벨이 구분된다.

    log4j2를 사용한다면 매우매우매우 많이 쓰는 옵션이니, 의미는 꼭 알아두도록 하자

    Level Description
    OFF 가장 높은 레벨이며, 로깅을 해제한다.
    FATAL 조기 종료를 유발하는 심각한 오류단계. 콘솔에서 즉시 볼 수 있다.
    ERROR 기타 런타임 오류 또는 예기치 않은 상태. 콘솔에서 즉시 볼 수 있다.
    WARN deprecated API를 사용했거나, API 사용 불량 등 정확히 "오류"는 아니지만 바람직하지 않거나 예상치 못한 기타 런타임 상황. 콘솔에서 즉시 볼 수 있다.
    INFO 런타임 이벤트(시작/종료)가 일어났을 경우. 즉시 콘솔에 나타나므로 최소한으로 유지하는 것을 권장.
    DEBUG 시스템을 통한 흐름에 대한 자세한 정보. 로그에만 기록될 것으로 예상. 일반적으로 애플리케이션에서 기록하는 대부분의 행은 DEBUG로 작성해야한다.
    TRACE 가장 자세한 정보. 로그에만 기록될 것으로 예상.

     

    xml 파일 설정을 정상적으로 마친 후,

    클래스 선언부에서 lombok 어노테이션을 붙이면 log를 찍을 수 있다.

    @Log4j2
    public class LogExample {;;}

    이 어노테이션은 롬복에서 제공하는 어노테이션으로, 

    해당 클래스의 clazz 객체의 FQCN을 logger name으로 갖는 Logger를

    static final 필드로 자동으로 추가해주는 기능을 한다.

     

    따라서 위의 코드블럭은 아래의 코드블럭과 동일하다!

     public class LogExample {
         private static final org.apache.logging.log4j.Logger log = 
         	org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
     }

     

    log를 찍는 법은 printf와 비슷하다.
    첫번째 매개변수에 출력할 형식을 문자열로 지정하고, 그 후 가변인자로 넣어줄 객체를 지정하면 된다
    포맷팅 기호는 {}이다(가변인자가 {}에 들어간다.)

    log.debug("main({}) invoked.", Arrays.toString(args));

    예시) 매개변수(Arrays.toString(args))가 출력할 때 중괄호 안에 찍히게 된다.

     

    이제 로그를 한번 찍어보도록 하자.

    주의할 점은 logging은 "기록"을 남겨주는 것이지 그 안에 어떤 정보를 넣을지는 내가 직접 정해주어야 한다!!

    log4j2는 로그를 찍어주는 기능 외에 뭐 호스트 주소를 가져와준다든가 하는 기능은 없다는 말.

    단어 자체의 의미에 집중하면 된다.

     

    java.net 패키지를 이용해 실제로 로그를 찍어보는 코드를 작성해보자.

    package sample0406.inetadress;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.Arrays;
    
    import lombok.extern.log4j.Log4j2;
    
    
    @Log4j2
    public class Logging {
    	
    	
    	public static void main(String[] args) throws UnknownHostException {
    		log.debug("main({}) invoked.", Arrays.toString(args));
    		
    		InetAddress localHost = InetAddress.getLocalHost();
    		
    		log.info(" 1. localHost : {}", localHost);
    		log.info(" 2. loopBackAddress : {}", InetAddress.getLoopbackAddress());
    		byte[] byteAddr = localHost.getAddress();
    		log.info(" 3. getAddress : {}", Arrays.toString(byteAddr));
    		
    		for(byte b : byteAddr) {
    			log.info("\t adressOneByOne : {}", (b > 0) ? b : b + 256);
    		} // enhanced for
    		
    	} // main
    
    } // end class

    이 코드를 실행하면 콘솔창에 다음과 같이 로그가 찍히는 것을 확인할 수 있다.

     

    위에서 말했던 level을 알고있으면, 저 코드가 무엇을 의미하는지 알 수 있다.

    log.debug는 debug레벨로 로그를 출력

    log.info는 info레벨로 로그를 출력한다는 의미다.

     

    아무도 내 PC의 IP주소에 관심 가지지 않겠지만 다들 가리길래 가려야하는건가보다 하고 가렸다...

    java.net의 InetAddress(IP주소를 가져오는 패키지)를 이용해 로컬호스트의 이름과 IP주소, 루프백 주소를 찍어봤다.

    여기서 하나 눈여겨볼점은, 로컬호스트를 바이트 배열로 받아서 그대로 출력할 경우 때에 따라 음수가 출력될 수도 있다는 것이다. 정상적인 IP주소는 모두 양수기 때문에,

    256을 더해 양수로 변환한 후 하나하나 찍어보았다. 왜 256인지는 바이트 타입의 범위가 -128~128인 것과 관련있다.

     

    내PC말고 다른 웹사이트의 정보를 출력하고 싶다면, java.net의 URL 패키지를 사용하면 된다.

    URL패키지는 해당 URL의 자원을 가져오는 기능을 제공한다.

     

    URL url1 = new URL("https://en.dict.naver.com/#/search?query=shrimp");
    log.info("1. url1 : {}, type : {}", url1, url1.getClass().getName());

    메인메소드 안에서 이런식으로 작성하면 된다.

    URL 객체 생성시 입력하는 주소는 저렇게 풀네임으로 적어도 되지만, 따로따로 분리해서 넣어주는 방법도 있다.

     

    URL url1 = new URL("http", "en.dict.naver.com", 80, "/#/search?query=shrimp");
    log.info("1. url1 : {}, type : {}", url1, url1.getClass().getName());

    프로토콜, 도메인이름, 포트번호, URI 순으로 나눠서 표기할 수 있다.

    String 필드에 분리해서 저장해놓고 변수를 불러와 사용할 수도 있을것 같다.

     

    참고로 우리가 사용하는 거의 모든 웹사이트의 포트번호는 80이기 때문에, 생략이 가능하다.

    (http : 80 / https : 443)

    http와 https의 차이는,

    https는 암호화된 http라고 생각하면된다. (http + s (secure))

     

    URI클래스의 다양한 get메소드를 사용해 필요한 정보들을 로그로 찍어낼 수 있다.

    댓글

Designed by Tistory.