9. 로그 관리

이 장을 마치면: 어떤 로그가 어디에 쌓이는지 알고, 로그와 core 파일이 디스크를 채우지 않게 관리한다.

9.1 로그 파일 지도

모든 로그는 ~/gritdb1/log/에 있다.

구분 파일 회전
설치 install_gritdb_<일시>.log(설치마다 새 파일) 없음
감독 프로세스 grit_admin_main.log와 grit_admin_channel_server.log 자동
화면 출력 grit_admin_stdout.log — 감독 프로세스, GritDB 엔진, catalog의 화면 출력. ⚠ 기동할 때마다 덮어쓴다 없음
PostgreSQL postgresql.log — 실패한 SQL 원문이 들어간다 없음(9.4)
공용(PostgreSQL 쪽과 GritDB 엔진이 같이 쓴다) grit_surfer_main.log와 grit_plug_producer_processor.log 200 MB를 넘길 수 있다. 크기 회전이 거의 일어나지 않기 때문이다. 정리는 9.5를, 크기 기록은 7.4를 본다
PostgreSQL 안의 GritDB 작업 grit_surfer_slot_manager_worker.log와 grit_recovery_worker_process.log 자동
catalog grit_catalog_processor.log(기동, 설정 읽기, 처리) 자동
엔진 — 변경분 수집 grit_plug_consumer_processor.log 자동
엔진 — 저장 grit_unify_main.log, grit_unify_delta_processor.log, grit_unify_chunk_processor.log, grit_unify_writer_processor.log, grit_unify_cold_store_compactor_gc_processor.log, grit_unify_hot_store_gc_processor.log, grit_unify_hot_store_memory_pool_gc_processor.log 자동
엔진 — 질의 처리 grit_burst_main.log와 grit_burst_query_processor.log 자동
중단 기록 GRIT_SURFER_ASSERT.log — 평소에는 0바이트다. 0보다 크면 중단이 있었다 없음

9.2 형식 · 등급

  • GritDB 로그 형식은 [일시][등급][tid:스레드][발생 위치] 내용이다. 등급은 INFO, WARN, ERROR다. 형식과 등급은 QuickStart 5.1과 같다.
  • 한 줄은 최대 4096바이트다. 넘는 줄은 잘리고 ...로 끝난다.
  • 회전된 새 파일의 첫 줄은 [GritSurferLogger] Log rotated - old file size: <바이트> bytes다. 이 줄에는 머리 칸이 없다.
  • PostgreSQL 로그(postgresql.log)는 PostgreSQL 기본 형식이다. 줄 머리는 log_line_prefix 기본값인 <일시> <시간대> [<PID>]다. 그 뒤에 LOG:, ERROR:, FATAL:, PANIC: 등이 온다. 실패한 문장은 다음 줄 STATEMENT:에 남는다(9.7). GritDB 확장의 메시지(GritSurfer: …)도 이 파일에 남는다.
  • GritDB 로그는 늘 INFO 등급으로 쓴다. INFO, WARN, ERROR 줄이 남는다. config/grit_*.config의 등급 키(*.log_level)는 1.1에서 등급을 바꾸지 않는다. 키는 지우지 않는다(5.6).
  • 로그 크기 키(grit_unify.delta.log_file_max_byte)도 1.1에서 쓰지 않는다. 회전 크기는 9.3의 고정값이다. 키는 지우지 않는다(5.6).

9.3 회전 · 크기

구분 회전 크기
GritDB 로그(9.1 표의 “자동”) 파일마다 200 MB에서 회전한다. .1(최신)부터 .20까지 남기고 그보다 오래된 파일은 지운다 로그 1종에 최대 약 4 GB
공용 로그 2개(grit_surfer_main.log와 grit_plug_producer_processor.log) 크기 회전이 거의 일어나지 않는다 200 MB를 넘어 계속 커질 수 있다. 실행 중에는 그대로 둔다. 정지 때 보관하고 정리한다(9.5)
회전하지 않는 파일 4개(postgresql.log, grit_admin_stdout.log, GRIT_SURFER_ASSERT.log, datafiles/query_text_archive.jsonl) 없음 계속 커진다. grit_admin_stdout.log만 기동할 때 새로 쓴다. 9.4와 9.5를 본다
  • 실행 중에 회전된 파일(.1~.20)을 지우거나 옮겨도 된다.
  • 회전하는 GritDB 로그가 모두 차면 log/는 수십 GB가 된다. 디스크 계획은 1.3을, 매일 크기 기록은 7.4를 본다.

9.4 PostgreSQL 로그 회전

설치 기본에서는 postgresql.log를 회전하지 않는다. 한 파일이 계속 커지므로 운영자가 회전을 설정한다. PostgreSQL 쪽 설명은 로그 파일 관리에 있다.

OS의 logrotate로 회전한다. 로그의 자리와 이름은 바뀌지 않는다. /etc/logrotate.d/gritdb를 root로 만든다.

