본문 바로가기
WIKI 기술 지식 베이스

log 지시문

원문 보기 위키 갱신

log 지시문 (HTTP 요청 로깅)

log 지시문은 HTTP 요청 로깅(액세스 로그라고도 함)을 활성화하고 설정해요. Caddy의 런타임 로그를 설정하려면 log 글로벌 옵션을 대신 참고해요.

출처: Caddy 공식 문서

본문

HTTP 요청 로깅(액세스 로그라고도 함)을 활성화하고 설정해요.

Caddy의 런타임 로그를 설정하려면 log 글로벌 옵션을 대신 참고해요.

log 지시문은 그것이 나타나는 사이트 블록의 호스트 이름에 적용되며, hostnames 하위 지시문으로 재정의할 수 있어요.

설정하면 기본적으로 사이트에 대한 모든 요청이 로깅돼요. 일부 요청을 로깅에서 조건부로 건너뛰려면 log_skip 지시문을 사용해요.

로그 항목에 커스텀 필드를 추가하려면 log_append 지시문을 사용해요.

기본적으로 잠재적으로 민감한 정보가 있는 헤더(Cookie, Set-Cookie, Authorization, Proxy-Authorization)는 액세스 로그에서 REDACTED로 기록돼요. 이 동작은 log_credentials 글로벌 서버 옵션으로 비활성화할 수 있어요.

문법 (Syntax)

log [<logger_name>] {
	hostnames <hostnames...>
	no_hostname
	output <writer_module> ...
	format <encoder_module> ...
	level  <level>
	sampling {
		interval   <duration>
		first      <number>
		thereafter <number>
	}
}
  • logger_name은 이 사이트의 로거 이름을 재정의하는 선택적 값이에요.

    기본적으로 로거 이름은 자동 생성돼요. 예를 들어 log0, log1 등으로, Caddyfile의 사이트 순서에 따라 결정돼요. 이는 전역 옵션에 정의된 다른 로거에서 이 로거의 출력을 안정적으로 참조하고 싶을 때만 유용해요. 아래 예시를 참고해요.

  • hostnames는 이 로거가 적용되는 호스트 이름을 재정의하는 선택적 값이에요.

    기본적으로 로거는 그것이 나타나는 사이트 블록의 호스트 이름, 즉 사이트 주소에 적용돼요. 와일드카드 사이트 블록에서 서브도메인별로 다른 로거를 정의하고 싶을 때 유용해요. 아래 예시를 참고해요.

  • no_hostname은 로거가 사이트 블록의 어떤 호스트 이름과도 연결되지 않게 해요. 기본적으로 로거는 log 지시문이 나타나는 사이트 주소와 연결돼요.

    요청 경로나 메서드 같은 조건에 따라 다른 파일로 요청을 로깅하고 싶을 때 유용해요. log_name 지시문을 사용해요.

  • output은 로그를 어디에 쓸지 설정해요. 아래 output 모듈을 참고해요.

    기본값: stderr.

  • format은 로그를 어떻게 인코딩(형식화)할지 설명해요. 아래 format 모듈을 참고해요.

    기본값: stderr가 터미널로 감지되면 console, 그 외에는 json.

  • level은 로깅할 최소 항목 레벨이에요. 기본값: INFO.

    액세스 로그는 현재 INFO와 ERROR 레벨 로그만 발행한다는 점에 주의해요.

  • sampling은 로그 양을 줄이기 위한 로그 샘플링을 설정해요. 샘플링이 지정되면 아래 기본값으로 활성화돼요. 생략하면 샘플링이 비활성화돼요.

  • interval은 샘플링을 수행할 기간 창이에요. 기본값: 1s(비활성).

  • first는 각 간격에서 주어진 레벨과 메시지에 대해 유지할 로그 수예요. 기본값: 100.

  • thereafter는 유지된 첫 로그 이후 각 간격에서 건너뛸 로그 수예요. 기본값: 100.

    예를 들어 interval 1s, first 5, thereafter 10이면 각 초마다 첫 5개 로그 항목이 유지되고, 그 후 그 초 안에서 같은 레벨·메시지의 로그 항목 10개마다 하나씩 통과시켜요.

