diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..22d0d82 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..d0cfc73 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,114 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/fsnotify/fsnotify" + packages = ["."] + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token" + ] + revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" + +[[projects]] + name = "github.com/magiconair/properties" + packages = ["."] + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" + +[[projects]] + name = "github.com/pelletier/go-toml" + packages = ["."] + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + name = "github.com/satori/go.uuid" + packages = ["."] + revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" + version = "v1.2.0" + +[[projects]] + name = "github.com/spf13/afero" + packages = [ + ".", + "mem" + ] + revision = "63644898a8da0bc22138abf860edaf5277b6102e" + version = "v1.1.0" + +[[projects]] + name = "github.com/spf13/cast" + packages = ["."] + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" + +[[projects]] + branch = "master" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "583c0c0531f06d5278b7d917446061adc344b5cd" + version = "v1.0.1" + +[[projects]] + name = "github.com/spf13/viper" + packages = ["."] + revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736" + version = "v1.0.2" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = ["unix"] + revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "internal/gen", + "internal/triegen", + "internal/ucd", + "transform", + "unicode/cldr", + "unicode/norm" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "99ea85b830fa108a2e5668f4bfec764c92c0e4f3af207e814d73a6aa049a40f6" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..f11142e --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/satori/go.uuid" + version = "1.2.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/apicontext/context.go b/apicontext/context.go new file mode 100644 index 0000000..21d4d52 --- /dev/null +++ b/apicontext/context.go @@ -0,0 +1,60 @@ +package apicontext + +import ( + "context" + + uuid "github.com/satori/go.uuid" +) + +type contextKey int + +const ( + reqIDKey contextKey = 0 + clientIDKey contextKey = 1 + userIDKey contextKey = 2 +) + +// WithReqID returns a new Context that carries request ID +func WithReqID(ctx context.Context) context.Context { + return context.WithValue(ctx, reqIDKey, uuid.NewV4().String()) +} + +// WithClientID returns a new Context that carries client ID +func WithClientID(ctx context.Context, clientID uint) context.Context { + return context.WithValue(ctx, clientIDKey, clientID) +} + +// WithUserID returns a new Context that carries user ID +func WithUserID(ctx context.Context, userID uint) context.Context { + return context.WithValue(ctx, userIDKey, userID) +} + +//ReqID returns the requestID from context. +//Returns 0 if requestID is not set in context +func ReqID(ctx context.Context) string { + reqID := ctx.Value(reqIDKey) + if reqID != nil { + return reqID.(string) + } + return "" +} + +//ClientID returns the client_id of authorized client from context. +//Returns 0 if client_id is not set in context +func ClientID(ctx context.Context) uint { + clientID := ctx.Value(clientIDKey) + if clientID != nil { + return clientID.(uint) + } + return 0 +} + +//UserID returns user_id of authenticated user of a client from context. +//Returns 0 if user_id is not set in context +func UserID(ctx context.Context) uint { + userID := ctx.Value(userIDKey) + if userID != nil { + return userID.(uint) + } + return 0 +} diff --git a/logger/logging.go b/logger/logging.go new file mode 100644 index 0000000..0fa3b51 --- /dev/null +++ b/logger/logging.go @@ -0,0 +1,44 @@ +package logger + +import ( + "context" + "fmt" + "log" + "log-context/apicontext" + "runtime" +) + +//Info logs with context +func Info(ctx context.Context, msg string, v ...interface{}) { + ctxString := fmt.Sprintf("[%v:%v:%v] %v", apicontext.ReqID(ctx), apicontext.ClientID(ctx), apicontext.UserID(ctx), caller()) + log.Printf("%v INFO: %v", ctxString, fmt.Sprintf(msg, v...)) +} + +//Error logs with context +func Error(ctx context.Context, msg string, v ...interface{}) { + ctxString := fmt.Sprintf("[%v:%v:%v] %v", apicontext.ReqID(ctx), apicontext.ClientID(ctx), apicontext.UserID(ctx), caller()) + log.Printf("%v ERROR: %v", ctxString, fmt.Sprintf(msg, v...)) +} + +//Debug logs with context +func Debug(ctx context.Context, msg string, v ...interface{}) { + ctxString := fmt.Sprintf("[%v:%v:%v] %v", apicontext.ReqID(ctx), apicontext.ClientID(ctx), apicontext.UserID(ctx), caller()) + log.Printf("%v DEBUG: %v", ctxString, fmt.Sprintf(msg, v...)) +} + +//to give you name of the file and line number from where logs are emitted +func caller() string { + _, file, no, ok := runtime.Caller(2) + if ok { + short := file + for i := len(file) - 1; i > 0; i-- { + if file[i] == '/' { + short = file[i+1:] + break + } + } + file = short + return fmt.Sprintf("%v:%v ", file, no) + } + return "???:0 " +} diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..7e70b4f --- /dev/null +++ b/server/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "context" + "log-context/apicontext" + "log-context/logger" +) + +func main() { + ctx := apicontext.WithReqID(context.Background()) + logger.Info(ctx, "test info log formatted with var %v, var %v ", 1, "two") + logger.Error(ctx, "test error log formatted with var %v, var %v ", 1, "two") + logger.Debug(ctx, "test debug log formatted with var %v, var %v ", 1, "two") +}