LoggingFilter


<aside>

package lh.h.config;

import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class LoggingFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;

        // 1. 공인 IP (X-Forwarded-For)
        String publicIp = req.getHeader("X-Forwarded-For");
        if (publicIp == null || publicIp.isEmpty() || "unknown".equalsIgnoreCase(publicIp)) {
            publicIp = req.getHeader("X-Real-IP"); // Nginx가 설정한 공인 IP
        }
        if (publicIp != null && publicIp.contains(",")) {
            publicIp = publicIp.split(",")[0].trim(); // 여러 개일 경우 첫 번째 (공인 IP)
        }

        // 2. 내부 IP (Local IP)
        String privateIp = req.getRemoteAddr();

        // 요청 URL과 함께 IP 로그 기록
        logger.info("Client Public IP: {}, Client Private IP: {}, Requested URL: {}",
                publicIp, privateIp, req.getRequestURI());

        chain.doFilter(request, response);
    }
}

</aside>

logback-spring.xml


<aside>

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 콘솔에 로그 출력 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - [PublicIP: %msg] [PrivateIP: %msg]%n</pattern>
        </encoder>
    </appender>

    <!-- 로그를 파일에 저장 -->
    <appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/ip-requests.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/ip-requests-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory> <!-- 30일간 로그 보관 -->
            <totalSizeCap>100MB</totalSizeCap> <!-- 전체 로그 용량 제한 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - [PublicIP: %msg] [PrivateIP: %msg]%n</pattern>
        </encoder>
    </appender>

    <!-- LoggingFilter 로그만 별도 파일에 저장 -->
    <logger name="lh.h.config.LoggingFilter" level="INFO" additivity="false">
        <appender-ref ref="fileAppender"/>
    </logger>

    <!-- 전체 애플리케이션 로그 설정 -->
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="fileAppender"/>
    </root>

</configuration>

</aside>

/etc/nginx/sites-available/default


<aside>

location / {
    proxy_pass <http://localhost:8083>; # 내부 애플리케이션 주소
    proxy_http_version 1.1;
    
    # 클라이언트의 실제 IP 전달
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

</aside>

/build/libs


<aside>

1. mkdir logs

2. chmod 777 logs

</aside>