github.com/go-kivik/kivik/v4@v4.3.2/x/kivikd/logger/logger.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 // Package logger defines the logger used by kivikd. 14 package logger 15 16 import ( 17 "fmt" 18 "io" 19 "net/http" 20 "os" 21 "strings" 22 "time" 23 ) 24 25 // RequestLogger is a request logger. 26 type RequestLogger interface { 27 Log(req *http.Request, status int, fields Fields) 28 } 29 30 // Pre-defined log fields 31 const ( 32 FieldUsername = "username" 33 FieldTimestamp = "timestamp" 34 FieldElapsedTime = "elapsed" 35 FieldResponseSize = "size" 36 ) 37 38 // Fields is simple wrapper around logging fields. 39 type Fields map[string]interface{} 40 41 // Exists returns true if the requested key exists in the map. 42 func (f Fields) Exists(key string) bool { 43 _, ok := f[key] 44 return ok 45 } 46 47 // Get returns the value associated with a key. 48 func (f Fields) Get(key string) interface{} { 49 return f[key] 50 } 51 52 // GetString returns a value as a string, or "-" 53 func (f Fields) GetString(key string) string { 54 v, ok := f[key].(string) 55 if ok { 56 return v 57 } 58 return "-" 59 } 60 61 // GetDuration returns a value as a time.Duration 62 func (f Fields) GetDuration(key string) time.Duration { 63 v, _ := f[key].(time.Duration) 64 return v 65 } 66 67 // GetTime returns a value as a timestamp. 68 func (f Fields) GetTime(key string) time.Time { 69 v, _ := f[key].(time.Time) 70 return v 71 } 72 73 // GetInt returns a value as an int. 74 func (f Fields) GetInt(key string) int { 75 v, _ := f[key].(int) 76 return v 77 } 78 79 type logger struct { 80 w io.Writer 81 } 82 83 var _ RequestLogger = &logger{} 84 85 // New returns a new RequestLogger that writes apache-style logs to an io.Writer. 86 func New(w io.Writer) RequestLogger { 87 return &logger{w} 88 } 89 90 // DefaultLogger logs to stderr. 91 var DefaultLogger = New(os.Stderr) 92 93 func (l *logger) Log(req *http.Request, status int, fields Fields) { 94 _, _ = fmt.Fprintf(l.w, `%s %s [%s] (%s) "%s %s %s" %d %d "%s" "%s"%c`, 95 req.RemoteAddr[0:strings.LastIndex(req.RemoteAddr, ":")], 96 fields.GetString(FieldUsername), 97 fields.GetTime(FieldTimestamp).Format("2006-01-02 15:04:05Z07:00"), 98 fields.GetDuration(FieldElapsedTime).String(), 99 req.Method, 100 req.URL.String(), 101 req.Proto, 102 status, 103 fields.GetInt(FieldResponseSize), 104 req.Header.Get("Referer"), 105 req.Header.Get("User-Agent"), 106 '\n', 107 ) 108 }