hostnames를 제외하고 각 하위 지시문은 log 블록당 한 번만 지정할 수 있어요(각 sampling 옵션은 sampling 블록당 한 번). 반복하면 에러예요.

출력 모듈 (Output modules)

output 하위 지시문은 로그가 어디에 쓰이는지 커스터마이즈할 수 있게 해줘요.

stderr

표준 에러(콘솔. 기본값).

output stderr

stdout

표준 출력(콘솔).

output stdout

discard

출력 없음.

output discard

file

파일. 기본적으로 로그 파일은 디스크 공간 고갈을 막기 위해 크기에 따라 회전("roll")돼요.

로그 회전은 timberjack이 제공해요.

로그 파일 옵션 재로딩에 대한 참고: 주어진 출력 파일에 대한 설정 변경을 적용하려면 서버 재시작이 필요해요. 새 로그 파일 이름을 추가하지 않는 한 변경 사항은 서버 재로드 시 적용되지 않아요. 로그 파일 옵션을 재로드할 때는 이 점을 유의해요.

output file <filename> {
	mode          <mode>
	roll_disabled
	roll_size     <size>
	roll_interval <duration>
	roll_minutes  <minutes...>
	roll_at	      <times...>
	roll_uncompressed
	roll_local_time
	roll_keep     <num>
	roll_keep_for <days>
	backup_time_format <format>
}
  • ****은 로그 파일의 경로예요.

    회전되면 파일은 <name>-<timestamp>-<reason>.log 템플릿으로 이름이 바뀌어요. 타임스탬프는 backup_time_format 옵션에 따라 형식화돼요. reason은 회전을 트리거한 것이 크기면 size, 시간이면 time이에요. 파일이 압축되면 파일 이름에 .gz가 붙어요.

    예를 들어 파일 이름이 access.log라면 크기로 회전된 경우 access-2026-01-30T22-15-42.123-size.log, 시간으로 회전된 경우 access-2025-01-30T00-00-00.000-time.log처럼 이름이 붙을 수 있어요.

  • mode는 로그 파일에 사용할 유닉스 파일 모드/권한이에요. 모드는 1~4자리 8진수로 구성돼요(유닉스 chmod 명령이 받는 숫자 형식과 같지만, 모두 0인 모드는 기본 모드 600으로 해석돼요).

    예를 들어 0600은 rw-,---,---(로그 파일 소유자에게 읽기/쓰기, 다른 사람은 접근 불가), 0640은 rw-,r--,---(파일 소유자에게 읽기/쓰기, 그룹에겐 읽기만), 644는 rw-,r--,r--(로그 파일 소유자에게 읽기/쓰기, 그룹 소유자와 다른 사용자에겐 읽기만)로 설정해요.

  • roll_disabled는 로그 회전을 비활성화해요. 디스크 공간 고갈로 이어질 수 있으므로, 로그 파일을 다른 방식으로 관리하는 경우에만 사용해요.

  • roll_size는 로그 파일을 회전할 크기예요. 현재 구현은 메가바이트 해상도를 지원하며, 소수 값은 다음 정수 메가바이트로 올림돼요. 예를 들어 1.1MiB는 2MiB로 올림돼요.

    항상 활성화돼 있어요. 로그에 대한 쓰기가 지정된 크기를 초과하면 로그가 즉시 회전돼요. 백업 파일 이름에는 reason으로 size가 포함돼요.

    기본값: 100MiB

  • roll_interval은 로그 회전 사이의 최대 기간이에요. 값은 회전 후 로그 파일을 회전할 기간 문자열이에요. 예: 12h 또는 1d.

    활성화되면 마지막 회전 이후 이 기간이 지난 후 로그에 대한 다음 쓰기에서 파일이 회전돼요. 백업 파일 이름에는 reason으로 time이 포함돼요.

    24h로 설정해도 반드시 자정에 회전하는 것은 아니고, 마지막 회전 후 24시간 지점에서 회전한다는 점에 주의해요. 크기 때문에 회전하면 다음 회전 시간이 이전 회전과 어긋날 수 있어요. 특정 시간에 회전하려면 roll_at이나 roll_minutes 옵션을 사용할 수 있어요.

    기본값: 비활성

  • roll_minutes는 로그 파일을 회전할 분 값(0-59) 목록이에요. 예를 들어 10 40은 매시간 xx:10과 xx:40에 30분마다 로그 파일을 회전해요. 회전은 시계의 분(초 0)에 맞춰져요.

    활성화하면 지정된 분 값에서 로그 회전을 트리거하는 goroutine 타이머가 생겨요(즉 약간의 백그라운드 처리가 추가돼요). roll_interval과 roll_size에 추가로 동작해요. 백업 파일 이름에는 reason으로 time이 포함돼요.

    기본값: 비활성

  • roll_at은 로그 파일을 회전할 시간 값(24시간 형식) 목록이에요. 예를 들어 00:00 12:00은 자정과 정오에 하루 두 번 로그 파일을 회전해요. 회전은 시계의 분(초 0)에 맞춰져요.

    활성화하면 지정된 시간에 로그 회전을 트리거하는 goroutine 타이머가 생겨요(즉 약간의 백그라운드 처리가 추가돼요). roll_interval과 roll_size에 추가로 동작해요. 백업 파일 이름에는 reason으로 time이 포함돼요.

    기본값: 비활성

  • roll_uncompressed는 gzip 로그 압축을 끄요.

    기본값: gzip 압축이 활성화됨.

  • roll_local_time은 파일 이름에 로컬 타임스탬프를 사용하도록 회전을 설정해요.

    기본값: UTC 시간 사용.

  • roll_keep은 가장 오래된 로그 파일을 삭제하기 전에 유지할 로그 파일 수예요. 새 로그 파일이 생성될 때 트리거돼요.

    이 옵션과 roll_keep_for가 함께 어떤 로그 파일을 유지할지 결정한다는 점을 알아두세요. 예를 들어 로그 파일을 매일 회전한다면, roll_keep_for 설정과 무관하게 기본 roll_keep 값 10에 따라 10개만 유지돼요. roll_keep을 비활성화하려면 값을 -1로 설정해요. 값 0은 설정하지 않은 것과 같게 취급되어 기본 10으로 폴백돼요. roll_keep을 roll_keep_for와 함께 비활성화하는 것은 권장하지 않아요. 모든 로그 파일이 유지되어 저장 공간이 가득 찰 수 있기 때문이에요.

    기본값: 10

  • roll_keep_for는 기간 문자열로 회전된 파일을 얼마나 오래 유지할지예요. 새 로그 파일이 생성될 때 트리거돼요. 현재 구현은 일(day) 해상도를 지원하며, 소수 값은 다음 정수 일로 올림돼요. 예를 들어 36h(1.5일)는 48h(2일)로 올림돼요.

    이 옵션과 roll_keep이 함께 어떤 로그 파일을 유지할지 결정한다는 점을 알아두세요. 예를 들어 로그 파일을 드물게 회전한다면, roll_keep 설정과 무관하게 roll_keep_for 기본값인 90일보다 오래된 파일만 유지돼요. roll_keep_for를 비활성화하려면 값을 0으로 설정해요. roll_keep과 roll_keep_for를 모두 0으로 설정하는 것은 권장하지 않아요. 모든 로그 파일이 유지되어 저장 공간이 가득 찰 수 있기 때문이에요.

    기본값: 2160h(90일)

  • backup_time_format은 백업 파일 이름에 사용할 시간 형식이에요. 유효한 time layout 문자열이어야 해요. 자세한 내용은 Go 문서를 참고해요.

    기본값: 2006-01-02T15-04-05

