diff options
| author | Christine Dodrill <me@christine.website> | 2017-12-13 10:43:58 -0800 |
|---|---|---|
| committer | Christine Dodrill <me@christine.website> | 2017-12-13 11:42:37 -0800 |
| commit | 3a21ef192628f6952eaa981bcdf718a35a4b43c7 (patch) | |
| tree | 9c88a3ddc57ab5014f436ec2c08c96280872632e /vendor/github.com/Xe/ln | |
| parent | 3b4b6cede9bc30008b0f40989a1564b26e64fd05 (diff) | |
| download | xesite-3a21ef192628f6952eaa981bcdf718a35a4b43c7.tar.xz xesite-3a21ef192628f6952eaa981bcdf718a35a4b43c7.zip | |
convert to go buildpack
Diffstat (limited to 'vendor/github.com/Xe/ln')
| -rw-r--r-- | vendor/github.com/Xe/ln/LICENSE | 25 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/README.md | 29 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/action.go | 11 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/context.go | 38 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/doc.go | 25 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/ex/doc.go | 7 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/ex/gotrace.go | 68 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/ex/http.go | 36 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/ex/l2met.go | 25 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/example/http.go | 51 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/filter.go | 15 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/formatter.go | 5 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/logger.go | 95 | ||||
| -rw-r--r-- | vendor/github.com/Xe/ln/logger_test.go | 111 |
14 files changed, 504 insertions, 37 deletions
diff --git a/vendor/github.com/Xe/ln/LICENSE b/vendor/github.com/Xe/ln/LICENSE new file mode 100644 index 0000000..7202b64 --- /dev/null +++ b/vendor/github.com/Xe/ln/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2015, Andrew Gwozdziewycz +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/vendor/github.com/Xe/ln/README.md b/vendor/github.com/Xe/ln/README.md new file mode 100644 index 0000000..61fc941 --- /dev/null +++ b/vendor/github.com/Xe/ln/README.md @@ -0,0 +1,29 @@ +# ln: The Natural Logger for Go + +`ln` provides a simple interface to logging, and metrics, and +obviates the need to utilize purpose built metrics packages, like +`go-metrics` for simple use cases. + +The design of `ln` centers around the idea of key-value pairs, which +can be interpreted on the fly, but "Filters" to do things such as +aggregated metrics, and report said metrics to, say Librato, or +statsd. + +"Filters" are like WSGI, or Rack Middleware. They are run "top down" +and can abort an emitted log's output at any time, or continue to let +it through the chain. However, the interface is slightly different +than that. Rather than encapsulating the chain with partial function +application, we utilize a simpler method, namely, each plugin defines +an `Apply` function, which takes as an argument the log event, and +performs the work of the plugin, only if the Plugin "Applies" to this +log event. + +If `Apply` returns `false`, the iteration through the rest of the +filters is aborted, and the log is dropped from further processing. + +## Current Status: Initial Development / Concept + +## Copyright + +(c) 2015, Andrew Gwozdziewycz, BSD Licensed. See LICENSE for more +info. diff --git a/vendor/github.com/Xe/ln/action.go b/vendor/github.com/Xe/ln/action.go new file mode 100644 index 0000000..54f8954 --- /dev/null +++ b/vendor/github.com/Xe/ln/action.go @@ -0,0 +1,11 @@ +package ln + +// Action is a convenience helper for logging the "action" being performed as +// part of a log line. +// +// It is a convenience wrapper for the following: +// +// ln.Log(ctx, fer, f, ln.Action("writing frozberry sales reports to database")) +func Action(act string) Fer { + return F{"action": act} +} diff --git a/vendor/github.com/Xe/ln/context.go b/vendor/github.com/Xe/ln/context.go new file mode 100644 index 0000000..0ea3229 --- /dev/null +++ b/vendor/github.com/Xe/ln/context.go @@ -0,0 +1,38 @@ +package ln + +import ( + "context" +) + +type ctxKey int + +const ( + fKey = iota +) + +// WithF stores or appends a given F instance into a context. +func WithF(ctx context.Context, f F) context.Context { + pf, ok := FFromContext(ctx) + if !ok { + return context.WithValue(ctx, fKey, f) + } + + pf.Extend(f) + + return context.WithValue(ctx, fKey, pf) +} + +// FFromContext fetches the `F` out of the context if it exists. +func FFromContext(ctx context.Context) (F, bool) { + fvp := ctx.Value(fKey) + if fvp == nil { + return nil, false + } + + f, ok := fvp.(F) + if !ok { + return nil, false + } + + return f, true +} diff --git a/vendor/github.com/Xe/ln/doc.go b/vendor/github.com/Xe/ln/doc.go new file mode 100644 index 0000000..ab81c3c --- /dev/null +++ b/vendor/github.com/Xe/ln/doc.go @@ -0,0 +1,25 @@ +/* +Package ln is the Natural Logger for Go + +`ln` provides a simple interface to logging, and metrics, and +obviates the need to utilize purpose built metrics packages, like +`go-metrics` for simple use cases. + +The design of `ln` centers around the idea of key-value pairs, which +can be interpreted on the fly, but "Filters" to do things such as +aggregated metrics, and report said metrics to, say Librato, or +statsd. + +"Filters" are like WSGI, or Rack Middleware. They are run "top down" +and can abort an emitted log's output at any time, or continue to let +it through the chain. However, the interface is slightly different +than that. Rather than encapsulating the chain with partial function +application, we utilize a simpler method, namely, each plugin defines +an `Apply` function, which takes as an argument the log event, and +performs the work of the plugin, only if the Plugin "Applies" to this +log event. + +If `Apply` returns `false`, the iteration through the rest of the +filters is aborted, and the log is dropped from further processing. +*/ +package ln diff --git a/vendor/github.com/Xe/ln/ex/doc.go b/vendor/github.com/Xe/ln/ex/doc.go new file mode 100644 index 0000000..932ed42 --- /dev/null +++ b/vendor/github.com/Xe/ln/ex/doc.go @@ -0,0 +1,7 @@ +/* +Package ex is a set of extensions and middleware for ln. + +This package will (inevitably) have a lot of third-party dependencies and +as such might be broken apart into other packages in the future. +*/ +package ex diff --git a/vendor/github.com/Xe/ln/ex/gotrace.go b/vendor/github.com/Xe/ln/ex/gotrace.go new file mode 100644 index 0000000..5579879 --- /dev/null +++ b/vendor/github.com/Xe/ln/ex/gotrace.go @@ -0,0 +1,68 @@ +package ex + +import ( + "context" + "log" + + "github.com/Xe/ln" + "golang.org/x/net/trace" +) + +type goEventLogger struct { + ev trace.EventLog +} + +// NewGoEventLogger will log ln information to a given trace.EventLog instance. +func NewGoEventLogger(ev trace.EventLog) ln.Filter { + return &goEventLogger{ev: ev} +} + +func (gel *goEventLogger) Apply(ctx context.Context, e ln.Event) bool { + data, err := ln.DefaultFormatter.Format(ctx, e) + if err != nil { + log.Printf("wtf: error in log formatting: %v", err) + return false + } + + if everr := e.Data["err"]; everr != nil { + gel.ev.Errorf("%s", string(data)) + return true + } + + gel.ev.Printf("%s", string(data)) + return true +} + +func (gel *goEventLogger) Close() { gel.ev.Finish() } +func (gel *goEventLogger) Run() {} + +type sst string + +func (s sst) String() string { return string(s) } + +func goTraceLogger(ctx context.Context, e ln.Event) bool { + sp, ok := trace.FromContext(ctx) + if !ok { + return true // no trace in context + } + + data, err := ln.DefaultFormatter.Format(ctx, e) + if err != nil { + log.Printf("wtf: error in log formatting: %v", err) + return false + } + + if everr := e.Data["err"]; everr != nil { + sp.SetError() + } + + sp.LazyLog(sst(string(data)), false) + + return true +} + +// NewGoTraceLogger will log ln information to a golang.org/x/net/trace.Trace +// if it is present in the context of ln calls. +func NewGoTraceLogger() ln.Filter { + return ln.FilterFunc(goTraceLogger) +} diff --git a/vendor/github.com/Xe/ln/ex/http.go b/vendor/github.com/Xe/ln/ex/http.go new file mode 100644 index 0000000..c5715a3 --- /dev/null +++ b/vendor/github.com/Xe/ln/ex/http.go @@ -0,0 +1,36 @@ +package ex + +import ( + "net" + "net/http" + "time" + + "github.com/Xe/ln" +) + +func HTTPLog(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + host, _, _ := net.SplitHostPort(r.RemoteAddr) + f := ln.F{ + "remote_ip": host, + "x_forwarded_for": r.Header.Get("X-Forwarded-For"), + "path": r.URL.Path, + } + ctx := ln.WithF(r.Context(), f) + st := time.Now() + + next.ServeHTTP(w, r.WithContext(ctx)) + + af := time.Now() + f["request_duration"] = af.Sub(st) + + ws, ok := w.(interface { + Status() int + }) + if ok { + f["status"] = ws.Status() + } + + ln.Log(r.Context(), f) + }) +} diff --git a/vendor/github.com/Xe/ln/ex/l2met.go b/vendor/github.com/Xe/ln/ex/l2met.go new file mode 100644 index 0000000..e2a7f19 --- /dev/null +++ b/vendor/github.com/Xe/ln/ex/l2met.go @@ -0,0 +1,25 @@ +package ex + +import ( + "time" + + "github.com/Xe/ln" +) + +// This file deals with formatting of [l2met] style metrics. +// [l2met]: https://r.32k.io/l2met-introduction + +// Counter formats a value as a metrics counter. +func Counter(name string, value int) ln.Fer { + return ln.F{"count#" + name: value} +} + +// Gauge formats a value as a metrics gauge. +func Gauge(name string, value int) ln.Fer { + return ln.F{"gauge#" + name: value} +} + +// Measure formats a value as a metrics measure. +func Measure(name string, ts time.Time) ln.Fer { + return ln.F{"measure#" + name: time.Since(ts)} +} diff --git a/vendor/github.com/Xe/ln/example/http.go b/vendor/github.com/Xe/ln/example/http.go new file mode 100644 index 0000000..7fb98a3 --- /dev/null +++ b/vendor/github.com/Xe/ln/example/http.go @@ -0,0 +1,51 @@ +// +build ignore + +package main + +import ( + "context" + "flag" + "net/http" + "time" + + "github.com/Xe/ln" + "github.com/Xe/ln/ex" + "github.com/facebookgo/flagenv" + "golang.org/x/net/trace" +) + +var ( + port = flag.String("port", "2145", "http port to listen on") + tracingFamily = flag.String("trace-family", "ln example", "tracing family to use for x/net/trace") +) + +func main() { + flagenv.Parse() + flag.Parse() + + ln.DefaultLogger.Filters = append(ln.DefaultLogger.Filters, ex.NewGoTraceLogger()) + + http.HandleFunc("/", handleIndex) + http.ListenAndServe(":"+*port, middlewareSpan(ex.HTTPLog(http.DefaultServeMux))) +} + +func middlewareSpan(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + sp := trace.New(*tracingFamily, "HTTP request") + defer sp.Finish() + ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second) + defer cancel() + + ctx = trace.NewContext(ctx, sp) + + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +func handleIndex(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + ln.Log(ctx, ln.Action("index"), ln.F{"there_is": "no_danger"}) + + http.Error(w, "There is no danger citizen", http.StatusOK) +} diff --git a/vendor/github.com/Xe/ln/filter.go b/vendor/github.com/Xe/ln/filter.go index 586efef..4f2d006 100644 --- a/vendor/github.com/Xe/ln/filter.go +++ b/vendor/github.com/Xe/ln/filter.go @@ -1,23 +1,24 @@ package ln import ( + "context" "io" "sync" ) // Filter interface for defining chain filters type Filter interface { - Apply(Event) bool + Apply(ctx context.Context, e Event) bool Run() Close() } // FilterFunc allows simple functions to implement the Filter interface -type FilterFunc func(e Event) bool +type FilterFunc func(ctx context.Context, e Event) bool // Apply implements the Filter interface -func (ff FilterFunc) Apply(e Event) bool { - return ff(e) +func (ff FilterFunc) Apply(ctx context.Context, e Event) bool { + return ff(ctx, e) } // Run implements the Filter interface @@ -45,8 +46,8 @@ func NewWriterFilter(out io.Writer, format Formatter) *WriterFilter { } // Apply implements the Filter interface -func (w *WriterFilter) Apply(e Event) bool { - output, err := w.Formatter.Format(e) +func (w *WriterFilter) Apply(ctx context.Context, e Event) bool { + output, err := w.Formatter.Format(ctx, e) if err == nil { w.Lock() w.Out.Write(output) @@ -63,4 +64,4 @@ func (w *WriterFilter) Run() {} func (w *WriterFilter) Close() {} // NilFilter is safe to return as a Filter, but does nothing -var NilFilter = FilterFunc(func(e Event) bool { return true }) +var NilFilter = FilterFunc(func(_ context.Context, e Event) bool { return true }) diff --git a/vendor/github.com/Xe/ln/formatter.go b/vendor/github.com/Xe/ln/formatter.go index ecd4743..70313fc 100644 --- a/vendor/github.com/Xe/ln/formatter.go +++ b/vendor/github.com/Xe/ln/formatter.go @@ -2,6 +2,7 @@ package ln import ( "bytes" + "context" "fmt" "time" ) @@ -13,7 +14,7 @@ var ( // Formatter defines the formatting of events type Formatter interface { - Format(Event) ([]byte, error) + Format(ctx context.Context, e Event) ([]byte, error) } // DefaultFormatter is the default way in which to format events @@ -36,7 +37,7 @@ func NewTextFormatter() Formatter { } // Format implements the Formatter interface -func (t *TextFormatter) Format(e Event) ([]byte, error) { +func (t *TextFormatter) Format(_ context.Context, e Event) ([]byte, error) { var writer bytes.Buffer writer.WriteString("time=\"") diff --git a/vendor/github.com/Xe/ln/logger.go b/vendor/github.com/Xe/ln/logger.go index cdfe89e..79a9a63 100644 --- a/vendor/github.com/Xe/ln/logger.go +++ b/vendor/github.com/Xe/ln/logger.go @@ -1,7 +1,7 @@ package ln import ( - "fmt" + "context" "os" "time" @@ -30,14 +30,28 @@ func init() { DefaultLogger = &Logger{ Filters: defaultFilters, } - } // F is a key-value mapping for structured data. type F map[string]interface{} +// Extend concatentates one F with one or many Fer instances. +func (f F) Extend(other ...Fer) { + for _, ff := range other { + for k, v := range ff.F() { + f[k] = v + } + } +} + +// F makes F an Fer +func (f F) F() F { + return f +} + +// Fer allows any type to add fields to the structured logging key->value pairs. type Fer interface { - F() map[string]interface{} + F() F } // Event represents an event @@ -48,8 +62,7 @@ type Event struct { } // Log is the generic logging method. -func (l *Logger) Log(xs ...interface{}) { - var bits []interface{} +func (l *Logger) Log(ctx context.Context, xs ...Fer) { event := Event{Time: time.Now()} addF := func(bf F) { @@ -62,18 +75,14 @@ func (l *Logger) Log(xs ...interface{}) { } } - // Assemble the event - for _, b := range xs { - if bf, ok := b.(F); ok { - addF(bf) - } else if fer, ok := b.(Fer); ok { - addF(F(fer.F())) - } else { - bits = append(bits, b) - } + for _, f := range xs { + addF(f.F()) } - event.Message = fmt.Sprint(bits...) + ctxf, ok := FFromContext(ctx) + if ok { + addF(ctxf) + } if os.Getenv("LN_DEBUG_ALL_EVENTS") == "1" { frame := callersFrame() @@ -85,19 +94,19 @@ func (l *Logger) Log(xs ...interface{}) { event.Data["_filename"] = frame.filename } - l.filter(event) + l.filter(ctx, event) } -func (l *Logger) filter(e Event) { +func (l *Logger) filter(ctx context.Context, e Event) { for _, f := range l.Filters { - if !f.Apply(e) { + if !f.Apply(ctx, e) { return } } } // Error logs an error and information about the context of said error. -func (l *Logger) Error(err error, xs ...interface{}) { +func (l *Logger) Error(ctx context.Context, err error, xs ...Fer) { data := F{} frame := callersFrame() @@ -113,12 +122,37 @@ func (l *Logger) Error(err error, xs ...interface{}) { xs = append(xs, data) - l.Log(xs...) + l.Log(ctx, xs...) } // Fatal logs this set of values, then exits with status code 1. -func (l *Logger) Fatal(xs ...interface{}) { - l.Log(xs...) +func (l *Logger) Fatal(ctx context.Context, xs ...Fer) { + xs = append(xs, F{"fatal": true}) + + l.Log(ctx, xs...) + + os.Exit(1) +} + +// FatalErr combines Fatal and Error. +func (l *Logger) FatalErr(ctx context.Context, err error, xs ...Fer) { + xs = append(xs, F{"fatal": true}) + + data := F{} + frame := callersFrame() + + data["_lineno"] = frame.lineno + data["_function"] = frame.function + data["_filename"] = frame.filename + data["err"] = err + + cause := errors.Cause(err) + if cause != nil { + data["cause"] = cause.Error() + } + + xs = append(xs, data) + l.Log(ctx, xs...) os.Exit(1) } @@ -126,16 +160,21 @@ func (l *Logger) Fatal(xs ...interface{}) { // Default Implementation // Log is the generic logging method. -func Log(xs ...interface{}) { - DefaultLogger.Log(xs...) +func Log(ctx context.Context, xs ...Fer) { + DefaultLogger.Log(ctx, xs...) } // Error logs an error and information about the context of said error. -func Error(err error, xs ...interface{}) { - DefaultLogger.Error(err, xs...) +func Error(ctx context.Context, err error, xs ...Fer) { + DefaultLogger.Error(ctx, err, xs...) } // Fatal logs this set of values, then exits with status code 1. -func Fatal(xs ...interface{}) { - DefaultLogger.Fatal(xs...) +func Fatal(ctx context.Context, xs ...Fer) { + DefaultLogger.Fatal(ctx, xs...) +} + +// FatalErr combines Fatal and Error. +func FatalErr(ctx context.Context, err error, xs ...Fer) { + DefaultLogger.FatalErr(ctx, err, xs...) } diff --git a/vendor/github.com/Xe/ln/logger_test.go b/vendor/github.com/Xe/ln/logger_test.go new file mode 100644 index 0000000..800ed90 --- /dev/null +++ b/vendor/github.com/Xe/ln/logger_test.go @@ -0,0 +1,111 @@ +package ln + +import ( + "bytes" + "context" + "fmt" + "testing" + "time" +) + +var ctx context.Context + +func setup(t *testing.T) (*bytes.Buffer, func()) { + ctx = context.Background() + + out := bytes.Buffer{} + oldFilters := DefaultLogger.Filters + DefaultLogger.Filters = []Filter{NewWriterFilter(&out, nil)} + return &out, func() { + DefaultLogger.Filters = oldFilters + } +} + +func TestSimpleError(t *testing.T) { + out, teardown := setup(t) + defer teardown() + + Log(ctx, F{"err": fmt.Errorf("This is an Error!!!")}, F{"msg": "fooey", "bar": "foo"}) + data := []string{ + `err="This is an Error!!!"`, + `fooey`, + `bar=foo`, + } + + for _, line := range data { + if !bytes.Contains(out.Bytes(), []byte(line)) { + t.Fatalf("Bytes: %s not in %s", line, out.Bytes()) + } + } +} + +func TestTimeConversion(t *testing.T) { + out, teardown := setup(t) + defer teardown() + + var zeroTime time.Time + + Log(ctx, F{"zero": zeroTime}) + data := []string{ + `zero=0001-01-01T00:00:00Z`, + } + + for _, line := range data { + if !bytes.Contains(out.Bytes(), []byte(line)) { + t.Fatalf("Bytes: %s not in %s", line, out.Bytes()) + } + } +} + +func TestDebug(t *testing.T) { + out, teardown := setup(t) + defer teardown() + + // set priority to Debug + Error(ctx, fmt.Errorf("This is an Error!!!"), F{}) + + data := []string{ + `err="This is an Error!!!"`, + `_lineno=`, + `_function=ln.TestDebug`, + `_filename=github.com/Xe/ln/logger_test.go`, + `cause="This is an Error!!!"`, + } + + for _, line := range data { + if !bytes.Contains(out.Bytes(), []byte(line)) { + t.Fatalf("Bytes: %s not in %s", line, out.Bytes()) + } + } +} + +func TestFer(t *testing.T) { + out, teardown := setup(t) + defer teardown() + + underTest := foobar{Foo: 1, Bar: "quux"} + + Log(ctx, underTest) + data := []string{ + `foo=1`, + `bar=quux`, + } + + for _, line := range data { + if !bytes.Contains(out.Bytes(), []byte(line)) { + t.Fatalf("Bytes: %s not in %s", line, out.Bytes()) + } + } +} + +type foobar struct { + Foo int + Bar string +} + +func (f foobar) F() F { + return F{ + "foo": f.Foo, + "bar": f.Bar, + } +} |