<설치 경로>/log/postgresql.log {
    su gritdb gritdb
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}
  • <설치 경로>에는 절대 경로를 쓴다(예: 서비스 계정 홈 아래 gritdb1).

  • rotate 30과 daily는 예다. 보존 기간(9.5)에 맞춘다.

  • copytruncate는 파일을 복사한 뒤 비운다. GritDB를 멈추지 않고 회전한다. 복사와 비우기 사이에 쓴 몇 줄을 잃을 수 있다. GritDB는 postgresql.log를 덧붙이기(append)로 열어 쓰므로 비운 뒤 앞에 빈 공간이 생기지 않는다.

  • sudo logrotate -d /etc/logrotate.d/gritdb를 실행해 오류 줄이 없는지 확인한다. 다음 날 ls -l <설치 경로>/log/postgresql.log*를 실행해 회전된 파일이 있는지 확인한다.

  • 회전한 날의 ERROR 수(QuickStart 5.2, 7.4)는 아래 명령처럼 두 파일에서 함께 센다. logrotate는 하루 한 번 돈다(Ubuntu 24.04에서는 자정부터 1시간 안). 회전 전에 쓴 오늘 줄은 postgresql.log.1로 옮겨진다. delaycompress는 .1을 압축하지 않는다는 뜻이다.

    cat ~/gritdb1/log/postgresql.log.1 ~/gritdb1/log/postgresql.log 2>/dev/null | grep -c "^$(date +%F).*ERROR:"
    

PostgreSQL 로그 수집기(logging_collector)로 회전할 수도 있다. 이때는 로그 자리가 바뀐다.

⚠ logging_collector를 켜면 PostgreSQL 로그의 자리와 이름이 바뀐다

  • 이유: 새 로그는 log_directory와 log_filename이 정한 파일에 쌓인다. QuickStart 5.2와 7장의 postgresql.log 명령이 새 줄을 보지 못한다.
  • 대신: logrotate를 쓴다. 수집기를 켰으면 바꾼 자리와 이름을 운영 기록에 적고, 점검 명령의 파일 이름을 바꾼다.

9.5 보존 · 정리

  • 보존 기간은 기관의 로그 보존 규정을 따른다.
  • 장애가 난 때부터 지원 문의가 끝날 때까지는 그때의 로그를 지우지 않는다. QuickStart 7.4가 log/를 통째로 모으기 때문이다.
파일 실행 중 정리 정리 방법
회전된 GritDB 로그(*.log.<N>) 된다 보존 기간이 지난 것을 지우거나 옮긴다(아래)
공용 로그 2개(grit_surfer_main.log와 grit_plug_producer_processor.log) 하지 않는다 정지한 상태에서 이름을 바꿔 보관한다(아래)
postgresql.log 회전 설정(9.4) logrotate가 지운다
grit_admin_stdout.log 하지 않는다 기동할 때마다 새로 쓴다. 비정상 종료 뒤에는 다시 기동하기 전에 모은다(4.3)
GRIT_SURFER_ASSERT.log 하지 않는다 0보다 크면 모아서 지원 문의를 한다(QuickStart 7.4). 문의가 끝난 뒤 정지 상태에서 다른 이름으로 옮긴다. 다음 기동 때 빈 파일이 생긴다
install_gritdb_<일시>.log 된다 설치 기록으로 보관한다
datafiles/query_text_archive.jsonl 옮길 수 있다 SQL 원문이 들어 있으므로 보관 규정에 따라 옮기고 지운다(9.7)

보존 기간이 지난 회전 파일을 서비스 계정으로 지운다. 먼저 -print로 대상을 본다.

find ~/gritdb1/log -name '*.log.[0-9]*' -mtime +<일수> -print
find ~/gritdb1/log -name '*.log.[0-9]*' -mtime +<일수> -delete

정지한 상태에서 공용 로그 2개를 보관한다.

for f in grit_surfer_main.log grit_plug_producer_processor.log; do
  mv ~/gritdb1/log/"$f" ~/gritdb1/log/"$f.$(date +%Y%m%d)"
done
  • ls -l ~/gritdb1/log/를 실행해 날짜가 붙은 파일이 있는지 확인한다. 다음 기동 뒤에는 원래 이름의 새 파일이 생겼는지 확인한다.
  • 이름을 바꾼 파일도 위 find 정리 대상이 된다.

9.6 core 파일

core 파일은 프로세스가 비정상으로 끝날 때 그 메모리를 디스크에 쓴 파일이다. GritDB 엔진의 core는 엔진 메모리만큼(수십 GB) 크다.

생기는 때 절
즉시 정지(gritdb-stop --quick) 4.2
정상 정지가 남은 세션 때문에 즉시 정지로 넘어갔을 때 4.2
비정상 종료나 정지 실패 4.3

core가 생기는 조건과 자리를 서비스 계정으로 본다.