net

네트워크 소켓. 소켓이 다운되면 재연결을 시도하는 동안 로그를 stderr로 덤프해요.

output net <address> {
	dial_timeout <duration>
	soft_start
}
  • **

    **는 로그를 쓸 주소예요.

  • dial_timeout은 로그 소켓에 연결 성공을 기다리는 시간이에요. 소켓이 다운되면 로그 발행이 이 시간만큼 차단될 수 있어요.

  • soft_start는 소켓 연결 오류를 무시해서, 원격 로그 서비스가 다운돼도 config를 로드할 수 있게 해줘요. 로그는 대신 stderr로 발행돼요.

형식 모듈 (Format modules)

format 하위 지시문은 로그를 어떻게 인코딩(형식화)할지 커스터마이즈할 수 있게 해줘요. log 블록 안에 나타나요.

Common Log Format(CLF)에 대한 참고: CLF는 현대 구조화 로그와 충돌해요. 액세스 로그를 더 이상 쓰이지 않는 Common Log Format으로 변환하려면 transform-encoder 플러그인을 사용해요.

각 개별 인코더의 문법에 더해, 대부분의 인코더에 다음 공통 속성을 설정할 수 있어요:

format <encoder_module> {
	message_key     <key>
	level_key       <key>
	time_key        <key>
	name_key        <key>
	caller_key      <key>
	stacktrace_key  <key>
	line_ending     <char>
	time_format     <format>
	time_local
	duration_format <format>
	level_format    <format>
}
  • message_key는 로그 항목의 메시지 필드 키예요. 기본값: msg

  • level_key는 로그 항목의 레벨 필드 키예요. 기본값: level

  • time_key는 로그 항목의 시간 필드 키예요. 기본값: ts

  • name_key는 로그 항목의 이름 필드 키예요. 기본값: name

  • caller_key는 로그 항목의 caller 필드 키예요.

  • stacktrace_key는 로그 항목의 stacktrace 필드 키예요.

  • line_ending은 사용할 줄 끝 문자예요.

  • time_format은 타임스탬프 형식이에요.

    기본값: 형식이 console로 기본 설정되면 wall_milli, 그 외 unix_seconds_float.

    다음 중 하나일 수 있어요:

    • unix_seconds_float — Unix epoch 이후 초의 부동소수점 수.

    • unix_milli_float — Unix epoch 이후 밀리초의 부동소수점 수.

    • unix_nano — Unix epoch 이후 나노초의 정수.

    • iso8601 — 예: 2006-01-02T15:04:05.000Z0700

    • rfc3339 — 예: 2006-01-02T15:04:05Z07:00

    • rfc3339_nano — 예: 2006-01-02T15:04:05.999999999Z07:00

    • wall — 예: 2006/01/02 15:04:05

    • wall_milli — 예: 2006/01/02 15:04:05.000

    • wall_nano — 예: 2006/01/02 15:04:05.000000000

    • common_log — 예: 02/Jan/2006:15:04:05 -0700

    • 또는 호환되는 임의의 time layout 문자열. 자세한 내용은 Go 문서를 참고해요.

    형식 문자열의 부분은 레이아웃의 특수 상수라는 점에 주의해요. 2006은 연도, 01은 월, Jan은 문자열 월, 02는 일이에요. 실제 현재 날짜 숫자를 형식 문자열에 사용하지 마세요.

  • time_local은 기본 UTC 시간 대신 로컬 시스템 시간으로 로깅해요.

  • duration_format은 기간 형식이에요.

    기본값: seconds.

    다음 중 하나일 수 있어요:

    • s, second 또는 seconds — 경과 초의 부동소수점 수.

    • ms, milli 또는 millis — 경과 밀리초의 부동소수점 수.

    • ns, nano 또는 nanos — 경과 나노초의 정수.

    • string — Go의 내장 문자열 형식 사용. 예: 1m32.05s 또는 6.31ms.

  • level_format은 레벨 형식이에요.

    기본값: 형식이 console로 기본 설정되면 color, 그 외 lower.

    다음 중 하나일 수 있어요:

    • lower — 소문자.

    • upper — 대문자.

    • color — ANSI 색상이 있는 대문자.

