diff --git a/README.md b/README.md index d563d1a..01e72ad 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,17 @@ import "github.com/localhots/gobelt/threadpool" ```go ctx := context.Background() -pool := threadpool.New(5) -pool.Enqueue(ctx, func() { - fmt.Println("Hello") -}) -pool.Close() +ctx, cancel = context.WithTimeout(ctx, 30 * time.Second) +defer cancel() + +pool := threadpool.New(10) +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 @@ -26,8 +32,12 @@ import "github.com/localhots/gobelt/filecache" ```go var val int filecache.Load(&val, "path/to/cachefile", func() interface{} { - // Expensive calls here - return 100 + var items []Item + 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 -log.Info("New user signed up", log.F{ - "name": u.Name, - "email": u.Email, -}) -log.Errorf("Invalid database flavor: %s", flavor) +ctx := context.Background() +ctx = log.ContextWithFields(ctx, log.F{"email": params["email"]}) + +user, err := signup(ctx, params) +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 ``` \ No newline at end of file diff --git a/log/context.go b/log/context.go new file mode 100644 index 0000000..91ec9c5 --- /dev/null +++ b/log/context.go @@ -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{} +} diff --git a/log/log.go b/log/log.go index 3961f07..7b8a807 100644 --- a/log/log.go +++ b/log/log.go @@ -1,6 +1,8 @@ package log import ( + "context" + "github.com/lytics/logrus" ) @@ -15,58 +17,61 @@ func init() { } // Debug prints a debug message with given fields attached. -func Debug(msg string, fields ...F) { - withFields(fields).Debug(msg) +func Debug(ctx context.Context, msg string, fields ...F) { + withFields(mergeFields(ctx, fields)).Debug(msg) } // Debugf prints a formatted debug message. -func Debugf(format string, args ...interface{}) { - logrus.Debugf(format, args...) +func Debugf(ctx context.Context, format string, args ...interface{}) { + withFields(contextFields(ctx)).Debugf(format, args...) } // Info prints an info message with given fields attached. -func Info(msg string, fields ...F) { - withFields(fields).Info(msg) +func Info(ctx context.Context, msg string, fields ...F) { + withFields(mergeFields(ctx, fields)).Info(msg) } // Infof prints a formatted info message. -func Infof(format string, args ...interface{}) { - logrus.Infof(format, args...) +func Infof(ctx context.Context, format string, args ...interface{}) { + withFields(contextFields(ctx)).Infof(format, args...) } // Error prints an error message with given fields attached. -func Error(msg string, fields ...F) { - withFields(fields).Error(msg) +func Error(ctx context.Context, msg string, fields ...F) { + withFields(mergeFields(ctx, fields)).Error(msg) } // Errorf prints a formatted error message. -func Errorf(format string, args ...interface{}) { - logrus.Errorf(format, args...) +func Errorf(ctx context.Context, format string, args ...interface{}) { + withFields(contextFields(ctx)).Errorf(format, args...) } // Fatal prints an error message with given fields attached and then exits. -func Fatal(msg string, fields ...F) { - withFields(fields).Fatal(msg) +func Fatal(ctx context.Context, msg string, fields ...F) { + withFields(mergeFields(ctx, fields)).Fatal(msg) } // Fatalf prints a formatted error message and then exits. -func Fatalf(format string, args ...interface{}) { - logrus.Fatalf(format, args...) +func Fatalf(ctx context.Context, format string, args ...interface{}) { + withFields(contextFields(ctx)).Fatalf(format, args...) } -func withFields(fields []F) *logrus.Entry { - switch len(fields) { - case 0: - return logrus.NewEntry(Logger) - 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)) +func mergeFields(ctx context.Context, fields []F) F { + ctxf := contextFields(ctx) + if len(ctxf) == 0 && len(fields) == 0 { + return nil } + 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)) } diff --git a/set/internal/impl/set_test.go b/set/internal/impl/set_test.go index 6a94e76..11eaa4a 100644 --- a/set/internal/impl/set_test.go +++ b/set/internal/impl/set_test.go @@ -3,9 +3,8 @@ package impl import ( "testing" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" ) const (