ulimit -Hc
cat /proc/sys/kernel/core_pattern
  • ulimit -Hc가 0이면 core가 생기지 않는다. GritDB 엔진은 soft 한도를 이 hard 값까지 올려 쓴다. 설정은 1.4에 있다.
  • core_pattern이 경로면 그 자리에 쓴다. |로 시작하면 OS의 core 수집 프로그램이 받는다. 이때는 그 프로그램의 자리와 설정을 본다.
  • core를 1분 안에 다 쓰지 못하면 잘리므로 빠른 디스크에 둔다.
  • core는 엔진 메모리만큼 여유가 있는 디스크에 둔다. datafiles/와 같은 파일시스템이면 core가 데이터 디스크를 채울 수 있다.
  • core는 지원 문의가 끝날 때까지 지우지 않는다. 끝난 뒤 지운다(7.6).
  • 지원 문의 때는 core의 자리와 크기를 알린다(QuickStart 7.4).
  • core에는 메모리 안의 데이터 값이 들어 있다. 반출은 9.7을 본다.

9.7 반출

  • ⚠ 로그, core 파일, 분석 질의 원문 파일에 SQL 원문과 데이터 값이 들어 있을 수 있다.
파일 들어 있는 것
postgresql.log 실패한 문장 원문(STATEMENT: 줄과 이어지는 줄), 오류 설명(DETAIL:, CONTEXT:, QUERY:), 오류 문구(ERROR:)의 값, log_statement(11.9)와 log_min_duration_statement로 남긴 문장(LOG: statement:, LOG: execute <이름>:, LOG: duration: … statement: 줄과 이어지는 줄). 11.9의 ddl이면 암호도 들어 있다
GritDB 로그(grit_*.log*) SQL 원문, 데이터 값, 파일 경로가 들어갈 수 있다
datafiles/query_text_archive.jsonl 분석 세션 조회의 SQL 원문 전체
분석 질의 이력(6.5) SQL 원문 앞 1024자
core 파일 프로세스 메모리 전체(데이터 값)

반출 전 순서:

  1. 보낼 파일은 아래 3번에서 만드는 $S.masked.tar.gz로 정한다. 이 묶음은 QuickStart 7.4 수집물, 실제로 쓰인 설정, 가린 로그로 이루어진다. QuickStart 7.4의 $S.tar.gz에는 가리지 않은 로그가 들어 있으므로 보내지 않는다. 이 파일은 서비스 계정만 읽게 두거나 지운다(11.7).

  2. 위 표의 자리를 기관 반출 규정에 따라 검토한다.

  3. 로그를 가린다. SQL 원문 줄을 뺀 사본으로 묶음을 다시 만든다. QuickStart 7.4와 같은 셸(cd ~, $S)에서 실행한다.

    for f in ~/gritdb1/log/postgresql.log*; do
      zcat -f "$f" | awk '/(STATEMENT|DETAIL|CONTEXT|QUERY):/ || /LOG: +(duration: [0-9.]+ ms +)?(statement|execute|bind|parse)[^:]*:/ {skip=1; next} skip && /^\t/ {next} {skip=0; print}' > "$S/masked_$(basename "$f" .gz)"
    done
    grep -c -E '(STATEMENT|DETAIL|CONTEXT|QUERY):|LOG: +(duration: [0-9.]+ ms +)?(statement|execute|bind|parse)[^:]*:' "$S"/masked_*
    cp ~/gritdb1/datafiles/pgdata/postgresql.auto.conf "$S/"
    cp -r ~/gritdb1/config "$S/"
    tar -czf "$S.masked.tar.gz" --exclude='postgresql.log*' "$S" -C ~/gritdb1 log
    tar -tzf "$S.masked.tar.gz" | grep -c '/postgresql\.log'
    
    • 빼는 줄은 오류에 딸린 문장과 설명(STATEMENT:, DETAIL:, CONTEXT:, QUERY:), log_statement와 log_min_duration_statement로 남긴 문장(statement:, execute, bind, parse)이다. 탭으로 시작하는 이어지는 줄까지 뺀다.
    • 회전된 파일(9.4의 .1, .2.gz …)도 가린다. zcat -f는 압축하지 않은 파일을 그대로 읽는다. 묶음에는 가리지 않은 postgresql.log*를 넣지 않는다(--exclude).
    • 첫 grep -c가 파일마다 0을 내고 마지막 줄이 0을 내는지 확인한다.
    • postgresql.auto.conf(ALTER SYSTEM 값, 5.3)와 config/(GritDB 엔진 설정, 5.6)는 실제로 쓰인 설정이므로 함께 보낸다.
    • ERROR: 줄에도 값이 들어갈 수 있으므로 2번 검토에서 본다.
  4. core 파일은 가릴 수 없으므로 보낼지를 기관과 정한다. 보내지 못하면 지원 문의 때 그렇게 알린다.

  5. 보낸 파일, 날짜, 받는 곳을 기록한다.

  • 자세한 수집과 반출 절차는 TroubleShooting을 본다.

문제가 생기면

  • 디스크가 모자라면 QuickStart 7장의 GDB-RUNTIME-002와 TroubleShooting을 본다.

더 알아보기