console

console 인코더는 일부 구조를 유지하면서 로그 항목을 사람이 읽기 좋게 형식화해요.

format console

json

각 로그 항목을 JSON 객체로 형식화해요.

format json

filter

필드별 필터링을 허용해요.

format filter {
	fields {
		<field> <filter> ...
	}
	<field> <filter> ...
	wrap <encode_module> ...
}

중첩 필드는 >로 한 계층의 중첩을 나타내 참조할 수 있어요. 즉 {"a":{"b":0}} 같은 객체에서 내부 필드는 a>b로 참조할 수 있어요.

ts, level, logger, msg 필드는 기본 로깅 라이브러리가 특수 케이스로 추가하기 때문에 필터링할 수 없는 로그의 기본 필드예요.

wrap 지정은 선택적이에요. 생략하면 현재 출력 모듈이 stderr 또는 stdout이고 대화형 터미널이면 기본이 선택되는데, 그 경우 console이 선택되고 그 외엔 json이 선택돼요.

단축으로 fields 블록을 생략하고 filter 블록 안에 바로 필터를 지정할 수 있어요.

사용 가능한 필터는 다음과 같아요:

delete

인코딩에서 건너뛸 필드를 표시해요.

<field> delete
rename

로그 필드의 키 이름을 바꿔요.

