// Copyright (c) 2016-2022 Uber Technologies, Inc.//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to deal// in the Software without restriction, including without limitation the rights// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN// THE SOFTWARE.package zapimport ()constschemeFile = "file"var_sinkRegistry = newSinkRegistry()// Sink defines the interface to write to and close logger destinations.typeSinkinterface {zapcore.WriteSyncerio.Closer}typeerrSinkNotFoundstruct {schemestring}func ( *errSinkNotFound) () string {returnfmt.Sprintf("no sink found for scheme %q", .scheme)}typenopCloserSinkstruct{ zapcore.WriteSyncer }func (nopCloserSink) () error { returnnil }typesinkRegistrystruct {musync.Mutexfactoriesmap[string]func(*url.URL) (Sink, error) // keyed by schemeopenFilefunc(string, int, os.FileMode) (*os.File, error) // type matches os.OpenFile}func () *sinkRegistry { := &sinkRegistry{factories: make(map[string]func(*url.URL) (Sink, error)),openFile: os.OpenFile, }// Infallible operation: the registry is empty, so we can't have a conflict. _ = .RegisterSink(schemeFile, .newFileSinkFromURL)return}// RegisterScheme registers the given factory for the specific scheme.func ( *sinkRegistry) ( string, func(*url.URL) (Sink, error)) error { .mu.Lock()defer .mu.Unlock()if == "" {returnerrors.New("can't register a sink factory for empty string") } , := normalizeScheme()if != nil {returnfmt.Errorf("%q is not a valid scheme: %v", , ) }if , := .factories[]; {returnfmt.Errorf("sink factory already registered for scheme %q", ) } .factories[] = returnnil}func ( *sinkRegistry) ( string) (Sink, error) {// URL parsing doesn't work well for Windows paths such as `c:\log.txt`, as scheme is set to // the drive, and path is unset unless `c:/log.txt` is used. // To avoid Windows-specific URL handling, we instead check IsAbs to open as a file. // filepath.IsAbs is OS-specific, so IsAbs('c:/log.txt') is false outside of Windows.iffilepath.IsAbs() {return .newFileSinkFromPath() } , := url.Parse()if != nil {returnnil, fmt.Errorf("can't parse %q as a URL: %v", , ) }if .Scheme == "" { .Scheme = schemeFile } .mu.Lock() , := .factories[.Scheme] .mu.Unlock()if ! {returnnil, &errSinkNotFound{.Scheme} }return ()}// RegisterSink registers a user-supplied factory for all sinks with a// particular scheme.//// All schemes must be ASCII, valid under section 0.1 of RFC 3986// (https://tools.ietf.org/html/rfc3983#section-3.1), and must not already// have a factory registered. Zap automatically registers a factory for the// "file" scheme.func ( string, func(*url.URL) (Sink, error)) error {return_sinkRegistry.RegisterSink(, )}func ( *sinkRegistry) ( *url.URL) (Sink, error) {if .User != nil {returnnil, fmt.Errorf("user and password not allowed with file URLs: got %v", ) }if .Fragment != "" {returnnil, fmt.Errorf("fragments not allowed with file URLs: got %v", ) }if .RawQuery != "" {returnnil, fmt.Errorf("query parameters not allowed with file URLs: got %v", ) }// Error messages are better if we check hostname and port separately.if .Port() != "" {returnnil, fmt.Errorf("ports not allowed with file URLs: got %v", ) }if := .Hostname(); != "" && != "localhost" {returnnil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", ) }return .newFileSinkFromPath(.Path)}func ( *sinkRegistry) ( string) (Sink, error) {switch {case"stdout":returnnopCloserSink{os.Stdout}, nilcase"stderr":returnnopCloserSink{os.Stderr}, nil }return .openFile(, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666)}func ( string) (string, error) {// https://tools.ietf.org/html/rfc3986#section-3.1 = strings.ToLower()if := [0]; 'a' > || 'z' < {return"", errors.New("must start with a letter") }for := 1; < len(); ++ { // iterate over bytes, not runes := []switch {case'a' <= && <= 'z':continuecase'0' <= && <= '9':continuecase == '.' || == '+' || == '-':continue }return"", fmt.Errorf("may not contain %q", ) }return , nil}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.