golang의 zap의 WriteSyncer에 대해서 얘기를 나눠보도록 하겠습니다.
8019 단어 golang
순서
본고는 주로 golang의 zap의 WriteSyncer를 연구하고자 합니다.
WriteSyncer
[email protected]/zapcore/write_syncer.go
type WriteSyncer interface {
io.Writer
Sync() error
}
WriteSyncer에 io가 내장되어 있습니다.Writer 인터페이스, Sync 방법 정의
Writer
/usr/local/go/src/io/io.go
type Writer interface {
Write(p []byte) (n int, err error)
}
Writer 인터페이스는 Write 메서드를 정의합니다.
lockedWriteSyncer
[email protected]/zapcore/write_syncer.go
type lockedWriteSyncer struct {
sync.Mutex
ws WriteSyncer
}
func Lock(ws WriteSyncer) WriteSyncer {
if _, ok := ws.(*lockedWriteSyncer); ok {
// no need to layer on another lock
return ws
}
return &lockedWriteSyncer{ws: ws}
}
func (s *lockedWriteSyncer) Write(bs []byte) (int, error) {
s.Lock()
n, err := s.ws.Write(bs)
s.Unlock()
return n, err
}
func (s *lockedWriteSyncer) Sync() error {
s.Lock()
err := s.ws.Sync()
s.Unlock()
return err
}
lockedWriteSyncer는 동기화를 정의합니다.Mutex와 WriteSyncer 속성은 WriteSyncer 인터페이스를 실현했고 Write와 Sync 방법에 모두 자물쇠를 달았으며 내부에 의뢰한 WriteSyncer;Lock 메서드는 lockedWriteSyncer를 만드는 데 사용됩니다.
multiWriteSyncer
[email protected]/zapcore/write_syncer.go
type multiWriteSyncer []WriteSyncer
func NewMultiWriteSyncer(ws ...WriteSyncer) WriteSyncer {
if len(ws) == 1 {
return ws[0]
}
// Copy to protect against https://github.com/golang/go/issues/7809
return multiWriteSyncer(append([]WriteSyncer(nil), ws...))
}
func (ws multiWriteSyncer) Write(p []byte) (int, error) {
var writeErr error
nWritten := 0
for _, w := range ws {
n, err := w.Write(p)
writeErr = multierr.Append(writeErr, err)
if nWritten == 0 && n != 0 {
nWritten = n
} else if n < nWritten {
nWritten = n
}
}
return nWritten, writeErr
}
func (ws multiWriteSyncer) Sync() error {
var err error
for _, w := range ws {
err = multierr.Append(err, w.Sync())
}
return err
}
multiWriteSyncer는
[]WriteSyncer
유형은 WriteSyncer 인터페이스를 실현하고 그 Write 방법은 multiWriteSyncer에서 하나씩 w.Write를 실행하고 multierr를 사용합니다.Append(writeErr,err)로 err를 포장합니다.그 Sync 방법은 multiWriteSyncer를 훑어보고 하나씩 w.Sync () 를 실행하고 multierr를 사용합니다.Append(writeErr,err)로 err를 포장합니다.NewMultiWriteSyncer 메서드는 multiWriteSyncer를 만드는 데 사용됩니다.CombineWriteSyncers
[email protected]/writer.go
func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer {
if len(writers) == 0 {
return zapcore.AddSync(ioutil.Discard)
}
return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...))
}
func Open(paths ...string) (zapcore.WriteSyncer, func(), error) {
writers, close, err := open(paths)
if err != nil {
return nil, nil, err
}
writer := CombineWriteSyncers(writers...)
return writer, close, nil
}
func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
writers := make([]zapcore.WriteSyncer, 0, len(paths))
closers := make([]io.Closer, 0, len(paths))
close := func() {
for _, c := range closers {
c.Close()
}
}
var openErr error
for _, path := range paths {
sink, err := newSink(path)
if err != nil {
openErr = multierr.Append(openErr, fmt.Errorf("couldn't open sink %q: %v", path, err))
continue
}
writers = append(writers, sink)
closers = append(closers, sink)
}
if openErr != nil {
close()
return writers, nil, openErr
}
return writers, close, nil
}
CombineWriteSyncers 방법은 zapcore를 먼저 사용합니다.NewMultiWriteSyncer(writers...)multiWriteSyncer를 만들고 Lock을 통해 lockedWriteSyncer를 만듭니다.오픈 방법은 paths에 따라zapcore를 만듭니다.WriteSyncer, 마지막으로 CombineWriteSyncers를 통해 자물쇠가 달린 multiWriteSyncer를 만듭니다.
Sink
[email protected]/sink.go
type Sink interface {
zapcore.WriteSyncer
io.Closer
}
Sink 인터페이스에zapcore가 내장되어 있습니다.WriteSyncer 및 io.Closer 인터페이스
Closer
/usr/local/go/src/io/io.go
type Closer interface {
Close() error
}
Closer 인터페이스에서 Close 방법을 정의했습니다.
nopCloserSink
type nopCloserSink struct{ zapcore.WriteSyncer }
func (nopCloserSink) Close() error { return nil }
nopCloserSink에 zapcore가 내장되어 있습니다.WriteSyncer, Close 메서드가 비어 있음
newSink
[email protected]/sink.go
var (
_sinkMutex sync.RWMutex
_sinkFactories map[string]func(*url.URL) (Sink, error) // keyed by scheme
)
func init() {
resetSinkRegistry()
}
func resetSinkRegistry() {
_sinkMutex.Lock()
defer _sinkMutex.Unlock()
_sinkFactories = map[string]func(*url.URL) (Sink, error){
schemeFile: newFileSink,
}
}
func newSink(rawURL string) (Sink, error) {
u, err := url.Parse(rawURL)
if err != nil {
return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err)
}
if u.Scheme == "" {
u.Scheme = schemeFile
}
_sinkMutex.RLock()
factory, ok := _sinkFactories[u.Scheme]
_sinkMutex.RUnlock()
if !ok {
return nil, &errSinkNotFound{u.Scheme}
}
return factory(u)
}
newSink 방법으로 URL을 해석하고 scheme를 통해 대응하는factory를 찾아factory를 호출하여 Sink를 만듭니다._sinkFactories는 기본적으로 newFileSink를 등록했습니다.
newFileSink
[email protected]/sink.go
func newFileSink(u *url.URL) (Sink, error) {
if u.User != nil {
return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u)
}
if u.Fragment != "" {
return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u)
}
if u.RawQuery != "" {
return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u)
}
// Error messages are better if we check hostname and port separately.
if u.Port() != "" {
return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u)
}
if hn := u.Hostname(); hn != "" && hn != "localhost" {
return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u)
}
switch u.Path {
case "stdout":
return nopCloserSink{os.Stdout}, nil
case "stderr":
return nopCloserSink{os.Stderr}, nil
}
return os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
}
stdout용 newFileSink 만들기
nopCloserSink{os.Stdout}
, stderr에 대한 생성nopCloserSink{os.Stderr}
, 이상 둘이 아니면 os로 돌아간다.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666); *os.File
Sink 인터페이스를 위한 Write, Sync, Close 메서드인스턴스
func sinkDemo() {
sink, cleanup, err := zap.Open("stdout", "/tmp/out1", "/tmp/out2")
if err == nil {
defer cleanup()
}
sink.Write([]byte("hello"))
sink.Write([]byte("world"))
}
출력
helloworld
동시에/tmp/out1,/tmp/out2도 출력이 있습니다.
작은 매듭
*os.File
는 Write, Sync, Close 방법을 가지고 Sink 인터페이스를 실현했다.nopCloserSink에 zapcore가 내장되어 있습니다.WriteSyncer, Close 메서드는 비어 있습니다.FileSink는 파일 기반sinkdoc
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
set containerThere is no built-in set container in Go How to implement Set struct{} => type struct{}{} => 0bytes How to create set :=...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.