<field> rename <key>
replace

인코딩 시점에 제공된 문자열로 대체할 필드를 표시해요.

<field> replace <replacement>
ip_mask

CIDR 마스크로 필드의 IP 주소를 마스킹해요. 즉 IP에서 유지할 비트 수로, 왼쪽부터 시작해요. 필드가 문자열 배열(예: HTTP 헤더)이면 배열의 각 값이 마스킹돼요. 값은 쉼표로 구분된 IP 주소 문자열일 수 있어요.

IPv4와 IPv6는 총 비트 수가 다르므로 별도 설정이 있어요.

가장 흔히 필터링할 필드는:

  • 직접 연결하는 클라이언트의 request>remote_ip

  • trusted_proxies가 설정될 때 파싱된 "실제 클라이언트"의 request>client_ip

  • 리버스 프록시 뒤라면 request>headers>X-Forwarded-For

<field> ip_mask [<ipv4> [<ipv6>]] {
	ipv4 <cidr>
	ipv6 <cidr>
}
query

URL 필드의 쿼리 부분을 조작하기 위해 하나 이상의 동작을 수행할 필드를 표시해요. 가장 흔히 필터링할 필드는 request>uri예요.

<field> query {
	delete  <key>
	replace <key> <replacement>
	hash    <key>
}

사용 가능한 동작:

  • delete는 쿼리에서 주어진 키를 제거해요.

  • replace는 주어진 쿼리 키의 값을 replacement로 바꿔요. 편집 표시 placeholder를 삽입하는 데 유용해요. 쿼리 키가 URL에 있었다는 건 보이지만 값은 숨겨져요.

  • hash는 주어진 쿼리 키의 값을 값의 SHA-256 해시의 첫 4바이트(소문자 16진수)로 바꿔요. 값이 민감할 때 값을 숨기면서도 각 요청의 값이 달랐는지 알아차릴 수 있게 해줘요.

Cookie HTTP 헤더의 값을 조작하기 위해 하나 이상의 동작을 수행할 필드를 표시해요. 가장 흔히 필터링할 필드는 request>headers>Cookie예요.

<field> cookie {
	delete  <name>
	replace <name> <replacement>
	hash    <name>
}

