1
0
Fork 0

Add context to logs, update readme

This commit is contained in:
Gregory Eremin 2018-06-24 02:57:14 +02:00
parent 984a90a75c
commit 01c445213c
No known key found for this signature in database
GPG Key ID: 8CB79D42167BEB7F
4 changed files with 92 additions and 44 deletions

View File

@ -10,11 +10,17 @@ import "github.com/localhots/gobelt/threadpool"
```go ```go
ctx := context.Background() ctx := context.Background()
pool := threadpool.New(5) ctx, cancel = context.WithTimeout(ctx, 30 * time.Second)
pool.Enqueue(ctx, func() { defer cancel()
fmt.Println("Hello")
}) pool := threadpool.New(10)
pool.Close() defer pool.Close()
for i := 0; i < 1000000; i++ {
i := i
pool.Enqueue(ctx, func() {
fmt.Printf("The number is %d\n", i)
})
}
``` ```
### File cache ### File cache
@ -26,8 +32,12 @@ import "github.com/localhots/gobelt/filecache"
```go ```go
var val int var val int
filecache.Load(&val, "path/to/cachefile", func() interface{} { filecache.Load(&val, "path/to/cachefile", func() interface{} {
// Expensive calls here var items []Item
return 100 err := conn.Query(ctx, "SELECT * FROM items").Load(&items).Error()
if err != nil {
log.Fatal("Failed to load items", log.F{"error": err})
}
return items
}) })
``` ```
@ -38,9 +48,16 @@ import "github.com/localhots/gobelt/log"
``` ```
```go ```go
log.Info("New user signed up", log.F{ ctx := context.Background()
"name": u.Name, ctx = log.ContextWithFields(ctx, log.F{"email": params["email"]})
"email": u.Email,
}) user, err := signup(ctx, params)
log.Errorf("Invalid database flavor: %s", flavor) if err != nil {
log.Errorf(ctx, "Signup failed: %v", err)
// [ERRO] Signup failed: db: duplicate entry email=bob@example.com
return
}
log.Info(ctx, "New user signed up", log.F{"id": user.ID})
// [INFO] New user signed up email=bob@example.com id=14
``` ```

27
log/context.go Normal file
View File

@ -0,0 +1,27 @@
package log
import "context"
type logContext byte
const ctxFields logContext = iota
// ContextWithFields returns a new context with given fields added.
func ContextWithFields(ctx context.Context, f F) context.Context {
ctxf, ok := ctx.Value(ctxFields).(F)
if !ok {
ctxf = F{}
}
for k, v := range f {
ctxf[k] = v
}
return context.WithValue(ctx, ctxFields, ctxf)
}
func contextFields(ctx context.Context) F {
f, ok := ctx.Value(ctxFields).(F)
if ok {
return f
}
return F{}
}

View File

@ -1,6 +1,8 @@
package log package log
import ( import (
"context"
"github.com/lytics/logrus" "github.com/lytics/logrus"
) )
@ -15,58 +17,61 @@ func init() {
} }
// Debug prints a debug message with given fields attached. // Debug prints a debug message with given fields attached.
func Debug(msg string, fields ...F) { func Debug(ctx context.Context, msg string, fields ...F) {
withFields(fields).Debug(msg) withFields(mergeFields(ctx, fields)).Debug(msg)
} }
// Debugf prints a formatted debug message. // Debugf prints a formatted debug message.
func Debugf(format string, args ...interface{}) { func Debugf(ctx context.Context, format string, args ...interface{}) {
logrus.Debugf(format, args...) withFields(contextFields(ctx)).Debugf(format, args...)
} }
// Info prints an info message with given fields attached. // Info prints an info message with given fields attached.
func Info(msg string, fields ...F) { func Info(ctx context.Context, msg string, fields ...F) {
withFields(fields).Info(msg) withFields(mergeFields(ctx, fields)).Info(msg)
} }
// Infof prints a formatted info message. // Infof prints a formatted info message.
func Infof(format string, args ...interface{}) { func Infof(ctx context.Context, format string, args ...interface{}) {
logrus.Infof(format, args...) withFields(contextFields(ctx)).Infof(format, args...)
} }
// Error prints an error message with given fields attached. // Error prints an error message with given fields attached.
func Error(msg string, fields ...F) { func Error(ctx context.Context, msg string, fields ...F) {
withFields(fields).Error(msg) withFields(mergeFields(ctx, fields)).Error(msg)
} }
// Errorf prints a formatted error message. // Errorf prints a formatted error message.
func Errorf(format string, args ...interface{}) { func Errorf(ctx context.Context, format string, args ...interface{}) {
logrus.Errorf(format, args...) withFields(contextFields(ctx)).Errorf(format, args...)
} }
// Fatal prints an error message with given fields attached and then exits. // Fatal prints an error message with given fields attached and then exits.
func Fatal(msg string, fields ...F) { func Fatal(ctx context.Context, msg string, fields ...F) {
withFields(fields).Fatal(msg) withFields(mergeFields(ctx, fields)).Fatal(msg)
} }
// Fatalf prints a formatted error message and then exits. // Fatalf prints a formatted error message and then exits.
func Fatalf(format string, args ...interface{}) { func Fatalf(ctx context.Context, format string, args ...interface{}) {
logrus.Fatalf(format, args...) withFields(contextFields(ctx)).Fatalf(format, args...)
} }
func withFields(fields []F) *logrus.Entry { func mergeFields(ctx context.Context, fields []F) F {
switch len(fields) { ctxf := contextFields(ctx)
case 0: if len(ctxf) == 0 && len(fields) == 0 {
return logrus.NewEntry(Logger) return nil
case 1:
return logrus.WithFields(logrus.Fields(fields[0]))
default:
f := F{}
for i := 0; i < len(fields); i++ {
for k, v := range fields[i] {
f[k] = v
}
}
return logrus.WithFields(logrus.Fields(f))
} }
for i := 0; i < len(fields); i++ {
for k, v := range fields[i] {
ctxf[k] = v
}
}
return ctxf
}
func withFields(f F) *logrus.Entry {
if len(f) == 0 {
return logrus.NewEntry(Logger)
}
return logrus.WithFields(logrus.Fields(f))
} }

View File

@ -3,9 +3,8 @@ package impl
import ( import (
"testing" "testing"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
) )
const ( const (