Skip to content

훅 시스템

DD 는 이벤트 기반의 훅 시스템을 제공하여 로그 라이프사이클의 핵심 시점에 커스텀 로직을 삽입할 수 있습니다.

훅 이벤트

상수String()트리거 시점
HookBeforeLog"BeforeLog"로그 쓰기 전
HookAfterLog"AfterLog"로그 쓰기 후
HookOnFilter"OnFilter"민감 데이터 필터링 시
HookOnRotate"OnRotate"파일 로테이션 시
HookOnClose"OnClose"로거 종료 시
HookOnError"OnError"오류 발생 시

훅 함수 타입

Hook

go
type Hook func(ctx context.Context, hookCtx *HookContext) error

훅 함수 시그니처. 로그 라이프사이클 이벤트 트리거 시 호출됩니다.

  • BeforeLog 훅이 오류를 반환하면 로그 항목이 기록되지 않습니다.
  • 다른 이벤트에서 반환된 오류는 기본적으로 이후 훅 실행을 중단시킵니다. 오류 핸들러 (아래 HookErrorHandler 참조) 를 설정한 경우에는 오류를 핸들러로 넘기고, 모든 훅이 여전히 실행됩니다.
  • 훅 내부에서 발생한 panic 은 HookRegistry가 잡아서 오류로 변환하여 애플리케이션 전체가 다운되는 것을 방지합니다.

HookErrorHandler

go
type HookErrorHandler func(event HookEvent, hookCtx *HookContext, err error)

훅 오류 핸들러 시그니처.

매개변수:

  • event: 오류를 트리거한 훅 이벤트 타입
  • hookCtx: 훅에 전달된 컨텍스트
  • err: 훅이 반환한 (또는 panic 에서 변환된) 오류

오류 핸들러를 설정 (HookRegistry.SetErrorHandler 또는 HooksConfig.ErrorHandler 경유) 하면, Trigger는 모든 훅을 실행하고 오류가 발생해도 곧바로 중단하지 않습니다. 각 오류는 핸들러에 전달됩니다. 예외: BeforeLog 이벤트는 핸들러를 설정해도 반환된 오류가 여전히 로그 쓰기를 차단합니다. 핸들러 내부에서 panic 을 일으키면 안 되며, 발생할 경우 복구되어 stderr 로 출력됩니다.

HookRegistry

훅 레지스트리로, 모든 훅의 등록과 트리거를 관리합니다. 스레드 안전.

생성

go
// 빈 레지스트리
reg := dd.NewHookRegistry()

// 구성에서 생성
reg := dd.NewHooksFromConfig(hooksConfig)

메서드

메서드시그니처설명
Add(event HookEvent, hook Hook)훅 등록
Remove(event HookEvent)이벤트의 모든 훅 제거
Trigger(ctx, event, hookCtx) error이벤트의 모든 훅 트리거
Clear()모든 훅 제거
ClearFor(event HookEvent)지정 이벤트의 훅 제거
SetErrorHandler(handler HookErrorHandler)오류 핸들러 설정

훅 등록

go
reg := dd.NewHookRegistry()

// BeforeLog 훅
reg.Add(dd.HookBeforeLog, func(ctx context.Context, hc *dd.HookContext) error {
    fmt.Println("로그 쓰기 직전:", hc.Message)
    return nil
})

// AfterLog 훅
reg.Add(dd.HookAfterLog, func(ctx context.Context, hc *dd.HookContext) error {
    metrics.LogCount.Inc()
    return nil
})

// OnRotate 훅
reg.Add(dd.HookOnRotate, func(ctx context.Context, hc *dd.HookContext) error {
    dd.InfoWith("파일 로테이션 완료",
        dd.String("path", hc.Metadata["path"].(string)),
    )
    return nil
})

Logger 로 관리

go
// 단일 훅 추가
_ = logger.AddHook(dd.HookBeforeLog, myHook)

// 전체 레지스트리 교체
_ = logger.SetHooks(reg)

// 현재 레지스트리 가져오기
hooks := logger.GetHooks()

HookContext

훅 컨텍스트로, 이벤트 발생 시의 상세 정보를 제공합니다.

go
type HookContext struct {
    Event          HookEvent      // 이벤트 타입
    Level          LogLevel       // 로그 레벨
    Message        string         // 로그 메시지
    Fields         []Field        // 구조화 필드 (필터 후)
    OriginalFields []Field        // 원본 필드 (필터 전)
    Error          error          // 오류 정보 (OnError 이벤트)
    Timestamp      time.Time      // 이벤트 시간
    Writer         io.Writer      // 대상 Writer(쓰기 관련 이벤트)
    Metadata       map[string]any // 추가 메타데이터
}

HooksConfig

구조화 훅 구성으로, 일괄 훅 등록에 권장됩니다.

go
type HooksConfig struct {
    BeforeLog    []Hook              // 로그 쓰기 전 훅
    AfterLog     []Hook              // 로그 쓰기 후 훅
    OnFilter     []Hook              // 민감 데이터 필터링 시 훅
    OnRotate     []Hook              // 파일 로테이션 시 훅
    OnClose      []Hook              // 로거 종료 시 훅
    OnError      []Hook              // 쓰기 오류 시 훅
    ErrorHandler HookErrorHandler    // 오류 핸들러
}
go
cfg := dd.HooksConfig{
    BeforeLog: []dd.Hook{func(ctx context.Context, hc *dd.HookContext) error {
        // 로그 전 처리
        return nil
    }},
    AfterLog: []dd.Hook{func(ctx context.Context, hc *dd.HookContext) error {
        metrics.LogCount.Inc()
        return nil
    }},
    ErrorHandler: func(event dd.HookEvent, hc *dd.HookContext, err error) {
        log.Printf("훅 오류: %v\n", err)
    },
}
registry := dd.NewHooksFromConfig(cfg)

전체 예

메트릭 수집

go
reg := dd.NewHookRegistry()
reg.Add(dd.HookAfterLog, func(ctx context.Context, hc *dd.HookContext) error {
    logCount.Inc()
    logLevelCounter.WithLabelValues(hc.Level.String()).Inc()
    return nil
})
reg.Add(dd.HookOnError, func(ctx context.Context, hc *dd.HookContext) error {
    errorCount.Inc()
    return nil
})
_ = logger.SetHooks(reg)

다음 단계