사용 가능한 동작:

  • delete는 이름으로 주어진 쿠키를 헤더에서 제거해요.

  • replace는 주어진 쿠키의 값을 replacement로 바꿔요. 편집 표시 placeholder를 삽입하는 데 유용해요. 쿠키가 헤더에 있었다는 건 보이지만 값은 숨겨져요.

  • hash는 주어진 쿠키의 값을 값의 SHA-256 해시의 첫 4바이트(소문자 16진수)로 바꿔요. 값이 민감할 때 값을 숨기면서도 각 요청의 값이 달랐는지 알아차릴 수 있게 해줘요.

같은 쿠키 이름에 여러 동작이 정의되면 첫 동작만 적용돼요.

set_cookie

Set-Cookie HTTP 응답 헤더의 값을 조작하기 위해 하나 이상의 동작을 수행할 필드를 표시해요. 가장 흔히 필터링할 필드는 resp_headers>Set-Cookie예요.

<field> set_cookie {
	delete  <name>
	replace <name> <replacement>
	hash    <name>
}

사용 가능한 동작:

  • delete는 주어진 쿠키 이름의 Set-Cookie 헤더 값을 제거해요.

  • replace는 주어진 쿠키의 값을 replacement로 바꾸면서, 쿠키의 속성(예: Path, Expires, HttpOnly)은 그대로 유지해요.

  • hash는 주어진 쿠키의 값을 값의 SHA-256 해시의 첫 4바이트(소문자 16진수)로 바꾸면서, 쿠키의 속성은 그대로 유지해요.

같은 쿠키 이름에 여러 동작이 정의되면 첫 동작만 적용돼요. 파싱할 수 없는 Set-Cookie 값은 변경 없이 기록돼요.

regexp

인코딩 시점에 정규 표현식 치환을 적용할 필드를 표시해요. 필드가 문자열 배열(예: HTTP 헤더)이면 배열의 각 값에 치환이 적용돼요.

<field> regexp <pattern> <replacement>

사용되는 정규 표현식 언어는 RE2로, Go에 포함돼 있어요. RE2 문법 참조와 Go regexp 문법 개요를 참고해요.

치환 문자열에서 ${group}으로 캡처 그룹을 참조할 수 있어요. 여기서 group은 표현식의 캡처 그룹 이름 또는 숫자예요. 캡처 그룹 0은 전체 정규식 일치, 1은 첫 번째 캡처 그룹, 2는 두 번째 캡처 그룹 등이에요.

hash

인코딩 시점에 값의 SHA-256 해시의 첫 4바이트(8개 16진 문자)로 대체할 필드를 표시해요. 필드가 문자열 배열(예: HTTP 헤더)이면 배열의 각 값이 해시돼요.

값이 민감할 때 값을 숨기면서도 각 요청의 값이 달랐는지 알아차릴 수 있게 해줘요.

<field> hash

append

모든 로그 항목에 필드를 추가해요.

format append {
	fields {
		<field> <value>
	}
	<field> <value>
	wrap <encode_module> ...
}

로그 항목을 생성하는 Caddy 인스턴스에 대한 정보, 가능하면 환경 변수로 추가하는 데 가장 유용해요. 필드 값은 전역 placeholder(예: {env.*})일 수 있지만, 로그가 HTTP 요청 컨텍스트 밖에서 기록되므로 요청별 placeholder는 쓸 수 없어요.

wrap 지정은 선택적이에요. 생략하면 현재 출력 모듈이 stderr 또는 stdout이고 대화형 터미널이면 기본이 선택되는데, 그 경우 console이 선택되고 그 외엔 json이 선택돼요.

fields 블록을 생략하고 append 블록 안에 바로 필드를 지정할 수 있어요.

예시 (Examples)

기본 로거에 액세스 로깅을 활성화해요.

