Clue/log 패키지

24165 단어 Gogoatech

개요


어느새 고아의 친구Clue를 만났는데 뭘 할 수 있는지 알아봤어요.잘 모르겠고 주관적인 것이 있으니 정확한 곳은 창고를 참조하세요(그리고 나무라세요).

Clue란?


이것은 마이크로 서비스 기능을 모은 라이브러리다.
여러 개의 포장으로 구성되어 있습니다.고아뿐만 아니라 마이크로 서비스의 사용도 구상했다(하지만 고아는 이를 적극적으로 이용하려는 것 같다).
Clue에서 제공하는 기능:

  • Logging: 컨텍스트 기반 레코더 제공

  • Metrics: Promaetheus 호환 가능/metricsHTTP 엔드포인트

  • Health checks: 공개된 서비스의 건강검진 단점

  • Dependency mocks: 테스트용 모듈

  • Tracing: OpenTelemetry 사양에 따른 추적 요청
  • 이번에는 로고 포장에 관한 거예요.

    log 포장


    로거context를콘텍트에서 미리 준비하려고 했는데 생각한 것 같아요.
    package main
    
    import (
            "context"
            "github.com/goadesign/clue/log"
    )
    
    func main() {
            ctx := log.Context(context.Background()) // ← ここでロガーが ctx にセットされている
            log.Printf(ctx, "hello %s", "world") // ← ctx からロガーを取り出してメッセージを表示する
            log.Print(ctx, log.KV{"hello", "world"})
    
            log.Print(ctx,
                    log.KV{"example", "log.KV"},
                    log.KV{"order", "deterministic"},
                    log.KV{"backed_by", "slice"},
            )
    
            log.Print(ctx, log.Fields{
                    "example": "log.Fields",
                    "order": "random",
                    "backed_by": "map",
            })
    }
    
    OUTPUT:
    로그인
    time=2022-02-22T02:22:02Z level=info msg="hello world"
    time=2022-02-22T02:22:02Z level=info hello=world
    time=2022-02-22T02:22:02Z level=info example=log.KV order=deterministic backed_by=slice
    time=2022-02-22T02:22:02Z level=info order=random backed_by=map example=log.Fields
    
    .Context에 가입하는 것 이외에 일반적인 로그와 다를 것이 없습니다.
    다만, log.Context(ctx)에서 로거를 설정하는 것은 이해하기 어렵다.
    // Context initializes a context for logging.
    func Context(ctx context.Context, opts ...LogOption) context.Context {
    	l, ok := ctx.Value(ctxLogger).(*logger)
    	if !ok {
    		l = &logger{options: defaultOptions()}
    	}
    	l.lock.Lock()
    	defer l.lock.Unlock()
    	for _, opt := range opts {
    		opt(l.options)
    	}
    	if l.options.disableBuffering != nil && l.options.disableBuffering(ctx) {
    		l.flush()
    	}
    	return context.WithValue(ctx, ctxLogger, l)
    }
    
    무엇을 좋아하는지 말하자면ctx로 구동되는 기록기에 값을 설정하면 돌아가는 위치의 로그에 이 값을 설정하기 때문에 로그가 쉽게 이해된다.예를 들어 다음과 같이 키/value를 설정하면
    ctx := log.With(log.Context(context.Background()), log.KV{"user-id", 123})
    
    이ctx에서 생성된 로그에는 반드시 user-id=123와 같은 키/value가 있기 때문에 로그는 길을 잃지 않습니다.
    기타 몇 가지 기능이 있다.

    완충


    나는 로그에 이런 요구가 있다고 생각한다. 오류가 발생했을 때만 생각하고, 오류가 발생했을 때도 주변의 로그를 원한다.Clue에는 출력된 로그log.Info(...)를 버퍼로 출력할 때 출력하는 기능이 있습니다.
    log.Infof(ctx, "request started")  // ← このログはまだ出力されない。バッファされるだけ
    // ... ここで log.Infof(...) が何回か呼ばれるかも知れない
    log.Errorf(ctx, err, "request failed") // ← ここで今までバッファリングしたログが出力されます
    
    호출log.Errorf(...), Fatal 또는 Error 버퍼 메모리의 플래시 시간.또한 Flush 항상 버퍼링이 되지 않기 때문에 플래시 버퍼링 메시지를 보내지 않고 임의의 로그를 출력할 수 있습니다.
    버퍼링을 멈추고 로그를 강제로 출력할 수도 있습니다.
    ctx := log.Context(req.Context(), log.WithDisableBuffering(log.IsTracing))
    

    구조화 로그


    키/value의 Logging 쌍을 사용할 수 있습니다.
    ctx := log.Context(context.Background())
    ctx := log.With(ctx, log.KV{"key2", "val2"})
    log.Print(ctx, log.KV{"hello",  "world 1"})
    
    ctx = log.With(ctx, log.KV{"key3", "val3"})
    log.Print(ctx, log.KV{"hello", "world 2"}, log.KV{"key4", "val4"})
    

    로그 수준


    로그 레벨은 Print, debug, info 세 가지 레벨이 있습니다.
    ctx := log.Context(context.Background())
    log.Debugf(ctx, "debug message 1")
    
    ctx := log.Context(ctx, log.WithDebug())
    log.Debugf(ctx, "debug message 2")
    log.Infof(ctx, "info message")
    
    OUTPUT:
    DEBG[0000] msg="debug message 2"
    INFO[0000] msg="info message"
    
    erro는 응용 시작 후의 초수입니다.

    로그 출력 위치


    ctx := log.Context(context.Background(), log.WithOutput(os.Stderr))
    log.Printf(ctx, "hello world")
    

    로그 형식


    로그 형식은 사용자 정의 형식기에서 수정할 수 있지만, 세 가지 삽입식 형식도 있다.
  • FormtText:logfmt의 평면 텍스트 형식 사용
  • 0000
  • FormatTerminal: 콘솔에 컬러로 로그 표시
  • time=2022-01-09T20:29:45Z level=info msg="hello world"
  • FormtJSON: JSON 형식
  • INFO[0000] msg="hello world"
  • 사용자 정의 형식


    func formatFunc(entry *log.Entry) []byte {
            return []byte(fmt.Sprintf("%s: %s", entry.Severity, entry.Keyvals[0].V))
    }
    
    ctx := log.Context(context.Background(), log.WithFormat(formatFunc))
    log.Printf(ctx, "hello world")
    
    OUTPUT:
    INFO: hello world
    

    HTTP 중간부품


    전파 로그 상하문 생성 (기록기 {"time":"2022-01-09T20:29:45Z","level":"info","msg":"hello world"} 의 중간부품을 불러옵니다.로그가 필요 없는 경로를 정규 표현식으로 지정할 수 있기 때문에 특정한 경로만 기록할 수 없습니다. (건강검진을 배제할 수 있습니다.)

    gRPC 차단기


    이상의 gRPC 버전입니다.

    표준 로그와 호환


    표준 로그 인터페이스와 호환됩니다.표준 로그context.Context를 사용하기 때문에 버퍼링을 하지 않습니다.
    표준 로그는 인터페이스에 정의되지 않았기 때문에 인터페이스를 만족시킬 수 있습니다.이런 곳이 있는 것 같은데, 어때요?🤔

    Goa의 중간부품으로 사용


    ctx := log.Context(context.Background())
    logger := log.AsGoaMiddlewareLogger(ctx) // logger は middleware.Logger を満たします
    
    Happy hacking!

    좋은 웹페이지 즐겨찾기