7.2 KiB
title, source_type, url, archive_url, related_branches, related_projects, tags, created
| title | source_type | url | archive_url | related_branches | related_projects | tags | created | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| PostgreSQL Audit Logging Using Triggers — Vlad Mihalcea | company-tech-blog | https://vladmihalcea.com/postgresql-audit-logging-triggers/ |
|
|
2026-06-10 |
PostgreSQL Audit Logging Using Triggers — Vlad Mihalcea
Layer:
raw/company-tech-blogs/— 외부 기술 블로그의 원문 발췌·출처 기록. 검증된 요약은/ingest후wiki/concepts/에 별도 작성. 원본은 raw 에 영구 보관.
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-persistence-auditing-contract | DB-level trigger auditing (standalone) 대안 기각: 애플리케이션 액터 ID 를 트리거로 넘기려면 매 DML 직전 SET LOCAL var.logged_user 세션 변수 주입 seam 이 필요하고, DB 타임소스가 앱 Clock bean 과 분리되어 감사 시각 통제권을 잃는다. |
출처 / Source
- 원본 URL: https://vladmihalcea.com/postgresql-audit-logging-triggers/
- 아카이브 URL: (없음)
- 저자 / 조직: Vlad Mihalcea (개인 전문가 기술 블로그)
- 발행일: (페이지에서 확인된 날짜 없음)
- 마지막 확인일: 2026-06-10
왜 저장했는지 / Why archived
PostgreSQL 트리거 기반 감사 로깅 구현 시 애플리케이션이 매 DML 전에 세션 변수(var.logged_user)를 직접 주입해야 한다는 사실을 원문 인용으로 확보하기 위해 보관. 이 seam 의 존재가 "DB-level trigger 단독 사용" 대안을 기각하는 근거가 된다.
핵심 인용 / Key quotes (verbatim, 5문장)
[§ trigger function] "the
dml_created_bycolumn is set to the value of thevar.logged_userPostgreSQL session variable, which was previously set by the application with the currently logged user"
[§ trigger function / SQL]
current_setting('var.logged_user')
[§ SET LOCAL / connection pooling] "Notice that we used
SET LOCALas we want the variable to be removed after the current transaction is committed or rolled back. This is especially useful when using connection pooling."
[§ trigger definition] "In order for the
book_audit_trigger_funcfunction to be executed after abooktable record is inserted, updated or deleted, we have to define the following trigger:"
[§ introduction] "In this article, we are going to see how we can implement an audit logging mechanism using PostgreSQL database triggers to store the CDC (Change Data Capture) records."
Claims Extracted / 추출된 주장
이 자료가 직접 말하는 것만 claim 으로 분리한다. 내 프로젝트에 적용한 결론은 여기 쓰지 않는다.
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| C1 | 트리거가 감사 행위자를 식별하려면 세션 변수 var.logged_user 를 읽고, 그 값은 애플리케이션이 미리 설정해야 한다 |
[§ trigger function] "the dml_created_by column is set to the value of the var.logged_user PostgreSQL session variable, which was previously set by the application with the currently logged user" |
engineering-blog |
PostgreSQL AFTER 트리거가 DML 마다 실행되는 모든 환경 | 애플리케이션이 변수를 설정하지 않았을 때 트리거가 어떻게 동작하는지(에러/null) 는 이 글 단독으로 증명 안 됨 |
| C2 | 트리거 함수 내부에서 current_setting('var.logged_user') 호출로 사용자 값을 읽는다 |
[§ trigger function / SQL] current_setting('var.logged_user') |
engineering-blog |
PostgreSQL PL/pgSQL 트리거 함수 | current_setting 의 두 번째 인자(missing_ok) 동작은 이 코드만으로 확정 불가 |
| C3 | SET LOCAL 을 사용하면 트랜잭션 커밋/롤백 후 변수가 자동 소멸하며, 이는 커넥션 풀 환경에서 특히 유용하다 |
[§ SET LOCAL / connection pooling] "Notice that we used SET LOCAL as we want the variable to be removed after the current transaction is committed or rolled back. This is especially useful when using connection pooling." |
engineering-blog |
HikariCP 등 커넥션 풀을 사용하는 모든 Spring 앱 | SET LOCAL 이 실제로 커넥션 풀 재사용 시 변수를 100% 소멸시킴을 PostgreSQL 공식 문서 수준으로 보증하지 않음 — 추가 확인 필요 |
| C4 | 트리거는 AFTER INSERT OR UPDATE OR DELETE 로 정의된다(AFTER 트리거) |
[§ trigger definition] "In order for the book_audit_trigger_func function to be executed after a book table record is inserted, updated or deleted, we have to define the following trigger:" |
engineering-blog |
PostgreSQL 감사 로그 트리거 정의 | BEFORE 트리거와의 trade-off 를 이 글이 명시적으로 비교하지 않음 |
| C5 | 이 패턴은 PostgreSQL 트리거 + JSON 컬럼으로 CDC 레코드를 저장하는 감사 로깅 구현이다 | [§ introduction] "In this article, we are going to see how we can implement an audit logging mechanism using PostgreSQL database triggers to store the CDC (Change Data Capture) records." | engineering-blog |
PostgreSQL 트리거 기반 감사 로깅 구현 | 이 패턴이 JPA/Hibernate 감사(@EntityListeners) 나 Envers 보다 우월하다는 주장은 이 글 단독으로 증명 안 됨 |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것:
C1,C2: 트리거가 직접current_setting('var.logged_user')를 읽고, 그 값은 애플리케이션이 매 DML 전SET LOCAL로 주입해야 한다 — 즉 애플리케이션-DB 간 세션 변수 propagation seam 이 불가피하다C3:SET LOCAL스코프는 트랜잭션 경계와 동기화되므로 커넥션 풀 환경에서 변수 누출을 방지한다 (단,engineering-blog등급이므로 official 보증 아님)C4: AFTER 트리거가 사용됨
- 이 자료가 증명하지 않는 것:
- JPA
@EntityListeners/ Spring Data Auditing / Hibernate Envers 와의 전면 비교 current_setting이 변수 미설정 시 null 반환인지 예외 발생인지 (PostgreSQL 공식 문서 별도 확인 필요)- 이 패턴이 ca-tmpl 실제 HikariCP 설정 하에서 변수 누출 없이 동작함
- JPA
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
- PostgreSQL 공식 문서에서
current_setting(name, missing_ok)동작 확인 - ca-tmpl 의 HikariCP +
SET LOCAL조합에서 커넥션 반납 후 변수 완전 소멸 여부 로컬 검증
- PostgreSQL 공식 문서에서
메모 / Notes
- 이 글은 개인 전문가 블로그(
engineering-blog) 등급이다. C3 의SET LOCAL+ 커넥션 풀 안전성은 공식 PostgreSQL 문서로 보강하기 전까지needs-confirmation취급. - 추가로 봐야 할 동일 출처: vladmihalcea.com/the-anatomy-of-connection-pooling/ (C3 보강 가능성)
- Hibernate Envers, Debezium 대안이 언급되나 비교 상세는 이 글 범위 밖.
Related / 관련
- 같은 주제 다른 자료: raw/company-tech-blogs/slow-query-datasource-proxy-spring-boot-galovics
- 이 자료를 인용한 wiki 요약: (생성 시)