즉 기본적으로 stderr로 로깅하지만, log 글로벌 옵션으로 default 로거를 재구성해 바꿀 수 있어요:

example.com {
	log
}

파일에 로그를 써요(기본으로 활성화된 로그 회전 포함):

example.com {
	log {
		output file /var/log/access.log
	}
}

로그 회전을 커스터마이즈해요. 자정 또는 로그 파일이 1GB에 도달하는 것 중 먼저 오는 때에 매일 회전하고, 회전된 파일 5개 또는 30일 치 로그를 유지해요:

example.com {
	log {
		output file /var/log/access.log {
			roll_at 00:00
			roll_size 1gb
			roll_keep 5
			roll_keep_for 720h
		}
	}
}

로그에서 User-Agent 요청 헤더를 삭제해요:

example.com {
	log {
		format filter {
			request>headers>User-Agent delete
		}
	}
}

여러 민감한 쿠키를 편집해요. (기본적으로 일부 민감한 헤더는 빈 값으로 기록된다는 점에 주의해요. Cookie 헤더 값 로깅을 활성화하려면 log_credentials 글로벌 옵션을 참고해요):

example.com {
	log {
		format filter {
			request>headers>Cookie cookie {
				replace session REDACTED
				delete secret
			}
		}
	}
}

마찬가지로 백엔드가 설정한 세션 쿠키의 값을 해시하면서 속성은 유지해요(Set-Cookie 헤더 값을 로깅하려면 log_credentials 글로벌 옵션도 필요해요):

example.com {
	log {
		format filter {
			resp_headers>Set-Cookie set_cookie {
				hash session
			}
		}
	}
}

요청에서 원격 주소를 마스킹해요. IPv4 주소는 처음 16비트(즉 255.255.0.0), IPv6 주소는 처음 32비트를 유지해요.

참고로 Caddy v2.7부터 remote_ip와 client_ip가 모두 기록되는데, trusted_proxies가 설정되면 client_ip가 "실제 IP"예요:

example.com {
	log {
		format filter {
			request>remote_ip ip_mask 16 32
			request>client_ip ip_mask 16 32
		}
	}
}

환경 변수에서 서버 ID를 모든 로그 항목에 추가하고, filter와 연결해 헤더를 삭제해요:

example.com {
	log {
		format append {
			server_id {env.SERVER_ID}
			wrap filter {
				request>headers>Cookie delete
			}
		}
	}
}

와일드카드 사이트 블록에서 각 로거의 hostnames를 재정의해 서브도메인별로 별도의 로그 파일을 써요. 반복을 피하기 위해 스니펫을 사용해요:

(subdomain-log) {
	log {
		hostnames {args[0]}
		output file /var/log/{args[0]}.log
	}
}

*.example.com {
	import subdomain-log foo.example.com
	@foo host foo.example.com
	handle @foo {
		respond "foo"
	}

	import subdomain-log bar.example.com
	@bar host bar.example.com
	handle @bar {
		respond "bar"
	}
}

특정 서브도메인의 액세스 로그를 서로 다른 형식으로 두 파일에 써요(하나는 transform-encoder 플러그인, 다른 하나는 json).

이것은 사이트 블록에서 로거 이름을 foo로 재정의한 다음, 전역 옵션의 두 로거에서 include http.log.access.foo로 그 로거가 생성한 액세스 로그를 포함하는 방식으로 동작해요:

{
	log access-formatted {
		include http.log.access.foo
		output file /var/log/access-foo.log
		format transform "{common_log}"
	}

	log access-json {
		include http.log.access.foo
		output file /var/log/access-foo.json
		format json
	}
}

foo.example.com {
	log foo
}

샘플링으로 로그 양을 줄이려면, 예를 들어 초당 처음 5개 요청을 유지하고 그 후 10개 중 1개를 유지해요:

example.com {
	log {
		sampling {
			interval   1s
			first      5
			thereafter 10
		}
	}
}

더 알아보기 (Learn more)