├── go.mod
├── examples
├── ConsoleLogWriter_Manual.go
├── XMLConfigurationExample.go
├── SocketLogWriter_Manual.go
├── SimpleNetLogServer.go
├── FileLogWriter_Manual.go
└── example.xml
├── README
├── LICENSE
├── termlog.go
├── socklog.go
├── pattlog.go
├── filelog.go
├── config.go
├── wrapper.go
├── log4go.go
├── log4go_test.go
└── go.sum
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/blackbeans/log4go
2 |
3 | go 1.16
4 |
5 | require github.com/prometheus/client_golang v1.14.0
6 |
--------------------------------------------------------------------------------
/examples/ConsoleLogWriter_Manual.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | import l4g "github.com/blackbeans/log4go"
8 |
9 | func main() {
10 | log := l4g.NewLogger()
11 | log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
12 | log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
13 | }
14 |
--------------------------------------------------------------------------------
/examples/XMLConfigurationExample.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import l4g "github.com/blackbeans/log4go"
4 |
5 | func main() {
6 | // Load the configuration (isn't this easy?)
7 | l4g.LoadConfiguration("example.xml")
8 |
9 | // And now we're ready!
10 | l4g.Finest("This will only go to those of you really cool UDP kids! If you change enabled=true.")
11 | l4g.Debug("Oh no! %d + %d = %d!", 2, 2, 2+2)
12 | l4g.Info("About that time, eh chaps?")
13 | }
14 |
--------------------------------------------------------------------------------
/examples/SocketLogWriter_Manual.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | import l4g "github.com/blackbeans/log4go"
8 |
9 | func main() {
10 | log := l4g.NewLogger()
11 | log.AddFilter("network", l4g.FINEST, l4g.NewSocketLogWriter("udp", "192.168.1.255:12124"))
12 |
13 | // Run `nc -u -l -p 12124` or similar before you run this to see the following message
14 | log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
15 |
16 | // This makes sure the output stream buffer is written
17 | log.Close()
18 | }
19 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Please see http://log4go.googlecode.com/
2 |
3 | Installation:
4 | - Run `go install log4go.googlecode.com/hg`
5 |
6 | Usage:
7 | - Add the following import:
8 | import l4g "log4go.googlecode.com/hg"
9 |
10 | Acknowledgements:
11 | - pomack
12 | For providing awesome patches to bring log4go up to the latest Go spec
13 |
14 |
15 | More Feature:
16 | - log to a file as you define
17 |
18 | log.LoadConfiguration("log.xml")
19 | exp:
20 | log.DebugLog("kite_handler",format,args...)
21 | log.InfoLog("kite_handler",format,args...)
22 | log.WarnLog("kite_handler",format,args...)
23 | log.ErrorLog("kite_handler",format,args...)
24 |
25 | - log rolling by day
26 |
27 | true
28 |
--------------------------------------------------------------------------------
/examples/SimpleNetLogServer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "net"
7 | "os"
8 | )
9 |
10 | var (
11 | port = flag.String("p", "12124", "Port number to listen on")
12 | )
13 |
14 | func e(err error) {
15 | if err != nil {
16 | fmt.Printf("Erroring out: %s\n", err)
17 | os.Exit(1)
18 | }
19 | }
20 |
21 | func main() {
22 | flag.Parse()
23 |
24 | // Bind to the port
25 | bind, err := net.ResolveUDPAddr("udp", "0.0.0.0:"+*port)
26 | e(err)
27 |
28 | // Create listener
29 | listener, err := net.ListenUDP("udp", bind)
30 | e(err)
31 |
32 | fmt.Printf("Listening to port %s...\n", *port)
33 | for {
34 | // read into a new buffer
35 | buffer := make([]byte, 1024)
36 | _, _, err := listener.ReadFrom(buffer)
37 | e(err)
38 |
39 | // log to standard output
40 | fmt.Println(string(buffer))
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010, Kyle Lemons . All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
5 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
6 | documentation and/or other materials provided with the distribution.
7 |
8 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
13 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 |
--------------------------------------------------------------------------------
/termlog.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "io"
7 | "os"
8 | "fmt"
9 | )
10 |
11 | var stdout io.Writer = os.Stdout
12 |
13 | // This is the standard writer that prints to standard output.
14 | type ConsoleLogWriter chan *LogRecord
15 |
16 | // This creates a new ConsoleLogWriter
17 | func NewConsoleLogWriter() ConsoleLogWriter {
18 | records := make(ConsoleLogWriter, LogBufferLength)
19 | go records.run(stdout)
20 | return records
21 | }
22 |
23 | func (w ConsoleLogWriter) run(out io.Writer) {
24 | var timestr string
25 | var timestrAt int64
26 |
27 | for rec := range w {
28 | if at := rec.Created.UnixNano() / 1e9; at != timestrAt {
29 | timestr, timestrAt = rec.Created.Format("01/02/06 15:04:05"), at
30 | }
31 | fmt.Fprint(out, "[", timestr, "] [", levelStrings[rec.Level], "] ", rec.Message, "\n")
32 | }
33 | }
34 |
35 | // This is the ConsoleLogWriter's output method. This will block if the output
36 | // buffer is full.
37 | func (w ConsoleLogWriter) LogWrite(rec *LogRecord) {
38 | w <- rec
39 | }
40 |
41 | // Close stops the logger from sending messages to standard output. Attempts to
42 | // send log messages to this logger after a Close have undefined behavior.
43 | func (w ConsoleLogWriter) Close() {
44 | close(w)
45 | }
46 |
--------------------------------------------------------------------------------
/socklog.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "encoding/json"
7 | "fmt"
8 | "net"
9 | "os"
10 | )
11 |
12 | // This log writer sends output to a socket
13 | type SocketLogWriter chan *LogRecord
14 |
15 | // This is the SocketLogWriter's output method
16 | func (w SocketLogWriter) LogWrite(rec *LogRecord) {
17 | w <- rec
18 | }
19 |
20 | func (w SocketLogWriter) Close() {
21 | close(w)
22 | }
23 |
24 | func NewSocketLogWriter(proto, hostport string) SocketLogWriter {
25 | sock, err := net.Dial(proto, hostport)
26 | if err != nil {
27 | fmt.Fprintf(os.Stderr, "NewSocketLogWriter(%q): %s\n", hostport, err)
28 | return nil
29 | }
30 |
31 | w := SocketLogWriter(make(chan *LogRecord, LogBufferLength))
32 |
33 | go func() {
34 | defer func() {
35 | if sock != nil && proto == "tcp" {
36 | sock.Close()
37 | }
38 | }()
39 |
40 | for rec := range w {
41 | // Marshall into JSON
42 | js, err := json.Marshal(rec)
43 | if err != nil {
44 | fmt.Fprint(os.Stderr, "SocketLogWriter(%q): %s", hostport, err)
45 | return
46 | }
47 |
48 | _, err = sock.Write(js)
49 | if err != nil {
50 | fmt.Fprint(os.Stderr, "SocketLogWriter(%q): %s", hostport, err)
51 | return
52 | }
53 | }
54 | }()
55 |
56 | return w
57 | }
58 |
--------------------------------------------------------------------------------
/examples/FileLogWriter_Manual.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "io"
7 | "os"
8 | "time"
9 | )
10 |
11 | import l4g "github.com/blackbeans/log4go"
12 |
13 | const (
14 | filename = "flw.log"
15 | )
16 |
17 | func main() {
18 | // Get a new logger instance
19 | log := l4g.NewLogger()
20 |
21 | // Create a default logger that is logging messages of FINE or higher
22 | log.AddFilter("file", l4g.FINE, l4g.NewFileLogWriter(filename, false, true))
23 | log.Close()
24 |
25 | /* Can also specify manually via the following: (these are the defaults) */
26 | flw := l4g.NewFileLogWriter(filename, false, true)
27 | flw.SetFormat("[%D %T] [%L] (%S) %M")
28 | flw.SetRotate(false)
29 | flw.SetRotateSize(0)
30 | flw.SetRotateLines(0)
31 | flw.SetRotateDaily(false)
32 | log.AddFilter("file", l4g.FINE, flw)
33 |
34 | // Log some experimental messages
35 | log.Finest("Everything is created now (notice that I will not be printing to the file)")
36 | log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
37 | log.Critical("Time to close out!")
38 |
39 | // Close the log
40 | log.Close()
41 |
42 | // Print what was logged to the file (yes, I know I'm skipping error checking)
43 | fd, _ := os.Open(filename)
44 | in := bufio.NewReader(fd)
45 | fmt.Print("Messages logged to file were: (line numbers not included)\n")
46 | for lineno := 1; ; lineno++ {
47 | line, err := in.ReadString('\n')
48 | if err == io.EOF {
49 | break
50 | }
51 | fmt.Printf("%3d:\t%s", lineno, line)
52 | }
53 | fd.Close()
54 |
55 | // Remove the file so it's not lying around
56 | os.Remove(filename)
57 | }
58 |
--------------------------------------------------------------------------------
/examples/example.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | stdout
4 | console
5 |
6 | DEBUG
7 |
8 |
9 | file
10 | file
11 | FINEST
12 | test.log
13 |
24 | [%D %T] [%L] (%S) %M
25 | false
26 | 0M
27 | 0K
28 | true
29 |
30 |
31 | xmllog
32 | xml
33 | TRACE
34 | trace.xml
35 | true
36 | 100M
37 | 6K
38 | false
39 |
40 |
41 | donotopen
42 | socket
43 | FINEST
44 | 192.168.1.255:12124
45 | udp
46 |
47 |
48 |
--------------------------------------------------------------------------------
/pattlog.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "bytes"
7 | "fmt"
8 | "io"
9 | )
10 |
11 | const (
12 | FORMAT_DEFAULT = "[%D %T] [%L] (%S) %M"
13 | FORMAT_SHORT = "[%t %d] [%L] %M"
14 | FORMAT_ABBREV = "[%L] %M"
15 | )
16 |
17 | type formatCacheType struct {
18 | LastUpdateSeconds int64
19 | shortTime, shortDate string
20 | longTime, longDate string
21 | }
22 |
23 | var formatCache = &formatCacheType{}
24 |
25 | // Known format codes:
26 | // %T - Time (15:04:05 MST)
27 | // %t - Time (15:04)
28 | // %D - Date (2006/01/02)
29 | // %d - Date (01/02/06)
30 | // %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
31 | // %S - Source
32 | // %M - Message
33 | // Ignores unknown formats
34 | // Recommended: "[%D %T] [%L] (%S) %M"
35 | func FormatLogRecord(format string, rec *LogRecord) string {
36 | if rec == nil {
37 | return ""
38 | }
39 | if len(format) == 0 {
40 | return ""
41 | }
42 |
43 | out := bytes.NewBuffer(make([]byte, 0, 64))
44 | secs := rec.Created.UnixNano() / 1e9
45 |
46 | cache := *formatCache
47 | if cache.LastUpdateSeconds != secs {
48 | month, day, year := rec.Created.Month(), rec.Created.Day(), rec.Created.Year()
49 | hour, minute, second := rec.Created.Hour(), rec.Created.Minute(), rec.Created.Second()
50 | zone, _ := rec.Created.Zone()
51 | updated := &formatCacheType{
52 | LastUpdateSeconds: secs,
53 | shortTime: fmt.Sprintf("%02d:%02d", hour, minute),
54 | shortDate: fmt.Sprintf("%02d/%02d/%02d", month, day, year%100),
55 | longTime: fmt.Sprintf("%02d:%02d:%02d %s", hour, minute, second, zone),
56 | longDate: fmt.Sprintf("%04d/%02d/%02d", year, month, day),
57 | }
58 | cache = *updated
59 | formatCache = updated
60 | }
61 |
62 | // Split the string into pieces by % signs
63 | pieces := bytes.Split([]byte(format), []byte{'%'})
64 |
65 | // Iterate over the pieces, replacing known formats
66 | for i, piece := range pieces {
67 | if i > 0 && len(piece) > 0 {
68 | switch piece[0] {
69 | case 'T':
70 | out.WriteString(cache.longTime)
71 | case 't':
72 | out.WriteString(cache.shortTime)
73 | case 'D':
74 | out.WriteString(cache.longDate)
75 | case 'd':
76 | out.WriteString(cache.shortDate)
77 | case 'L':
78 | out.WriteString(levelStrings[rec.Level])
79 | case 'S':
80 | out.WriteString(rec.Source)
81 | case 'M':
82 | out.WriteString(rec.Message)
83 | }
84 | if len(piece) > 1 {
85 | out.Write(piece[1:])
86 | }
87 | } else if len(piece) > 0 {
88 | out.Write(piece)
89 | }
90 | }
91 | out.WriteByte('\n')
92 |
93 | return out.String()
94 | }
95 |
96 | // This is the standard writer that prints to standard output.
97 | type FormatLogWriter chan *LogRecord
98 |
99 | // This creates a new FormatLogWriter
100 | func NewFormatLogWriter(out io.Writer, format string) FormatLogWriter {
101 | records := make(FormatLogWriter, LogBufferLength)
102 | go records.run(out, format)
103 | return records
104 | }
105 |
106 | func (w FormatLogWriter) run(out io.Writer, format string) {
107 | for rec := range w {
108 | fmt.Fprint(out, FormatLogRecord(format, rec))
109 | }
110 | }
111 |
112 | // This is the FormatLogWriter's output method. This will block if the output
113 | // buffer is full.
114 | func (w FormatLogWriter) LogWrite(rec *LogRecord) {
115 | w <- rec
116 | }
117 |
118 | // Close stops the logger from sending messages to standard output. Attempts to
119 | // send log messages to this logger after a Close have undefined behavior.
120 | func (w FormatLogWriter) Close() {
121 | close(w)
122 | }
123 |
--------------------------------------------------------------------------------
/filelog.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "fmt"
7 | "os"
8 | "strings"
9 | "time"
10 | )
11 |
12 | // This log writer sends output to a file
13 | type FileLogWriter struct {
14 | rec chan *LogRecord
15 | rot chan bool
16 |
17 | // The opened file
18 | filename string
19 | file *os.File
20 |
21 | // The logging format
22 | format string
23 |
24 | // File header/trailer
25 | header, trailer string
26 |
27 | // Rotate at linecount
28 | maxlines int
29 | maxlines_curlines int
30 |
31 | // Rotate at size
32 | maxsize int
33 | maxsize_cursize int
34 |
35 | // Rotate daily
36 | daily bool
37 | daily_opendate int
38 |
39 | // Keep old logfiles (.001, .002, etc)
40 | rotate bool
41 | }
42 |
43 | // This is the FileLogWriter's output method
44 | func (w *FileLogWriter) LogWrite(rec *LogRecord) {
45 | w.rec <- rec
46 | }
47 |
48 | func (w *FileLogWriter) Close() {
49 | close(w.rec)
50 | }
51 |
52 | // NewFileLogWriter creates a new LogWriter which writes to the given file and
53 | // has rotation enabled if rotate is true.
54 | //
55 | // If rotate is true, any time a new log file is opened, the old one is renamed
56 | // with a .### extension to preserve it. The various Set* methods can be used
57 | // to configure log rotation based on lines, size, and daily.
58 | //
59 | // The standard log-line format is:
60 | // [%D %T] [%L] (%S) %M
61 | func NewFileLogWriter(fname string, rotate bool, daily bool) *FileLogWriter {
62 | w := &FileLogWriter{
63 | rec: make(chan *LogRecord, LogBufferLength),
64 | rot: make(chan bool),
65 | filename: fname,
66 | daily_opendate: time.Now().Day(),
67 | format: "[%D %T] [%L] (%S) %M",
68 | rotate: rotate,
69 | daily: daily}
70 |
71 | // open the file for the first time
72 | // if err := w.intRotate(); err != nil {
73 | // fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
74 | // return nil
75 | // }
76 |
77 | fpath := fname[:strings.LastIndex(fname, "/")]
78 |
79 | //check path
80 | _, err := os.Lstat(fpath)
81 | if nil != err {
82 | os.MkdirAll(fpath, os.ModePerm)
83 | }
84 |
85 | // Open the log file
86 | fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
87 | if err != nil {
88 | panic(err)
89 | }
90 | w.file = fd
91 |
92 | now := time.Now()
93 |
94 | // Set the daily open date to the current date
95 | w.daily_opendate = now.Day()
96 |
97 | fi, err := fd.Stat()
98 | if nil == err && nil != fi {
99 | w.maxsize_cursize = int(fi.Size())
100 | now = fi.ModTime()
101 | }
102 | // initialize rotation values
103 | w.maxlines_curlines = 0
104 |
105 | fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: now}))
106 |
107 | go func() {
108 | defer func() {
109 | if w.file != nil {
110 | fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
111 | w.file.Close()
112 | }
113 | }()
114 |
115 | for {
116 | select {
117 | case <-w.rot:
118 | if err := w.intRotate(); err != nil {
119 | fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
120 | return
121 | }
122 | case rec, ok := <-w.rec:
123 | if !ok {
124 | return
125 | }
126 |
127 | if (w.maxlines > 0 && w.maxlines_curlines >= w.maxlines) ||
128 | (w.maxsize > 0 && w.maxsize_cursize >= w.maxsize) {
129 | if err := w.intRotate(); err != nil {
130 | fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
131 | return
132 | }
133 | }
134 |
135 | now := time.Now()
136 | //如果是开启了并且按天滚动,并且已经换了一天需要重建
137 | if w.daily {
138 | if now.Day() != w.daily_opendate {
139 | if err := w.intRotate(); err != nil {
140 | fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
141 | return
142 | }
143 | }
144 | }
145 |
146 | // Perform the write
147 | n, err := fmt.Fprint(w.file, FormatLogRecord(w.format, rec))
148 | if err != nil {
149 | fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
150 | return
151 | }
152 |
153 | // Update the counts
154 | w.maxlines_curlines++
155 | w.maxsize_cursize += n
156 | }
157 | }
158 | }()
159 |
160 | return w
161 | }
162 |
163 | // Request that the logs rotate
164 | func (w *FileLogWriter) Rotate() {
165 | w.rot <- true
166 | }
167 |
168 | // If this is called in a threaded context, it MUST be synchronized
169 | func (w *FileLogWriter) intRotate() error {
170 | // Close any log file that may be open
171 | if w.file != nil {
172 | fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
173 | w.file.Close()
174 | }
175 |
176 | // If we are keeping log files, move it to the next available number
177 | if w.rotate {
178 | _, err := os.Lstat(w.filename)
179 | if err == nil { // file exists
180 | // Find the next available number
181 | num := 1
182 | fname := w.filename
183 | filename := strings.TrimSuffix(w.filename, ".log")
184 | for ; err == nil && num <= 999; num++ {
185 | if w.daily {
186 | if time.Now().Day() != w.daily_opendate {
187 | t := time.Now().Add(-24 * time.Hour).Format("2006-01-02")
188 | fname = fmt.Sprintf("%s.%s-%03d.log", filename, t, num)
189 | } else {
190 | t := time.Now().Format("2006-01-02")
191 | fname = fmt.Sprintf("%s.%s-%03d.log", filename, t, num)
192 | }
193 | } else {
194 | fname = fmt.Sprintf("%s.%03d.log", filename, num)
195 | }
196 |
197 | _, err = os.Lstat(fname)
198 | }
199 | // return error if the last file checked still existed
200 | if err == nil {
201 | return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.filename)
202 | }
203 |
204 | // Rename the file to its newfound home
205 | err = os.Rename(w.filename, fname)
206 | if err != nil {
207 | return fmt.Errorf("Rotate: %s\n", err)
208 | }
209 | }
210 | }
211 |
212 | // Open the log file
213 | fd, err := os.OpenFile(w.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
214 | if err != nil {
215 | return err
216 | }
217 | w.file = fd
218 |
219 | now := time.Now()
220 | fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: now}))
221 |
222 | // Set the daily open date to the current date
223 | w.daily_opendate = now.Day()
224 |
225 | // initialize rotation values
226 | w.maxlines_curlines = 0
227 | w.maxsize_cursize = 0
228 | return nil
229 | }
230 |
231 | // Set the logging format (chainable). Must be called before the first log
232 | // message is written.
233 | func (w *FileLogWriter) SetFormat(format string) *FileLogWriter {
234 | w.format = format
235 | return w
236 | }
237 |
238 | // Set the logfile header and footer (chainable). Must be called before the first log
239 | // message is written. These are formatted similar to the FormatLogRecord (e.g.
240 | // you can use %D and %T in your header/footer for date and time).
241 | func (w *FileLogWriter) SetHeadFoot(head, foot string) *FileLogWriter {
242 | w.header, w.trailer = head, foot
243 | if w.maxlines_curlines == 0 {
244 | fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: time.Now()}))
245 | }
246 | return w
247 | }
248 |
249 | // Set rotate at linecount (chainable). Must be called before the first log
250 | // message is written.
251 | func (w *FileLogWriter) SetRotateLines(maxlines int) *FileLogWriter {
252 | //fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateLines: %v\n", maxlines)
253 | w.maxlines = maxlines
254 | return w
255 | }
256 |
257 | // Set rotate at size (chainable). Must be called before the first log message
258 | // is written.
259 | func (w *FileLogWriter) SetRotateSize(maxsize int) *FileLogWriter {
260 | //fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateSize: %v\n", maxsize)
261 | w.maxsize = maxsize
262 | return w
263 | }
264 |
265 | // Set rotate daily (chainable). Must be called before the first log message is
266 | // written.
267 | func (w *FileLogWriter) SetRotateDaily(daily bool) *FileLogWriter {
268 | //fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateDaily: %v\n", daily)
269 | w.daily = daily
270 | return w
271 | }
272 |
273 | // SetRotate changes whether or not the old logs are kept. (chainable) Must be
274 | // called before the first log message is written. If rotate is false, the
275 | // files are overwritten; otherwise, they are rotated to another file before the
276 | // new log is opened.
277 | func (w *FileLogWriter) SetRotate(rotate bool) *FileLogWriter {
278 | //fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotate: %v\n", rotate)
279 | w.rotate = rotate
280 | return w
281 | }
282 |
283 | // NewXMLLogWriter is a utility method for creating a FileLogWriter set up to
284 | // output XML record log messages instead of line-based ones.
285 | func NewXMLLogWriter(fname string, rotate bool, daily bool) *FileLogWriter {
286 | return NewFileLogWriter(fname, rotate, daily).SetFormat(
287 | `
288 | %D %T
289 | %S
290 | %M
291 | `).SetHeadFoot("", "")
292 | }
293 |
--------------------------------------------------------------------------------
/config.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "encoding/xml"
7 | "fmt"
8 | "io/ioutil"
9 | "os"
10 | "strconv"
11 | "strings"
12 | )
13 |
14 | type xmlProperty struct {
15 | Name string `xml:"name,attr"`
16 | Value string `xml:",chardata"`
17 | }
18 |
19 | type xmlFilter struct {
20 | Enabled string `xml:"enabled,attr"`
21 | Tag string `xml:"tag"`
22 | Level string `xml:"level"`
23 | Type string `xml:"type"`
24 | Property []xmlProperty `xml:"property"`
25 | }
26 |
27 | type xmlLoggerConfig struct {
28 | Filter []xmlFilter `xml:"filter"`
29 | }
30 |
31 | // Load XML configuration; see examples/example.xml for documentation
32 | func (log Logger) LoadConfiguration(filename string) {
33 | log.Close()
34 |
35 | // Open the configuration file
36 | fd, err := os.Open(filename)
37 | if err != nil {
38 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not open %q for reading: %s\n", filename, err)
39 | os.Exit(1)
40 | }
41 |
42 | contents, err := ioutil.ReadAll(fd)
43 | if err != nil {
44 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not read %q: %s\n", filename, err)
45 | os.Exit(1)
46 | }
47 |
48 | xc := new(xmlLoggerConfig)
49 | if err := xml.Unmarshal(contents, xc); err != nil {
50 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not parse XML configuration in %q: %s\n", filename, err)
51 | os.Exit(1)
52 | }
53 |
54 | for _, xmlfilt := range xc.Filter {
55 | var filt LogWriter
56 | var lvl level
57 | bad, good, enabled := false, true, false
58 |
59 | // Check required children
60 | if len(xmlfilt.Enabled) == 0 {
61 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required attribute %s for filter missing in %s\n", "enabled", filename)
62 | bad = true
63 | } else {
64 | enabled = xmlfilt.Enabled != "false"
65 | }
66 | if len(xmlfilt.Tag) == 0 {
67 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "tag", filename)
68 | bad = true
69 | }
70 | if len(xmlfilt.Type) == 0 {
71 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "type", filename)
72 | bad = true
73 | }
74 | if len(xmlfilt.Level) == 0 {
75 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "level", filename)
76 | bad = true
77 | }
78 |
79 | switch xmlfilt.Level {
80 | case "FINEST":
81 | lvl = FINEST
82 | case "FINE":
83 | lvl = FINE
84 | case "DEBUG":
85 | lvl = DEBUG
86 | case "TRACE":
87 | lvl = TRACE
88 | case "INFO":
89 | lvl = INFO
90 | case "WARNING":
91 | lvl = WARNING
92 | case "ERROR":
93 | lvl = ERROR
94 | case "CRITICAL":
95 | lvl = CRITICAL
96 | default:
97 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter has unknown value in %s: %s\n", "level", filename, xmlfilt.Level)
98 | bad = true
99 | }
100 |
101 | // Just so all of the required attributes are errored at the same time if missing
102 | if bad {
103 | os.Exit(1)
104 | }
105 |
106 | file := "./logs/"
107 | switch xmlfilt.Type {
108 | case "console":
109 | filt, good = xmlToConsoleLogWriter(filename, xmlfilt.Property, enabled)
110 | case "file":
111 | filt, file, good = xmlToFileLogWriter(filename, xmlfilt.Property, enabled)
112 | case "xml":
113 | filt, file, good = xmlToXMLLogWriter(filename, xmlfilt.Property, enabled)
114 | case "socket":
115 | filt, good = xmlToSocketLogWriter(filename, xmlfilt.Property, enabled)
116 | default:
117 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not load XML configuration in %s: unknown filter type \"%s\"\n", filename, xmlfilt.Type)
118 | os.Exit(1)
119 | }
120 |
121 | // Just so all of the required params are errored at the same time if wrong
122 | if !good {
123 | os.Exit(1)
124 | }
125 |
126 | // If we're disabled (syntax and correctness checks only), don't add to logger
127 | if !enabled {
128 | continue
129 | }
130 |
131 | log[xmlfilt.Tag] = &Filter{lvl, file, filt}
132 | }
133 | }
134 |
135 | func xmlToConsoleLogWriter(filename string, props []xmlProperty, enabled bool) (ConsoleLogWriter, bool) {
136 | // Parse properties
137 | for _, prop := range props {
138 | switch prop.Name {
139 | default:
140 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for console filter in %s\n", prop.Name, filename)
141 | }
142 | }
143 |
144 | // If it's disabled, we're just checking syntax
145 | if !enabled {
146 | return nil, true
147 | }
148 |
149 | return NewConsoleLogWriter(), true
150 | }
151 |
152 | // Parse a number with K/M/G suffixes based on thousands (1000) or 2^10 (1024)
153 | func strToNumSuffix(str string, mult int) int {
154 | num := 1
155 | if len(str) > 1 {
156 | switch str[len(str)-1] {
157 | case 'G', 'g':
158 | num *= mult
159 | fallthrough
160 | case 'M', 'm':
161 | num *= mult
162 | fallthrough
163 | case 'K', 'k':
164 | num *= mult
165 | str = str[0 : len(str)-1]
166 | }
167 | }
168 | parsed, _ := strconv.Atoi(str)
169 | return parsed * num
170 | }
171 | func xmlToFileLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, string, bool) {
172 | file := ""
173 | format := "[%D %T] [%L] (%S) %M"
174 | maxlines := 0
175 | maxsize := 0
176 | daily := false
177 | rotate := false
178 |
179 | // Parse properties
180 | for _, prop := range props {
181 | switch prop.Name {
182 | case "filename":
183 | file = strings.Trim(prop.Value, " \r\n")
184 | case "format":
185 | format = strings.Trim(prop.Value, " \r\n")
186 | case "maxlines":
187 | maxlines = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
188 | case "maxsize":
189 | maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
190 | case "daily":
191 | daily = strings.Trim(prop.Value, " \r\n") != "false"
192 | case "rotate":
193 | rotate = strings.Trim(prop.Value, " \r\n") != "false"
194 | default:
195 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
196 | }
197 | }
198 |
199 | // Check properties
200 | if len(file) == 0 {
201 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "filename", filename)
202 | return nil, file, false
203 | }
204 |
205 | // If it's disabled, we're just checking syntax
206 | if !enabled {
207 | return nil, file, true
208 | }
209 |
210 | flw := NewFileLogWriter(file, rotate, daily)
211 | flw.SetFormat(format)
212 | flw.SetRotateLines(maxlines)
213 | flw.SetRotateSize(maxsize)
214 | return flw, file, true
215 | }
216 |
217 | func xmlToXMLLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, string, bool) {
218 | file := ""
219 | maxrecords := 0
220 | maxsize := 0
221 | daily := false
222 | rotate := false
223 |
224 | // Parse properties
225 | for _, prop := range props {
226 | switch prop.Name {
227 | case "filename":
228 | file = strings.Trim(prop.Value, " \r\n")
229 | case "maxrecords":
230 | maxrecords = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
231 | case "maxsize":
232 | maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
233 | case "daily":
234 | daily = strings.Trim(prop.Value, " \r\n") != "false"
235 | case "rotate":
236 | rotate = strings.Trim(prop.Value, " \r\n") != "false"
237 | default:
238 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for xml filter in %s\n", prop.Name, filename)
239 | }
240 | }
241 |
242 | // Check properties
243 | if len(file) == 0 {
244 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for xml filter missing in %s\n", "filename", filename)
245 | return nil, file, false
246 | }
247 |
248 | // If it's disabled, we're just checking syntax
249 | if !enabled {
250 | return nil, file, true
251 | }
252 |
253 | xlw := NewXMLLogWriter(file, rotate, daily)
254 | xlw.SetRotateLines(maxrecords)
255 | xlw.SetRotateSize(maxsize)
256 | return xlw, file, true
257 | }
258 |
259 | func xmlToSocketLogWriter(filename string, props []xmlProperty, enabled bool) (SocketLogWriter, bool) {
260 | endpoint := ""
261 | protocol := "udp"
262 |
263 | // Parse properties
264 | for _, prop := range props {
265 | switch prop.Name {
266 | case "endpoint":
267 | endpoint = strings.Trim(prop.Value, " \r\n")
268 | case "protocol":
269 | protocol = strings.Trim(prop.Value, " \r\n")
270 | default:
271 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
272 | }
273 | }
274 |
275 | // Check properties
276 | if len(endpoint) == 0 {
277 | fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "endpoint", filename)
278 | return nil, false
279 | }
280 |
281 | // If it's disabled, we're just checking syntax
282 | if !enabled {
283 | return nil, true
284 | }
285 |
286 | return NewSocketLogWriter(protocol, endpoint), true
287 | }
288 |
--------------------------------------------------------------------------------
/wrapper.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "errors"
7 | "fmt"
8 | "os"
9 | "strings"
10 | )
11 |
12 | var (
13 | Global Logger
14 | )
15 |
16 | func init() {
17 | Global = NewDefaultLogger(DEBUG)
18 | // innerInit()
19 | }
20 |
21 | // Wrapper for (*Logger).LoadConfiguration
22 | func LoadConfiguration(filename string) {
23 | Global.LoadConfiguration(filename)
24 |
25 | //check defualt logger
26 | _, ok := Global["stdout"]
27 | if !ok {
28 | Global["stdout"] = &Filter{INFO, "./logs/", NewConsoleLogWriter()}
29 | }
30 | }
31 |
32 | // Wrapper for (*Logger).AddFilter
33 | func AddFilter(name string, lvl level, writer LogWriter) {
34 | Global.AddFilter(name, lvl, writer)
35 |
36 | }
37 |
38 | // Wrapper for (*Logger).Close (closes and removes all logwriters)
39 | func Close() {
40 | Global.Close()
41 | }
42 |
43 | func Crash(args ...interface{}) {
44 | if len(args) > 0 {
45 | Global.intLogf(CRITICAL, strings.Repeat(" %v", len(args))[1:], args...)
46 | }
47 | panic(args)
48 | }
49 |
50 | // Logs the given message and crashes the program
51 | func Crashf(format string, args ...interface{}) {
52 | Global.intLogf(CRITICAL, format, args...)
53 | Global.Close() // so that hopefully the messages get logged
54 | panic(fmt.Sprintf(format, args...))
55 | }
56 |
57 | // Compatibility with `log`
58 | func Exit(args ...interface{}) {
59 | if len(args) > 0 {
60 | Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
61 | }
62 | Global.Close() // so that hopefully the messages get logged
63 | os.Exit(0)
64 | }
65 |
66 | // Compatibility with `log`
67 | func Exitf(format string, args ...interface{}) {
68 | Global.intLogf(ERROR, format, args...)
69 | Global.Close() // so that hopefully the messages get logged
70 | os.Exit(0)
71 | }
72 |
73 | // Compatibility with `log`
74 | func Stderr(args ...interface{}) {
75 | if len(args) > 0 {
76 | Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
77 | }
78 | }
79 |
80 | // Compatibility with `log`
81 | func Stderrf(format string, args ...interface{}) {
82 | Global.intLogf(ERROR, format, args...)
83 | }
84 |
85 | // Compatibility with `log`
86 | func Stdout(args ...interface{}) {
87 | if len(args) > 0 {
88 | Global.intLogf(INFO, strings.Repeat(" %v", len(args))[1:], args...)
89 | }
90 | }
91 |
92 | // Compatibility with `log`
93 | func Stdoutf(format string, args ...interface{}) {
94 | Global.intLogf(INFO, format, args...)
95 | }
96 |
97 | // Send a log message manually
98 | // Wrapper for (*Logger).Log
99 | func Log(lvl level, source, message string) {
100 | Global.Log(lvl, source, message)
101 | }
102 |
103 | // Send a formatted log message easily
104 | // Wrapper for (*Logger).Logf
105 | func Logf(lvl level, format string, args ...interface{}) {
106 | Global.intLogf(lvl, format, args...)
107 | }
108 |
109 | // Send a closure log message
110 | // Wrapper for (*Logger).Logc
111 | func Logc(lvl level, closure func() string) {
112 | Global.intLogc(lvl, closure)
113 | }
114 |
115 | // Utility for finest log messages (see Debug() for parameter explanation)
116 | // Wrapper for (*Logger).Finest
117 | func Finest(arg0 interface{}, args ...interface{}) {
118 | const (
119 | lvl = FINEST
120 | )
121 | switch first := arg0.(type) {
122 | case string:
123 | // Use the string as a format string
124 | Global.intLogf(lvl, first, args...)
125 | case func() string:
126 | // Log the closure (no other arguments used)
127 | Global.intLogc(lvl, first)
128 | default:
129 | // Build a format string so that it will be similar to Sprint
130 | Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
131 | }
132 | }
133 |
134 | // Utility for fine log messages (see Debug() for parameter explanation)
135 | // Wrapper for (*Logger).Fine
136 | func Fine(arg0 interface{}, args ...interface{}) {
137 | const (
138 | lvl = FINE
139 | )
140 | switch first := arg0.(type) {
141 | case string:
142 | // Use the string as a format string
143 | Global.intLogf(lvl, first, args...)
144 | case func() string:
145 | // Log the closure (no other arguments used)
146 | Global.intLogc(lvl, first)
147 | default:
148 | // Build a format string so that it will be similar to Sprint
149 | Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
150 | }
151 | }
152 |
153 | // Utility for debug log messages
154 | // When given a string as the first argument, this behaves like Logf but with the DEBUG log level (e.g. the first argument is interpreted as a format for the latter arguments)
155 | // When given a closure of type func()string, this logs the string returned by the closure iff it will be logged. The closure runs at most one time.
156 | // When given anything else, the log message will be each of the arguments formatted with %v and separated by spaces (ala Sprint).
157 | // Wrapper for (*Logger).Debug
158 | func Debug(arg0 interface{}, args ...interface{}) {
159 | const (
160 | lvl = DEBUG
161 | )
162 | switch first := arg0.(type) {
163 | case string:
164 | // Use the string as a format string
165 | Global.intLogf(lvl, first, args...)
166 | case func() string:
167 | // Log the closure (no other arguments used)
168 | Global.intLogc(lvl, first)
169 | default:
170 | // Build a format string so that it will be similar to Sprint
171 | Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
172 | }
173 | }
174 |
175 | // Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
176 | // These functions will execute a closure exactly once, to build the error message for the return
177 | // Wrapper for (*Logger).Error
178 | func DebugLog(logname string, arg0 interface{}, args ...interface{}) error {
179 | const (
180 | lvl = DEBUG
181 | )
182 | switch first := arg0.(type) {
183 | case string:
184 | // Use the string as a format string
185 | Global.intLogNamef(logname, lvl, first, args...)
186 | case func() string:
187 | // Log the closure (no other arguments used)
188 | Global.intLogNamec(logname, lvl, first)
189 | default:
190 | // Build a format string so that it will be similar to Sprint
191 | Global.intLogNamef(logname, lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
192 | }
193 | return nil
194 | }
195 |
196 | // Utility for trace log messages (see Debug() for parameter explanation)
197 | // Wrapper for (*Logger).Trace
198 | func Trace(arg0 interface{}, args ...interface{}) {
199 | const (
200 | lvl = TRACE
201 | )
202 | switch first := arg0.(type) {
203 | case string:
204 | // Use the string as a format string
205 | Global.intLogf(lvl, first, args...)
206 | case func() string:
207 | // Log the closure (no other arguments used)
208 | Global.intLogc(lvl, first)
209 | default:
210 | // Build a format string so that it will be similar to Sprint
211 | Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
212 | }
213 | }
214 |
215 | func TraceLog(logname string, arg0 interface{}, args ...interface{}) {
216 | const (
217 | lvl = TRACE
218 | )
219 | switch first := arg0.(type) {
220 | case string:
221 | // Use the string as a format string
222 | Global.intLogNamef(logname, lvl, first, args...)
223 | case func() string:
224 | // Log the closure (no other arguments used)
225 | Global.intLogNamec(logname, lvl, first)
226 | default:
227 | // Build a format string so that it will be similar to Sprint
228 | Global.intLogNamef(logname, lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
229 | }
230 |
231 | }
232 |
233 | // Utility for info log messages (see Debug() for parameter explanation)
234 | // Wrapper for (*Logger).Info
235 | func Info(arg0 interface{}, args ...interface{}) {
236 | const (
237 | lvl = INFO
238 | )
239 | switch first := arg0.(type) {
240 | case string:
241 | // Use the string as a format string
242 | Global.intLogf(lvl, first, args...)
243 | case func() string:
244 | // Log the closure (no other arguments used)
245 | Global.intLogc(lvl, first)
246 | default:
247 | // Build a format string so that it will be similar to Sprint
248 | Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
249 | }
250 | }
251 |
252 | func InfoLog(logname string, arg0 interface{}, args ...interface{}) {
253 | const (
254 | lvl = INFO
255 | )
256 | switch first := arg0.(type) {
257 | case string:
258 | // Use the string as a format string
259 | Global.intLogNamef(logname, lvl, first, args...)
260 | case func() string:
261 | // Log the closure (no other arguments used)
262 | Global.intLogNamec(logname, lvl, first)
263 | default:
264 | // Build a format string so that it will be similar to Sprint
265 | Global.intLogNamef(logname, lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
266 | }
267 |
268 | }
269 |
270 | // Utility for warn log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
271 | // These functions will execute a closure exactly once, to build the error message for the return
272 | // Wrapper for (*Logger).Warn
273 | func Warn(arg0 interface{}, args ...interface{}) error {
274 | const (
275 | lvl = WARNING
276 | )
277 | switch first := arg0.(type) {
278 | case string:
279 | // Use the string as a format string
280 | Global.intLogf(lvl, first, args...)
281 | return errors.New(fmt.Sprintf(first, args...))
282 | case func() string:
283 | // Log the closure (no other arguments used)
284 | str := first()
285 | Global.intLogf(lvl, "%s", str)
286 | return errors.New(str)
287 | default:
288 | // Build a format string so that it will be similar to Sprint
289 | Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
290 | return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
291 | }
292 | return nil
293 | }
294 |
295 | func WarnLog(logname string, arg0 interface{}, args ...interface{}) error {
296 | const (
297 | lvl = WARNING
298 | )
299 | switch first := arg0.(type) {
300 | case string:
301 | // Use the string as a format string
302 | Global.intLogNamef(logname, lvl, first, args...)
303 | return errors.New(fmt.Sprintf(first, args...))
304 | case func() string:
305 | // Log the closure (no other arguments used)
306 | str := first()
307 | Global.intLogNamef(logname, lvl, "%s", str)
308 | return errors.New(str)
309 | default:
310 | // Build a format string so that it will be similar to Sprint
311 | Global.intLogNamef(logname, lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
312 | return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
313 | }
314 | return nil
315 | }
316 |
317 | // Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
318 | // These functions will execute a closure exactly once, to build the error message for the return
319 | // Wrapper for (*Logger).Error
320 | func Error(arg0 interface{}, args ...interface{}) error {
321 | const (
322 | lvl = ERROR
323 | )
324 | switch first := arg0.(type) {
325 | case string:
326 | // Use the string as a format string
327 | Global.intLogf(lvl, first, args...)
328 | return errors.New(fmt.Sprintf(first, args...))
329 | case func() string:
330 | // Log the closure (no other arguments used)
331 | str := first()
332 | Global.intLogf(lvl, "%s", str)
333 | return errors.New(str)
334 | default:
335 | // Build a format string so that it will be similar to Sprint
336 | Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
337 | return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
338 | }
339 | return nil
340 | }
341 |
342 | // Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
343 | // These functions will execute a closure exactly once, to build the error message for the return
344 | // Wrapper for (*Logger).Error
345 | func ErrorLog(logname string, arg0 interface{}, args ...interface{}) error {
346 | const (
347 | lvl = ERROR
348 | )
349 | switch first := arg0.(type) {
350 | case string:
351 | // Use the string as a format string
352 | Global.intLogNamef(logname, lvl, first, args...)
353 | return errors.New(fmt.Sprintf(first, args...))
354 | case func() string:
355 | // Log the closure (no other arguments used)
356 | str := first()
357 | Global.intLogNamef(logname, lvl, "%s", str)
358 | return errors.New(str)
359 | default:
360 | // Build a format string so that it will be similar to Sprint
361 | Global.intLogNamef(logname, lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
362 | return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
363 | }
364 | return nil
365 | }
366 |
367 | // Utility for critical log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
368 | // These functions will execute a closure exactly once, to build the error message for the return
369 | // Wrapper for (*Logger).Critical
370 | func Critical(arg0 interface{}, args ...interface{}) error {
371 | const (
372 | lvl = CRITICAL
373 | )
374 | switch first := arg0.(type) {
375 | case string:
376 | // Use the string as a format string
377 | Global.intLogf(lvl, first, args...)
378 | return errors.New(fmt.Sprintf(first, args...))
379 | case func() string:
380 | // Log the closure (no other arguments used)
381 | str := first()
382 | Global.intLogf(lvl, "%s", str)
383 | return errors.New(str)
384 | default:
385 | // Build a format string so that it will be similar to Sprint
386 | Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
387 | return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
388 | }
389 | return nil
390 | }
391 |
392 | func CriticalLog(logname string, arg0 interface{}, args ...interface{}) error {
393 | const (
394 | lvl = CRITICAL
395 | )
396 | switch first := arg0.(type) {
397 | case string:
398 | // Use the string as a format string
399 | Global.intLogNamef(logname, lvl, first, args...)
400 | return errors.New(fmt.Sprintf(first, args...))
401 | case func() string:
402 | // Log the closure (no other arguments used)
403 | str := first()
404 | Global.intLogNamef(logname, lvl, "%s", str)
405 | return errors.New(str)
406 | default:
407 | // Build a format string so that it will be similar to Sprint
408 | Global.intLogNamef(logname, lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
409 | return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
410 | }
411 | return nil
412 | }
413 |
--------------------------------------------------------------------------------
/log4go.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | // Package log4go provides level-based and highly configurable logging.
4 | //
5 | // Enhanced Logging
6 | //
7 | // This is inspired by the logging functionality in Java. Essentially, you create a Logger
8 | // object and create output filters for it. You can send whatever you want to the Logger,
9 | // and it will filter that based on your settings and send it to the outputs. This way, you
10 | // can put as much debug code in your program as you want, and when you're done you can filter
11 | // out the mundane messages so only the important ones show up.
12 | //
13 | // Utility functions are provided to make life easier. Here is some example code to get started:
14 | //
15 | // log := log4go.NewLogger()
16 | // log.AddFilter("stdout", log4go.DEBUG, log4go.NewConsoleLogWriter())
17 | // log.AddFilter("log", log4go.FINE, log4go.NewFileLogWriter("example.log", true))
18 | // log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
19 | //
20 | // The first two lines can be combined with the utility NewDefaultLogger:
21 | //
22 | // log := log4go.NewDefaultLogger(log4go.DEBUG)
23 | // log.AddFilter("log", log4go.FINE, log4go.NewFileLogWriter("example.log", true))
24 | // log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
25 | //
26 | // Usage notes:
27 | // - The ConsoleLogWriter does not display the source of the message to standard
28 | // output, but the FileLogWriter does.
29 | // - The utility functions (Info, Debug, Warn, etc) derive their source from the
30 | // calling function, and this incurs extra overhead.
31 | //
32 | // Changes from 2.0:
33 | // - The external interface has remained mostly stable, but a lot of the
34 | // internals have been changed, so if you depended on any of this or created
35 | // your own LogWriter, then you will probably have to update your code. In
36 | // particular, Logger is now a map and ConsoleLogWriter is now a channel
37 | // behind-the-scenes, and the LogWrite method no longer has return values.
38 | //
39 | // Future work: (please let me know if you think I should work on any of these particularly)
40 | // - Log file rotation
41 | // - Logging configuration files ala log4j
42 | // - Have the ability to remove filters?
43 | // - Have GetInfoChannel, GetDebugChannel, etc return a chan string that allows
44 | // for another method of logging
45 | // - Add an XML filter type
46 | package log4go
47 |
48 | import (
49 | "errors"
50 | "fmt"
51 | "github.com/prometheus/client_golang/prometheus"
52 | "os"
53 | "runtime"
54 | "strings"
55 | "time"
56 | )
57 |
58 | // Version information
59 | const (
60 | L4G_VERSION = "log4go-v3.0.1"
61 | L4G_MAJOR = 3
62 | L4G_MINOR = 0
63 | L4G_BUILD = 1
64 | )
65 |
66 | var (
67 | loglevelCounter *prometheus.CounterVec
68 | )
69 |
70 | func init() {
71 | loglevelCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
72 | Name: "log_level_total",
73 | Help: "Total number of a specified loglevel",
74 | }, []string{"level"})
75 |
76 | for _, levelString := range levelStrings {
77 | loglevelCounter.WithLabelValues(levelString)
78 | }
79 | err := prometheus.Register(loglevelCounter)
80 | if err != nil {
81 | panic(err)
82 | }
83 | }
84 |
85 | /****** Constants ******/
86 |
87 | // These are the integer logging levels used by the logger
88 | type level int
89 |
90 | const (
91 | FINEST level = iota
92 | FINE
93 | DEBUG
94 | TRACE
95 | INFO
96 | WARNING
97 | ERROR
98 | CRITICAL
99 | )
100 |
101 | // Logging level strings
102 | var (
103 | levelStrings = [...]string{"FNST", "FINE", "DEBG", "TRAC", "INFO", "WARN", "EROR", "CRIT"}
104 | )
105 |
106 | func (l level) String() string {
107 | if l < 0 || int(l) > len(levelStrings) {
108 | return "UNKNOWN"
109 | }
110 | return levelStrings[int(l)]
111 | }
112 |
113 | /****** Variables ******/
114 | var (
115 | // LogBufferLength specifies how many log messages a particular log4go
116 | // logger can buffer at a time before writing them.
117 | LogBufferLength = 32
118 | )
119 |
120 | /****** LogRecord ******/
121 |
122 | // A LogRecord contains all of the pertinent information for each message
123 | type LogRecord struct {
124 | Level level // The log level
125 | Created time.Time // The time at which the log message was created (nanoseconds)
126 | Source string // The message source
127 | Message string // The log message
128 | }
129 |
130 | /****** LogWriter ******/
131 |
132 | // This is an interface for anything that should be able to write logs
133 | type LogWriter interface {
134 | // This will be called to log a LogRecord message.
135 | LogWrite(rec *LogRecord)
136 |
137 | // This should clean up anything lingering about the LogWriter, as it is called before
138 | // the LogWriter is removed. LogWrite should not be called after Close.
139 | Close()
140 | }
141 |
142 | /****** Logger ******/
143 |
144 | // A Filter represents the log level below which no log records are written to
145 | // the associated LogWriter.
146 | type Filter struct {
147 | Level level
148 | Path string
149 | LogWriter
150 | }
151 |
152 | // A Logger represents a collection of Filters through which log messages are
153 | // written.
154 | type Logger map[string]*Filter
155 |
156 | // Create a new logger.
157 | //
158 | // DEPRECATED: Use make(Logger) instead.
159 | func NewLogger() Logger {
160 | os.Stderr.WriteString("warning: use of deprecated NewLogger\n")
161 | return make(Logger)
162 | }
163 |
164 | // Create a new logger with a "stdout" filter configured to send log messages at
165 | // or above lvl to standard output.
166 | //
167 | // DEPRECATED: use NewDefaultLogger instead.
168 | func NewConsoleLogger(lvl level) Logger {
169 | os.Stderr.WriteString("warning: use of deprecated NewConsoleLogger\n")
170 | return Logger{
171 | "stdout": &Filter{lvl, "./logs/stdout.log", NewConsoleLogWriter()},
172 | }
173 | }
174 |
175 | // Create a new logger with a "stdout" filter configured to send log messages at
176 | // or above lvl to standard output.
177 | func NewDefaultLogger(lvl level) Logger {
178 | return Logger{
179 | "stdout": &Filter{lvl, "./logs/stdout.log", NewConsoleLogWriter()},
180 | }
181 | }
182 |
183 | // Closes all log writers in preparation for exiting the program or a
184 | // reconfiguration of logging. Calling this is not really imperative, unless
185 | // you want to guarantee that all log messages are written. Close removes
186 | // all filters (and thus all LogWriters) from the logger.
187 | func (log Logger) Close() {
188 | // Close all open loggers
189 | for name, filt := range log {
190 | filt.Close()
191 | delete(log, name)
192 | }
193 | }
194 |
195 | // Add a new LogWriter to the Logger which will only log messages at lvl or
196 | // higher. This function should not be called from multiple goroutines.
197 | // Returns the logger for chaining.
198 | func (log Logger) AddFilter(name string, lvl level, writer LogWriter) Logger {
199 | log[name] = &Filter{lvl, "./logs/" + name + ".log", writer}
200 | return log
201 | }
202 |
203 | /******* Logging *******/
204 | // Send a formatted log message internally
205 | func (log Logger) intLogf(lvl level, format string, args ...interface{}) {
206 | log.intLogNamef(logName(lvl), lvl, format, args...)
207 | }
208 |
209 | // Send a closure log message internally
210 | func (log Logger) intLogc(lvl level, closure func() string) {
211 |
212 | log.intLogNamec(logName(lvl), lvl, closure)
213 | }
214 |
215 | func logName(lvl level) string {
216 | return "stdout"
217 | }
218 |
219 | // Send a log message with manual level, source, and message.
220 | func (log Logger) Log(lvl level, source, message string) {
221 | log.intLogNamef(logName(lvl), lvl, message)
222 | }
223 |
224 | func (log Logger) getLogger(logname string, lvl level) (*Filter, bool) {
225 | l, ok := log[logname]
226 | if !ok {
227 | //use stdout
228 | l, ok = log["stdout"]
229 | }
230 | return l, ok
231 | }
232 |
233 | // Send a formatted log message internally
234 | func (log Logger) intLogNamef(logname string, lvl level, format string, args ...interface{}) {
235 |
236 | loglevelCounter.WithLabelValues(lvl.String()).Inc()
237 |
238 | l, ok := log.getLogger(logname, lvl)
239 | //log level less than filter level ignored
240 | if !ok || lvl < l.Level {
241 | return
242 | }
243 |
244 | // Determine caller func
245 | pc, _, lineno, ok := runtime.Caller(2)
246 | src := ""
247 | if ok {
248 | src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
249 | }
250 |
251 | msg := format
252 | if len(args) > 0 {
253 | msg = fmt.Sprintf(format, args...)
254 | }
255 |
256 | // Make the log record
257 | rec := &LogRecord{
258 | Level: lvl,
259 | Created: time.Now(),
260 | Source: src,
261 | Message: msg,
262 | }
263 |
264 | // Dispatch the logs
265 | l.LogWrite(rec)
266 | }
267 |
268 | // Send a closure log message internally
269 | func (log Logger) intLogNamec(logname string, lvl level, closure func() string) {
270 | l, ok := log.getLogger(logname, lvl)
271 |
272 | //log level less than filter level ignored
273 | if !ok || lvl < l.Level {
274 | return
275 | }
276 |
277 | // Determine caller func
278 | pc, _, lineno, ok := runtime.Caller(2)
279 | src := ""
280 | if ok {
281 | src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
282 | }
283 |
284 | // Make the log record
285 | rec := &LogRecord{
286 | Level: lvl,
287 | Created: time.Now(),
288 | Source: src,
289 | Message: closure(),
290 | }
291 |
292 | // Dispatch the logs
293 | l.LogWrite(rec)
294 | }
295 |
296 | // Logf logs a formatted log message at the given log level, using the caller as
297 | // its source.
298 | func (log Logger) Logf(lvl level, format string, args ...interface{}) {
299 | log.intLogf(lvl, format, args...)
300 | }
301 |
302 | // Logc logs a string returned by the closure at the given log level, using the caller as
303 | // its source. If no log message would be written, the closure is never called.
304 | func (log Logger) Logc(lvl level, closure func() string) {
305 | log.intLogc(lvl, closure)
306 | }
307 |
308 | // Finest logs a message at the finest log level.
309 | // See Debug for an explanation of the arguments.
310 | func (log Logger) Finest(arg0 interface{}, args ...interface{}) {
311 | const (
312 | lvl = FINEST
313 | )
314 | switch first := arg0.(type) {
315 | case string:
316 | // Use the string as a format string
317 | log.intLogf(lvl, first, args...)
318 | case func() string:
319 | // Log the closure (no other arguments used)
320 | log.intLogc(lvl, first)
321 | default:
322 | // Build a format string so that it will be similar to Sprint
323 | log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
324 | }
325 | }
326 |
327 | // Fine logs a message at the fine log level.
328 | // See Debug for an explanation of the arguments.
329 | func (log Logger) Fine(arg0 interface{}, args ...interface{}) {
330 | const (
331 | lvl = FINE
332 | )
333 | switch first := arg0.(type) {
334 | case string:
335 | // Use the string as a format string
336 | log.intLogf(lvl, first, args...)
337 | case func() string:
338 | // Log the closure (no other arguments used)
339 | log.intLogc(lvl, first)
340 | default:
341 | // Build a format string so that it will be similar to Sprint
342 | log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
343 | }
344 | }
345 |
346 | // Debug is a utility method for debug log messages.
347 | // The behavior of Debug depends on the first argument:
348 | // - arg0 is a string
349 | // When given a string as the first argument, this behaves like Logf but with
350 | // the DEBUG log level: the first argument is interpreted as a format for the
351 | // latter arguments.
352 | // - arg0 is a func()string
353 | // When given a closure of type func()string, this logs the string returned by
354 | // the closure iff it will be logged. The closure runs at most one time.
355 | // - arg0 is interface{}
356 | // When given anything else, the log message will be each of the arguments
357 | // formatted with %v and separated by spaces (ala Sprint).
358 | func (log Logger) Debug(arg0 interface{}, args ...interface{}) {
359 | const (
360 | lvl = DEBUG
361 | )
362 | switch first := arg0.(type) {
363 | case string:
364 | // Use the string as a format string
365 | log.intLogf(lvl, first, args...)
366 | case func() string:
367 | // Log the closure (no other arguments used)
368 | log.intLogc(lvl, first)
369 | default:
370 | // Build a format string so that it will be similar to Sprint
371 | log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
372 | }
373 | }
374 |
375 | // Trace logs a message at the trace log level.
376 | // See Debug for an explanation of the arguments.
377 | func (log Logger) Trace(arg0 interface{}, args ...interface{}) {
378 | const (
379 | lvl = TRACE
380 | )
381 | switch first := arg0.(type) {
382 | case string:
383 | // Use the string as a format string
384 | log.intLogf(lvl, first, args...)
385 | case func() string:
386 | // Log the closure (no other arguments used)
387 | log.intLogc(lvl, first)
388 | default:
389 | // Build a format string so that it will be similar to Sprint
390 | log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
391 | }
392 | }
393 |
394 | // Info logs a message at the info log level.
395 | // See Debug for an explanation of the arguments.
396 | func (log Logger) Info(arg0 interface{}, args ...interface{}) {
397 | const (
398 | lvl = INFO
399 | )
400 | switch first := arg0.(type) {
401 | case string:
402 | // Use the string as a format string
403 | log.intLogf(lvl, first, args...)
404 | case func() string:
405 | // Log the closure (no other arguments used)
406 | log.intLogc(lvl, first)
407 | default:
408 | // Build a format string so that it will be similar to Sprint
409 | log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
410 | }
411 | }
412 |
413 | // Warn logs a message at the warning log level and returns the formatted error.
414 | // At the warning level and higher, there is no performance benefit if the
415 | // message is not actually logged, because all formats are processed and all
416 | // closures are executed to format the error message.
417 | // See Debug for further explanation of the arguments.
418 | func (log Logger) Warn(arg0 interface{}, args ...interface{}) error {
419 | const (
420 | lvl = WARNING
421 | )
422 | var msg string
423 | switch first := arg0.(type) {
424 | case string:
425 | // Use the string as a format string
426 | msg = fmt.Sprintf(first, args...)
427 | case func() string:
428 | // Log the closure (no other arguments used)
429 | msg = first()
430 | default:
431 | // Build a format string so that it will be similar to Sprint
432 | msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
433 | }
434 | log.intLogf(lvl, msg)
435 | return errors.New(msg)
436 | }
437 |
438 | // Error logs a message at the error log level and returns the formatted error,
439 | // See Warn for an explanation of the performance and Debug for an explanation
440 | // of the parameters.
441 | func (log Logger) Error(arg0 interface{}, args ...interface{}) error {
442 | const (
443 | lvl = ERROR
444 | )
445 | var msg string
446 | switch first := arg0.(type) {
447 | case string:
448 | // Use the string as a format string
449 | msg = fmt.Sprintf(first, args...)
450 | case func() string:
451 | // Log the closure (no other arguments used)
452 | msg = first()
453 | default:
454 | // Build a format string so that it will be similar to Sprint
455 | msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
456 | }
457 | log.intLogf(lvl, msg)
458 | return errors.New(msg)
459 | }
460 |
461 | // Critical logs a message at the critical log level and returns the formatted error,
462 | // See Warn for an explanation of the performance and Debug for an explanation
463 | // of the parameters.
464 | func (log Logger) Critical(arg0 interface{}, args ...interface{}) error {
465 | const (
466 | lvl = CRITICAL
467 | )
468 | var msg string
469 | switch first := arg0.(type) {
470 | case string:
471 | // Use the string as a format string
472 | msg = fmt.Sprintf(first, args...)
473 | case func() string:
474 | // Log the closure (no other arguments used)
475 | msg = first()
476 | default:
477 | // Build a format string so that it will be similar to Sprint
478 | msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
479 | }
480 | log.intLogf(lvl, msg)
481 | return errors.New(msg)
482 | }
483 |
--------------------------------------------------------------------------------
/log4go_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2010, Kyle Lemons . All rights reserved.
2 |
3 | package log4go
4 |
5 | import (
6 | "crypto/md5"
7 | "encoding/hex"
8 | "fmt"
9 | "io"
10 | "io/ioutil"
11 | "os"
12 | "runtime"
13 | "testing"
14 | "time"
15 | )
16 |
17 | const testLogFile = "_logtest.log"
18 |
19 | var now time.Time = time.Unix(0, 1234567890123456789).In(time.UTC)
20 |
21 | func newLogRecord(lvl level, src string, msg string) *LogRecord {
22 | return &LogRecord{
23 | Level: lvl,
24 | Source: src,
25 | Created: now,
26 | Message: msg,
27 | }
28 | }
29 |
30 | func TestELog(t *testing.T) {
31 | fmt.Printf("Testing %s\n", L4G_VERSION)
32 | lr := newLogRecord(CRITICAL, "source", "message")
33 | if lr.Level != CRITICAL {
34 | t.Errorf("Incorrect level: %d should be %d", lr.Level, CRITICAL)
35 | }
36 | if lr.Source != "source" {
37 | t.Errorf("Incorrect source: %s should be %s", lr.Source, "source")
38 | }
39 | if lr.Message != "message" {
40 | t.Errorf("Incorrect message: %s should be %s", lr.Source, "message")
41 | }
42 | }
43 |
44 | var formatTests = []struct {
45 | Test string
46 | Record *LogRecord
47 | Formats map[string]string
48 | }{
49 | {
50 | Test: "Standard formats",
51 | Record: &LogRecord{
52 | Level: ERROR,
53 | Source: "source",
54 | Message: "message",
55 | Created: now,
56 | },
57 | Formats: map[string]string{
58 | // TODO(kevlar): How can I do this so it'll work outside of PST?
59 | FORMAT_DEFAULT: "[2009/02/13 23:31:30 UTC] [EROR] (source) message\n",
60 | FORMAT_SHORT: "[23:31 02/13/09] [EROR] message\n",
61 | FORMAT_ABBREV: "[EROR] message\n",
62 | },
63 | },
64 | }
65 |
66 | func TestFormatLogRecord(t *testing.T) {
67 | for _, test := range formatTests {
68 | name := test.Test
69 | for fmt, want := range test.Formats {
70 | if got := FormatLogRecord(fmt, test.Record); got != want {
71 | t.Errorf("%s - %s:", name, fmt)
72 | t.Errorf(" got %q", got)
73 | t.Errorf(" want %q", want)
74 | }
75 | }
76 | }
77 | }
78 |
79 | var logRecordWriteTests = []struct {
80 | Test string
81 | Record *LogRecord
82 | Console string
83 | }{
84 | {
85 | Test: "Normal message",
86 | Record: &LogRecord{
87 | Level: CRITICAL,
88 | Source: "source",
89 | Message: "message",
90 | Created: now,
91 | },
92 | Console: "[02/13/09 23:31:30] [CRIT] message\n",
93 | },
94 | }
95 |
96 | func TestConsoleLogWriter(t *testing.T) {
97 | console := make(ConsoleLogWriter)
98 |
99 | r, w := io.Pipe()
100 | go console.run(w)
101 | defer console.Close()
102 |
103 | buf := make([]byte, 1024)
104 |
105 | for _, test := range logRecordWriteTests {
106 | name := test.Test
107 |
108 | console.LogWrite(test.Record)
109 | n, _ := r.Read(buf)
110 |
111 | if got, want := string(buf[:n]), test.Console; got != want {
112 | t.Errorf("%s: got %q", name, got)
113 | t.Errorf("%s: want %q", name, want)
114 | }
115 | }
116 | }
117 |
118 | func TestFileLogWriter(t *testing.T) {
119 | defer func(buflen int) {
120 | LogBufferLength = buflen
121 | }(LogBufferLength)
122 | LogBufferLength = 0
123 |
124 | w := NewFileLogWriter(testLogFile, false, true)
125 | if w == nil {
126 | t.Fatalf("Invalid return: w should not be nil")
127 | }
128 | defer os.Remove(testLogFile)
129 |
130 | w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
131 | w.Close()
132 | runtime.Gosched()
133 |
134 | if contents, err := ioutil.ReadFile(testLogFile); err != nil {
135 | t.Errorf("read(%q): %s", testLogFile, err)
136 | } else if len(contents) != 50 {
137 | t.Errorf("malformed filelog: %q (%d bytes)", string(contents), len(contents))
138 | }
139 | }
140 |
141 | func TestXMLLogWriter(t *testing.T) {
142 | defer func(buflen int) {
143 | LogBufferLength = buflen
144 | }(LogBufferLength)
145 | LogBufferLength = 0
146 |
147 | w := NewXMLLogWriter(testLogFile, false, true)
148 | if w == nil {
149 | t.Fatalf("Invalid return: w should not be nil")
150 | }
151 | defer os.Remove(testLogFile)
152 |
153 | w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
154 | w.Close()
155 | runtime.Gosched()
156 |
157 | if contents, err := ioutil.ReadFile(testLogFile); err != nil {
158 | t.Errorf("read(%q): %s", testLogFile, err)
159 | } else if len(contents) != 185 {
160 | t.Errorf("malformed xmllog: %q (%d bytes)", string(contents), len(contents))
161 | }
162 | }
163 |
164 | func TestLogger(t *testing.T) {
165 | sl := NewDefaultLogger(WARNING)
166 | if sl == nil {
167 | t.Fatalf("NewDefaultLogger should never return nil")
168 | }
169 | if lw, exist := sl["stdout"]; lw == nil || exist != true {
170 | t.Fatalf("NewDefaultLogger produced invalid logger (DNE or nil)")
171 | }
172 | if sl["stdout"].Level != WARNING {
173 | t.Fatalf("NewDefaultLogger produced invalid logger (incorrect level)")
174 | }
175 | if len(sl) != 1 {
176 | t.Fatalf("NewDefaultLogger produced invalid logger (incorrect map count)")
177 | }
178 |
179 | //func (l *Logger) AddFilter(name string, level int, writer LogWriter) {}
180 | l := make(Logger)
181 | l.AddFilter("stdout", DEBUG, NewConsoleLogWriter())
182 | if lw, exist := l["stdout"]; lw == nil || exist != true {
183 | t.Fatalf("AddFilter produced invalid logger (DNE or nil)")
184 | }
185 | if l["stdout"].Level != DEBUG {
186 | t.Fatalf("AddFilter produced invalid logger (incorrect level)")
187 | }
188 | if len(l) != 1 {
189 | t.Fatalf("AddFilter produced invalid logger (incorrect map count)")
190 | }
191 |
192 | //func (l *Logger) Warn(format string, args ...interface{}) error {}
193 | if err := l.Warn("%s %d %#v", "Warning:", 1, []int{}); err.Error() != "Warning: 1 []int{}" {
194 | t.Errorf("Warn returned invalid error: %s", err)
195 | }
196 |
197 | //func (l *Logger) Error(format string, args ...interface{}) error {}
198 | if err := l.Error("%s %d %#v", "Error:", 10, []string{}); err.Error() != "Error: 10 []string{}" {
199 | t.Errorf("Error returned invalid error: %s", err)
200 | }
201 |
202 | //func (l *Logger) Critical(format string, args ...interface{}) error {}
203 | if err := l.Critical("%s %d %#v", "Critical:", 100, []int64{}); err.Error() != "Critical: 100 []int64{}" {
204 | t.Errorf("Critical returned invalid error: %s", err)
205 | }
206 |
207 | // Already tested or basically untestable
208 | //func (l *Logger) Log(level int, source, message string) {}
209 | //func (l *Logger) Logf(level int, format string, args ...interface{}) {}
210 | //func (l *Logger) intLogf(level int, format string, args ...interface{}) string {}
211 | //func (l *Logger) Finest(format string, args ...interface{}) {}
212 | //func (l *Logger) Fine(format string, args ...interface{}) {}
213 | //func (l *Logger) Debug(format string, args ...interface{}) {}
214 | //func (l *Logger) Trace(format string, args ...interface{}) {}
215 | //func (l *Logger) Info(format string, args ...interface{}) {}
216 | }
217 |
218 | func TestLogOutput(t *testing.T) {
219 | const (
220 | expected = "fdf3e51e444da56b4cb400f30bc47424"
221 | )
222 |
223 | // Unbuffered output
224 | defer func(buflen int) {
225 | LogBufferLength = buflen
226 | }(LogBufferLength)
227 | LogBufferLength = 0
228 |
229 | l := make(Logger)
230 |
231 | // Delete and open the output log without a timestamp (for a constant md5sum)
232 | l.AddFilter("file", FINEST, NewFileLogWriter(testLogFile, false, true).SetFormat("[%L] %M"))
233 | defer os.Remove(testLogFile)
234 |
235 | // Send some log messages
236 | l.Log(CRITICAL, "testsrc1", fmt.Sprintf("This message is level %d", int(CRITICAL)))
237 | l.Logf(ERROR, "This message is level %v", ERROR)
238 | l.Logf(WARNING, "This message is level %s", WARNING)
239 | l.Logc(INFO, func() string { return "This message is level INFO" })
240 | l.Trace("This message is level %d", int(TRACE))
241 | l.Debug("This message is level %s", DEBUG)
242 | l.Fine(func() string { return fmt.Sprintf("This message is level %v", FINE) })
243 | l.Finest("This message is level %v", FINEST)
244 | l.Finest(FINEST, "is also this message's level")
245 |
246 | l.Close()
247 |
248 | contents, err := ioutil.ReadFile(testLogFile)
249 | if err != nil {
250 | t.Fatalf("Could not read output log: %s", err)
251 | }
252 |
253 | sum := md5.New()
254 | sum.Write(contents)
255 | if sumstr := hex.EncodeToString(sum.Sum(nil)); sumstr != expected {
256 | t.Errorf("--- Log Contents:\n%s---", string(contents))
257 | t.Fatalf("Checksum does not match: %s (expecting %s)", sumstr, expected)
258 | }
259 | }
260 |
261 | func TestCountMallocs(t *testing.T) {
262 | const N = 1
263 | var m runtime.MemStats
264 | getMallocs := func() uint64 {
265 | runtime.ReadMemStats(&m)
266 | return m.Mallocs
267 | }
268 |
269 | // Console logger
270 | sl := NewDefaultLogger(INFO)
271 | mallocs := 0 - getMallocs()
272 | for i := 0; i < N; i++ {
273 | sl.Log(WARNING, "here", "This is a WARNING message")
274 | }
275 | mallocs += getMallocs()
276 | fmt.Printf("mallocs per sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
277 |
278 | // Console logger formatted
279 | mallocs = 0 - getMallocs()
280 | for i := 0; i < N; i++ {
281 | sl.Logf(WARNING, "%s is a log message with level %d", "This", WARNING)
282 | }
283 | mallocs += getMallocs()
284 | fmt.Printf("mallocs per sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
285 |
286 | // Console logger (not logged)
287 | sl = NewDefaultLogger(INFO)
288 | mallocs = 0 - getMallocs()
289 | for i := 0; i < N; i++ {
290 | sl.Log(DEBUG, "here", "This is a DEBUG log message")
291 | }
292 | mallocs += getMallocs()
293 | fmt.Printf("mallocs per unlogged sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
294 |
295 | // Console logger formatted (not logged)
296 | mallocs = 0 - getMallocs()
297 | for i := 0; i < N; i++ {
298 | sl.Logf(DEBUG, "%s is a log message with level %d", "This", DEBUG)
299 | }
300 | mallocs += getMallocs()
301 | fmt.Printf("mallocs per unlogged sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
302 | }
303 |
304 | func TestXMLConfig(t *testing.T) {
305 | const (
306 | configfile = "example.xml"
307 | )
308 |
309 | fd, err := os.Create(configfile)
310 | if err != nil {
311 | t.Fatalf("Could not open %s for writing: %s", configfile, err)
312 | }
313 |
314 | fmt.Fprintln(fd, "")
315 | fmt.Fprintln(fd, " ")
316 | fmt.Fprintln(fd, " stdout")
317 | fmt.Fprintln(fd, " console")
318 | fmt.Fprintln(fd, " ")
319 | fmt.Fprintln(fd, " DEBUG")
320 | fmt.Fprintln(fd, " ")
321 | fmt.Fprintln(fd, " ")
322 | fmt.Fprintln(fd, " file")
323 | fmt.Fprintln(fd, " file")
324 | fmt.Fprintln(fd, " FINEST")
325 | fmt.Fprintln(fd, " test.log")
326 | fmt.Fprintln(fd, " ")
337 | fmt.Fprintln(fd, " [%D %T] [%L] (%S) %M")
338 | fmt.Fprintln(fd, " false ")
339 | fmt.Fprintln(fd, " 0M ")
340 | fmt.Fprintln(fd, " 0K ")
341 | fmt.Fprintln(fd, " true ")
342 | fmt.Fprintln(fd, " ")
343 | fmt.Fprintln(fd, " ")
344 | fmt.Fprintln(fd, " xmllog")
345 | fmt.Fprintln(fd, " xml")
346 | fmt.Fprintln(fd, " TRACE")
347 | fmt.Fprintln(fd, " trace.xml")
348 | fmt.Fprintln(fd, " true ")
349 | fmt.Fprintln(fd, " 100M ")
350 | fmt.Fprintln(fd, " 6K ")
351 | fmt.Fprintln(fd, " false ")
352 | fmt.Fprintln(fd, " ")
353 | fmt.Fprintln(fd, " ")
354 | fmt.Fprintln(fd, " donotopen")
355 | fmt.Fprintln(fd, " socket")
356 | fmt.Fprintln(fd, " FINEST")
357 | fmt.Fprintln(fd, " 192.168.1.255:12124 ")
358 | fmt.Fprintln(fd, " udp ")
359 | fmt.Fprintln(fd, " ")
360 | fmt.Fprintln(fd, "")
361 | fd.Close()
362 |
363 | log := make(Logger)
364 | log.LoadConfiguration(configfile)
365 | defer os.Remove("trace.xml")
366 | defer os.Remove("test.log")
367 | defer log.Close()
368 |
369 | // Make sure we got all loggers
370 | if len(log) != 3 {
371 | t.Fatalf("XMLConfig: Expected 3 filters, found %d", len(log))
372 | }
373 |
374 | // Make sure they're the right keys
375 | if _, ok := log["stdout"]; !ok {
376 | t.Errorf("XMLConfig: Expected stdout logger")
377 | }
378 | if _, ok := log["file"]; !ok {
379 | t.Fatalf("XMLConfig: Expected file logger")
380 | }
381 | if _, ok := log["xmllog"]; !ok {
382 | t.Fatalf("XMLConfig: Expected xmllog logger")
383 | }
384 |
385 | // Make sure they're the right type
386 | if _, ok := log["stdout"].LogWriter.(ConsoleLogWriter); !ok {
387 | t.Fatalf("XMLConfig: Expected stdout to be ConsoleLogWriter, found %T", log["stdout"].LogWriter)
388 | }
389 | if _, ok := log["file"].LogWriter.(*FileLogWriter); !ok {
390 | t.Fatalf("XMLConfig: Expected file to be *FileLogWriter, found %T", log["file"].LogWriter)
391 | }
392 | if _, ok := log["xmllog"].LogWriter.(*FileLogWriter); !ok {
393 | t.Fatalf("XMLConfig: Expected xmllog to be *FileLogWriter, found %T", log["xmllog"].LogWriter)
394 | }
395 |
396 | // Make sure levels are set
397 | if lvl := log["stdout"].Level; lvl != DEBUG {
398 | t.Errorf("XMLConfig: Expected stdout to be set to level %d, found %d", DEBUG, lvl)
399 | }
400 | if lvl := log["file"].Level; lvl != FINEST {
401 | t.Errorf("XMLConfig: Expected file to be set to level %d, found %d", FINEST, lvl)
402 | }
403 | if lvl := log["xmllog"].Level; lvl != TRACE {
404 | t.Errorf("XMLConfig: Expected xmllog to be set to level %d, found %d", TRACE, lvl)
405 | }
406 |
407 | // Make sure the w is open and points to the right file
408 | if fname := log["file"].LogWriter.(*FileLogWriter).file.Name(); fname != "test.log" {
409 | t.Errorf("XMLConfig: Expected file to have opened %s, found %s", "test.log", fname)
410 | }
411 |
412 | // Make sure the XLW is open and points to the right file
413 | if fname := log["xmllog"].LogWriter.(*FileLogWriter).file.Name(); fname != "trace.xml" {
414 | t.Errorf("XMLConfig: Expected xmllog to have opened %s, found %s", "trace.xml", fname)
415 | }
416 |
417 | // Move XML log file
418 | os.Rename(configfile, "examples/"+configfile) // Keep this so that an example with the documentation is available
419 | }
420 |
421 | func BenchmarkFormatLogRecord(b *testing.B) {
422 | const updateEvery = 1
423 | rec := &LogRecord{
424 | Level: CRITICAL,
425 | Created: now,
426 | Source: "source",
427 | Message: "message",
428 | }
429 | for i := 0; i < b.N; i++ {
430 | rec.Created = rec.Created.Add(1 * time.Second / updateEvery)
431 | if i%2 == 0 {
432 | FormatLogRecord(FORMAT_DEFAULT, rec)
433 | } else {
434 | FormatLogRecord(FORMAT_SHORT, rec)
435 | }
436 | }
437 | }
438 |
439 | func BenchmarkConsoleLog(b *testing.B) {
440 | /* This doesn't seem to work on OS X
441 | sink, err := os.Open(os.DevNull)
442 | if err != nil {
443 | panic(err)
444 | }
445 | if err := syscall.Dup2(int(sink.Fd()), syscall.Stdout); err != nil {
446 | panic(err)
447 | }
448 | */
449 |
450 | stdout = ioutil.Discard
451 | sl := NewDefaultLogger(INFO)
452 | for i := 0; i < b.N; i++ {
453 | sl.Log(WARNING, "here", "This is a log message")
454 | }
455 | }
456 |
457 | func BenchmarkConsoleNotLogged(b *testing.B) {
458 | sl := NewDefaultLogger(INFO)
459 | for i := 0; i < b.N; i++ {
460 | sl.Log(DEBUG, "here", "This is a log message")
461 | }
462 | }
463 |
464 | func BenchmarkConsoleUtilLog(b *testing.B) {
465 | sl := NewDefaultLogger(INFO)
466 | for i := 0; i < b.N; i++ {
467 | sl.Info("%s is a log message", "This")
468 | }
469 | }
470 |
471 | func BenchmarkConsoleUtilNotLog(b *testing.B) {
472 | sl := NewDefaultLogger(INFO)
473 | for i := 0; i < b.N; i++ {
474 | sl.Debug("%s is a log message", "This")
475 | }
476 | }
477 |
478 | func BenchmarkFileLog(b *testing.B) {
479 | sl := make(Logger)
480 | b.StopTimer()
481 | sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false, true))
482 | b.StartTimer()
483 | for i := 0; i < b.N; i++ {
484 | sl.Log(WARNING, "here", "This is a log message")
485 | }
486 | b.StopTimer()
487 | os.Remove("benchlog.log")
488 | }
489 |
490 | func BenchmarkFileNotLogged(b *testing.B) {
491 | sl := make(Logger)
492 | b.StopTimer()
493 | sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false, true))
494 | b.StartTimer()
495 | for i := 0; i < b.N; i++ {
496 | sl.Log(DEBUG, "here", "This is a log message")
497 | }
498 | b.StopTimer()
499 | os.Remove("benchlog.log")
500 | }
501 |
502 | func BenchmarkFileUtilLog(b *testing.B) {
503 | sl := make(Logger)
504 | b.StopTimer()
505 | sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false, true))
506 | b.StartTimer()
507 | for i := 0; i < b.N; i++ {
508 | sl.Info("%s is a log message", "This")
509 | }
510 | b.StopTimer()
511 | os.Remove("benchlog.log")
512 | }
513 |
514 | func BenchmarkFileUtilNotLog(b *testing.B) {
515 | sl := make(Logger)
516 | b.StopTimer()
517 | sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false, true))
518 | b.StartTimer()
519 | for i := 0; i < b.N; i++ {
520 | sl.Debug("%s is a log message", "This")
521 | }
522 | b.StopTimer()
523 | os.Remove("benchlog.log")
524 | }
525 |
526 | // Benchmark results (darwin amd64 6g)
527 | //elog.BenchmarkConsoleLog 100000 22819 ns/op
528 | //elog.BenchmarkConsoleNotLogged 2000000 879 ns/op
529 | //elog.BenchmarkConsoleUtilLog 50000 34380 ns/op
530 | //elog.BenchmarkConsoleUtilNotLog 1000000 1339 ns/op
531 | //elog.BenchmarkFileLog 100000 26497 ns/op
532 | //elog.BenchmarkFileNotLogged 2000000 821 ns/op
533 | //elog.BenchmarkFileUtilLog 50000 33945 ns/op
534 | //elog.BenchmarkFileUtilNotLog 1000000 1258 ns/op
535 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
16 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
17 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
18 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
19 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
20 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
21 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
22 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
23 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
24 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
25 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
26 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
27 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
28 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
29 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
30 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
31 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
32 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
33 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
34 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
35 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
36 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
37 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
38 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
39 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
40 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
41 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
42 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
43 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
44 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
45 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
46 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
47 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
48 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
49 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
50 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
51 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
52 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
53 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
54 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
56 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
57 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
58 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
59 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
60 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
61 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
62 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
63 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
64 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
65 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
66 | github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
67 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
68 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
69 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
70 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
71 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
72 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
73 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
74 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
75 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
76 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
77 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
78 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
79 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
80 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
81 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
82 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
83 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
84 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
85 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
86 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
87 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
88 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
89 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
90 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
91 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
92 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
93 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
94 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
95 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
96 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
97 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
98 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
99 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
100 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
101 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
102 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
103 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
104 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
105 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
106 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
107 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
108 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
109 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
110 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
111 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
112 | github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
113 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
114 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
115 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
116 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
117 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
118 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
119 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
120 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
121 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
122 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
123 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
124 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
125 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
126 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
127 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
128 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
129 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
130 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
131 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
132 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
133 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
134 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
135 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
136 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
137 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
138 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
139 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
140 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
141 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
142 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
143 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
144 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
145 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
146 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
147 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
148 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
149 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
150 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
151 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
152 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
153 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
154 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
155 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
156 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
157 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
158 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
159 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
160 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
161 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
162 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
163 | github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
164 | github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
165 | github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
166 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
167 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
168 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
169 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
170 | github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
171 | github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
172 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
173 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
174 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
175 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
176 | github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
177 | github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
178 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
179 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
180 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
181 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
182 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
183 | github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
184 | github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
185 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
186 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
187 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
188 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
189 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
190 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
191 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
192 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
193 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
194 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
195 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
196 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
197 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
198 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
199 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
200 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
201 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
202 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
203 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
204 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
205 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
206 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
207 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
208 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
209 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
210 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
211 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
212 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
213 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
214 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
215 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
216 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
217 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
218 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
219 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
220 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
221 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
222 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
223 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
224 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
225 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
226 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
227 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
228 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
229 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
230 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
231 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
232 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
233 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
234 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
235 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
236 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
237 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
238 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
239 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
240 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
241 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
242 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
243 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
244 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
245 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
246 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
247 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
248 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
249 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
250 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
251 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
252 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
253 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
254 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
255 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
256 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
257 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
258 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
259 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
260 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
261 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
262 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
263 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
264 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
265 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
266 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
267 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
268 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
269 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
270 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
271 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
272 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
273 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
274 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
275 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
276 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
277 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
278 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
279 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
280 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
281 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
282 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
283 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
284 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
285 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
286 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
287 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
288 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
289 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
290 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
291 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
292 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
293 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
294 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
295 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
296 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
297 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
298 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
299 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
300 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
301 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
302 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
303 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
304 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
305 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
306 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
307 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
308 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
309 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
310 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
311 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
312 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
313 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
314 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
315 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
316 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
317 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
318 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
319 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
320 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
321 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
322 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
323 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
324 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
325 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
326 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
327 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
328 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
329 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
330 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
331 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
332 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
333 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
334 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
335 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
336 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
337 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
338 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
339 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
340 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
341 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
342 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
343 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
344 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
345 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
346 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
347 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
348 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
349 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
350 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
351 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
352 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
353 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
354 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
355 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
356 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
357 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
358 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
359 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
360 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
361 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
362 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
363 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
364 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
365 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
366 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
367 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
368 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
369 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
370 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
371 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
372 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
373 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
374 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
375 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
376 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
377 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
378 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
379 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
380 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
381 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
382 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
383 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
384 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
385 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
386 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
387 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
388 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
389 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
390 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
391 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
392 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
393 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
394 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
395 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
396 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
397 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
398 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
399 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
400 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
401 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
402 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
403 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
404 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
405 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
406 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
407 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
408 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
409 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
410 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
411 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
412 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
413 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
414 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
415 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
416 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
417 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
418 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
419 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
420 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
421 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
422 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
423 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
424 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
425 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
426 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
427 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
428 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
429 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
430 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
431 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
432 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
433 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
434 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
435 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
436 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
437 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
438 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
439 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
440 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
441 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
442 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
443 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
444 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
445 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
446 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
447 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
448 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
449 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
450 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
451 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
452 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
453 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
454 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
455 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
456 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
457 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
458 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
459 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
460 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
461 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
462 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
463 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
464 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
465 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
466 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
467 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
468 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
469 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
470 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
471 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
472 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
473 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
474 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
475 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
476 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
477 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
478 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
479 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
480 |
--------------------------------------------------------------------------------