postgresql.conf 로그 세팅 커스텀

박성현·2026년 2월 10일

개발중 학습

목록 보기
41/43

PostgreSQL 로그에 실제 클라이언트 IP 남기기

문제 상황

배포 환경에서 PostgreSQL 로그를 확인하면 모든 접속이 서버 IP로만 기록되는 문제가 발생했습니다.

# 로컬 환경
2026-02-10 10:00:00 [12345] 192.168.0.49 mydb  ✅ 실제 클라이언트 IP

# 배포 환경
2026-02-10 10:00:00 [12345] 192.168.0.111 mydb  ❌ 서버 IP만 표시

원인

클라이언트 (192.168.0.49)
    ↓
웹서버/프록시 (192.168.0.111)
    ↓
PostgreSQL → client_addr = 192.168.0.111 (웹서버 IP만 보임)

PostgreSQL은 직접 연결된 클라이언트 IP만 인식하기 때문에 프록시 환경에서는 서버 IP만 기록됩니다.


해결 방법

PostgreSQL의 application_name에 실제 클라이언트 IP를 저장하는 방식으로 해결했습니다.

1. Interceptor 생성

DatabaseClientIpInterceptor.java

@Slf4j
@Component
@RequiredArgsConstructor
public class DatabaseClientIpInterceptor implements HandlerInterceptor {

    private final DataSource dataSource;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        try {
            // HTTP 헤더에서 실제 클라이언트 IP 추출
            String clientIp = IpAddrHelper.getClientIpAddr(request);
            
            // PostgreSQL에 application_name 설정
            try (Connection conn = dataSource.getConnection();
                 Statement stmt = conn.createStatement()) {
                String appName = "myapp_" + clientIp.replace("'", "");
                stmt.execute("SET application_name TO '" + appName + "'");
                log.debug("Set PostgreSQL application_name to: {}", appName);
            }
        } catch (Throwable e) {
            log.warn("Failed to set client IP (ignored): {}", e.getMessage());
        }
        
        return true;
    }
}

2. WebConfig에 등록

@Override
public void addInterceptors(InterceptorRegistry registry) {
   		~ 기존로직 ~
        
    // DB IP Interceptor 추가
    registry.addInterceptor(databaseClientIpInterceptor)
        .addPathPatterns("/**")
        .excludePathPatterns(excludes);
}

3. PostgreSQL 설정

postgresql.conf

log_line_prefix = '%m [%p] %h %d @%a '
  • %m: 타임스탬프
  • %p: 프로세스 ID
  • %h: 클라이언트 IP (서버 IP로 표시됨)
  • %d: 데이터베이스명
  • %a: application_name (실제 클라이언트 IP 표시) ✅

동작 흐름

1. 클라이언트 요청 (192.168.0.49)
   ↓
2. DatabaseClientIpInterceptor 실행
   - X-Forwarded-For 헤더에서 실제 IP 추출
   - SET application_name TO 'myapp_192.168.0.49' 실행
   ↓
3. Controller 실행
   - DB 쿼리: SELECT * FROM users
   ↓
4. PostgreSQL 로그 기록
   - "2026-02-10 10:00:00 [12345] 192.168.0.111 mydb @myapp_192.168.0.49"

결과

변경 전:

2026-02-10 10:00:00 [12345] 192.168.0.111 mydb SELECT * FROM users
2026-02-10 10:00:01 [12346] 192.168.0.111 mydb SELECT * FROM orders

변경 후:

2026-02-10 10:00:00 [12345] 192.168.0.111 mydb @myapp_192.168.0.49 SELECT * FROM users
2026-02-10 10:00:01 [12346] 192.168.0.111 mydb @myapp_192.168.0.52 SELECT * FROM orders

이제 @myapp_ 뒤에 각 클라이언트의 실제 IP가 기록되어 사용자별 추적이 가능합니다.


특징

장점

  • 기존 로직에 영향 없음
  • 실패해도 요청은 정상 처리
  • 언제든 비활성화 가능
  • 여러 프로젝트에 재사용 가능

주의사항

  • 정적 리소스는 제외 권장 (성능 최적화)
  • SQL Injection 방지를 위해 특수문자 필터링 필수

마무리

프록시 환경에서 PostgreSQL 로그에 실제 클라이언트 IP를 남기는 방법을 Spring Interceptor와 application_name을 활용해 구현했습니다. 이를 통해 사용자별 DB 접근 추적과 보안 감사가 가능해졌습니다.

profile
개발기록장

0개의 댓글