From eb6b2b91aaa73caf5ca27f9381956a35ceaa69a9 Mon Sep 17 00:00:00 2001 From: embs Date: Tue, 21 Nov 2017 13:05:06 -0300 Subject: [PATCH] Enrich Zipkin db tracing Add info regarding - database type and address - approximation for queries results size --- api/endpoints.go | 28 +++----- api/middlewares.go | 73 ++++++++++----------- api/service.go | 63 +++++++++--------- db/db.go | 53 ++++++++-------- db/tracing_middleware.go | 134 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 111 deletions(-) create mode 100644 db/tracing_middleware.go diff --git a/api/endpoints.go b/api/endpoints.go index e45c8525..ef258bae 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -53,7 +53,7 @@ func MakeLoginEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(loginRequest) - u, err := s.Login(req.Username, req.Password) + u, err := s.Login(ctx, req.Username, req.Password) return userResponse{User: u}, err } } @@ -66,7 +66,7 @@ func MakeRegisterEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(registerRequest) - id, err := s.Register(req.Username, req.Password, req.Email, req.FirstName, req.LastName) + id, err := s.Register(ctx, req.Username, req.Password, req.Email, req.FirstName, req.LastName) return postResponse{ID: id}, err } } @@ -81,9 +81,7 @@ func MakeUserGetEndpoint(s Service) endpoint.Endpoint { req := request.(GetRequest) - userspan := stdopentracing.StartSpan("users from db", stdopentracing.ChildOf(span.Context())) - usrs, err := s.GetUsers(req.ID) - userspan.Finish() + usrs, err := s.GetUsers(ctx, req.ID) if req.ID == "" { return EmbedStruct{usersResponse{Users: usrs}}, err } @@ -97,9 +95,7 @@ func MakeUserGetEndpoint(s Service) endpoint.Endpoint { return users.User{}, err } user := usrs[0] - attrspan := stdopentracing.StartSpan("attributes from db", stdopentracing.ChildOf(span.Context())) - db.GetUserAttributes(&user) - attrspan.Finish() + db.GetUserAttributes(ctx, &user) if req.Attr == "addresses" { return EmbedStruct{addressesResponse{Addresses: user.Addresses}}, err } @@ -118,7 +114,7 @@ func MakeUserPostEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(users.User) - id, err := s.PostUser(req) + id, err := s.PostUser(ctx, req) return postResponse{ID: id}, err } } @@ -131,9 +127,7 @@ func MakeAddressGetEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(GetRequest) - addrspan := stdopentracing.StartSpan("addresses from db", stdopentracing.ChildOf(span.Context())) - adds, err := s.GetAddresses(req.ID) - addrspan.Finish() + adds, err := s.GetAddresses(ctx, req.ID) if req.ID == "" { return EmbedStruct{addressesResponse{Addresses: adds}}, err } @@ -152,7 +146,7 @@ func MakeAddressPostEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(addressPostRequest) - id, err := s.PostAddress(req.Address, req.UserID) + id, err := s.PostAddress(ctx, req.Address, req.UserID) return postResponse{ID: id}, err } } @@ -165,9 +159,7 @@ func MakeCardGetEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(GetRequest) - cardspan := stdopentracing.StartSpan("addresses from db", stdopentracing.ChildOf(span.Context())) - cards, err := s.GetCards(req.ID) - cardspan.Finish() + cards, err := s.GetCards(ctx, req.ID) if req.ID == "" { return EmbedStruct{cardsResponse{Cards: cards}}, err } @@ -186,7 +178,7 @@ func MakeCardPostEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(cardPostRequest) - id, err := s.PostCard(req.Card, req.UserID) + id, err := s.PostCard(ctx, req.Card, req.UserID) return postResponse{ID: id}, err } } @@ -199,7 +191,7 @@ func MakeDeleteEndpoint(s Service) endpoint.Endpoint { span.SetTag("service", "user") defer span.Finish() req := request.(deleteRequest) - err = s.Delete(req.Entity, req.ID) + err = s.Delete(ctx, req.Entity, req.ID) if err == nil { return statusResponse{Status: true}, err } diff --git a/api/middlewares.go b/api/middlewares.go index ba6eb560..62806dc6 100644 --- a/api/middlewares.go +++ b/api/middlewares.go @@ -1,6 +1,7 @@ package api import ( + "context" "time" "github.com/go-kit/kit/log" @@ -26,17 +27,17 @@ type loggingMiddleware struct { logger log.Logger } -func (mw loggingMiddleware) Login(username, password string) (user users.User, err error) { +func (mw loggingMiddleware) Login(ctx context.Context, username, password string) (user users.User, err error) { defer func(begin time.Time) { mw.logger.Log( "method", "Login", "took", time.Since(begin), ) }(time.Now()) - return mw.next.Login(username, password) + return mw.next.Login(ctx, username, password) } -func (mw loggingMiddleware) Register(username, password, email, first, last string) (string, error) { +func (mw loggingMiddleware) Register(ctx context.Context, username, password, email, first, last string) (string, error) { defer func(begin time.Time) { mw.logger.Log( "method", "Register", @@ -45,10 +46,10 @@ func (mw loggingMiddleware) Register(username, password, email, first, last stri "took", time.Since(begin), ) }(time.Now()) - return mw.next.Register(username, password, email, first, last) + return mw.next.Register(ctx, username, password, email, first, last) } -func (mw loggingMiddleware) PostUser(user users.User) (id string, err error) { +func (mw loggingMiddleware) PostUser(ctx context.Context, user users.User) (id string, err error) { defer func(begin time.Time) { mw.logger.Log( "method", "PostUser", @@ -58,10 +59,10 @@ func (mw loggingMiddleware) PostUser(user users.User) (id string, err error) { "took", time.Since(begin), ) }(time.Now()) - return mw.next.PostUser(user) + return mw.next.PostUser(ctx, user) } -func (mw loggingMiddleware) GetUsers(id string) (u []users.User, err error) { +func (mw loggingMiddleware) GetUsers(ctx context.Context, id string) (u []users.User, err error) { defer func(begin time.Time) { who := id if who == "" { @@ -74,10 +75,10 @@ func (mw loggingMiddleware) GetUsers(id string) (u []users.User, err error) { "took", time.Since(begin), ) }(time.Now()) - return mw.next.GetUsers(id) + return mw.next.GetUsers(ctx, id) } -func (mw loggingMiddleware) PostAddress(add users.Address, id string) (string, error) { +func (mw loggingMiddleware) PostAddress(ctx context.Context, add users.Address, id string) (string, error) { defer func(begin time.Time) { mw.logger.Log( "method", "PostAddress", @@ -87,10 +88,10 @@ func (mw loggingMiddleware) PostAddress(add users.Address, id string) (string, e "took", time.Since(begin), ) }(time.Now()) - return mw.next.PostAddress(add, id) + return mw.next.PostAddress(ctx, add, id) } -func (mw loggingMiddleware) GetAddresses(id string) (a []users.Address, err error) { +func (mw loggingMiddleware) GetAddresses(ctx context.Context, id string) (a []users.Address, err error) { defer func(begin time.Time) { who := id if who == "" { @@ -103,10 +104,10 @@ func (mw loggingMiddleware) GetAddresses(id string) (a []users.Address, err erro "took", time.Since(begin), ) }(time.Now()) - return mw.next.GetAddresses(id) + return mw.next.GetAddresses(ctx, id) } -func (mw loggingMiddleware) PostCard(card users.Card, id string) (string, error) { +func (mw loggingMiddleware) PostCard(ctx context.Context, card users.Card, id string) (string, error) { defer func(begin time.Time) { cc := card cc.MaskCC() @@ -117,10 +118,10 @@ func (mw loggingMiddleware) PostCard(card users.Card, id string) (string, error) "took", time.Since(begin), ) }(time.Now()) - return mw.next.PostCard(card, id) + return mw.next.PostCard(ctx, card, id) } -func (mw loggingMiddleware) GetCards(id string) (a []users.Card, err error) { +func (mw loggingMiddleware) GetCards(ctx context.Context, id string) (a []users.Card, err error) { defer func(begin time.Time) { who := id if who == "" { @@ -133,10 +134,10 @@ func (mw loggingMiddleware) GetCards(id string) (a []users.Card, err error) { "took", time.Since(begin), ) }(time.Now()) - return mw.next.GetCards(id) + return mw.next.GetCards(ctx, id) } -func (mw loggingMiddleware) Delete(entity, id string) (err error) { +func (mw loggingMiddleware) Delete(ctx context.Context, entity, id string) (err error) { defer func(begin time.Time) { mw.logger.Log( "method", "Delete", @@ -145,7 +146,7 @@ func (mw loggingMiddleware) Delete(entity, id string) (err error) { "took", time.Since(begin), ) }(time.Now()) - return mw.next.Delete(entity, id) + return mw.next.Delete(ctx, entity, id) } func (mw loggingMiddleware) Health() (health []Health) { @@ -174,85 +175,85 @@ func NewInstrumentingService(requestCount metrics.Counter, requestLatency metric } } -func (s *instrumentingService) Login(username, password string) (users.User, error) { +func (s *instrumentingService) Login(ctx context.Context, username, password string) (users.User, error) { defer func(begin time.Time) { s.requestCount.With("method", "login").Add(1) s.requestLatency.With("method", "login").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.Login(username, password) + return s.Service.Login(ctx, username, password) } -func (s *instrumentingService) Register(username, password, email, first, last string) (string, error) { +func (s *instrumentingService) Register(ctx context.Context, username, password, email, first, last string) (string, error) { defer func(begin time.Time) { s.requestCount.With("method", "register").Add(1) s.requestLatency.With("method", "register").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.Register(username, password, email, first, last) + return s.Service.Register(ctx, username, password, email, first, last) } -func (s *instrumentingService) PostUser(user users.User) (string, error) { +func (s *instrumentingService) PostUser(ctx context.Context, user users.User) (string, error) { defer func(begin time.Time) { s.requestCount.With("method", "postUser").Add(1) s.requestLatency.With("method", "postUser").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.PostUser(user) + return s.Service.PostUser(ctx, user) } -func (s *instrumentingService) GetUsers(id string) (u []users.User, err error) { +func (s *instrumentingService) GetUsers(ctx context.Context, id string) (u []users.User, err error) { defer func(begin time.Time) { s.requestCount.With("method", "getUsers").Add(1) s.requestLatency.With("method", "getUsers").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.GetUsers(id) + return s.Service.GetUsers(ctx, id) } -func (s *instrumentingService) PostAddress(add users.Address, id string) (string, error) { +func (s *instrumentingService) PostAddress(ctx context.Context, add users.Address, id string) (string, error) { defer func(begin time.Time) { s.requestCount.With("method", "postAddress").Add(1) s.requestLatency.With("method", "postAddress").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.PostAddress(add, id) + return s.Service.PostAddress(ctx, add, id) } -func (s *instrumentingService) GetAddresses(id string) ([]users.Address, error) { +func (s *instrumentingService) GetAddresses(ctx context.Context, id string) ([]users.Address, error) { defer func(begin time.Time) { s.requestCount.With("method", "getAddresses").Add(1) s.requestLatency.With("method", "getAddresses").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.GetAddresses(id) + return s.Service.GetAddresses(ctx, id) } -func (s *instrumentingService) PostCard(card users.Card, id string) (string, error) { +func (s *instrumentingService) PostCard(ctx context.Context, card users.Card, id string) (string, error) { defer func(begin time.Time) { s.requestCount.With("method", "postCard").Add(1) s.requestLatency.With("method", "postCard").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.PostCard(card, id) + return s.Service.PostCard(ctx, card, id) } -func (s *instrumentingService) GetCards(id string) ([]users.Card, error) { +func (s *instrumentingService) GetCards(ctx context.Context, id string) ([]users.Card, error) { defer func(begin time.Time) { s.requestCount.With("method", "getCards").Add(1) s.requestLatency.With("method", "getCards").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.GetCards(id) + return s.Service.GetCards(ctx, id) } -func (s *instrumentingService) Delete(entity, id string) error { +func (s *instrumentingService) Delete(ctx context.Context, entity, id string) error { defer func(begin time.Time) { s.requestCount.With("method", "delete").Add(1) s.requestLatency.With("method", "delete").Observe(time.Since(begin).Seconds()) }(time.Now()) - return s.Service.Delete(entity, id) + return s.Service.Delete(ctx, entity, id) } func (s *instrumentingService) Health() []Health { diff --git a/api/service.go b/api/service.go index 68a86949..367cec8d 100644 --- a/api/service.go +++ b/api/service.go @@ -4,6 +4,7 @@ package api // user service. Everything here is agnostic to the transport (HTTP). import ( + "context" "crypto/sha1" "errors" "fmt" @@ -20,15 +21,15 @@ var ( // Service is the user service, providing operations for users to login, register, and retrieve customer information. type Service interface { - Login(username, password string) (users.User, error) // GET /login - Register(username, password, email, first, last string) (string, error) - GetUsers(id string) ([]users.User, error) - PostUser(u users.User) (string, error) - GetAddresses(id string) ([]users.Address, error) - PostAddress(u users.Address, userid string) (string, error) - GetCards(id string) ([]users.Card, error) - PostCard(u users.Card, userid string) (string, error) - Delete(entity, id string) error + Login(ctx context.Context, username, password string) (users.User, error) // GET /login + Register(ctx context.Context, username, password, email, first, last string) (string, error) + GetUsers(ctx context.Context, id string) ([]users.User, error) + PostUser(ctx context.Context, u users.User) (string, error) + GetAddresses(ctx context.Context, id string) ([]users.Address, error) + PostAddress(ctx context.Context, u users.Address, userid string) (string, error) + GetCards(ctx context.Context, id string) ([]users.Card, error) + PostCard(ctx context.Context, u users.Card, userid string) (string, error) + Delete(ctx context.Context, entity, id string) error Health() []Health // GET /health } @@ -45,92 +46,92 @@ type Health struct { Time string `json:"time"` } -func (s *fixedService) Login(username, password string) (users.User, error) { - u, err := db.GetUserByName(username) +func (s *fixedService) Login(ctx context.Context, username, password string) (users.User, error) { + u, err := db.GetUserByName(ctx, username) if err != nil { return users.New(), err } if u.Password != calculatePassHash(password, u.Salt) { return users.New(), ErrUnauthorized } - db.GetUserAttributes(&u) + db.GetUserAttributes(ctx, &u) u.MaskCCs() return u, nil } -func (s *fixedService) Register(username, password, email, first, last string) (string, error) { +func (s *fixedService) Register(ctx context.Context, username, password, email, first, last string) (string, error) { u := users.New() u.Username = username u.Password = calculatePassHash(password, u.Salt) u.Email = email u.FirstName = first u.LastName = last - err := db.CreateUser(&u) + err := db.CreateUser(ctx, &u) return u.UserID, err } -func (s *fixedService) GetUsers(id string) ([]users.User, error) { +func (s *fixedService) GetUsers(ctx context.Context, id string) ([]users.User, error) { if id == "" { - us, err := db.GetUsers() + us, err := db.GetUsers(ctx) for k, u := range us { u.AddLinks() us[k] = u } return us, err } - u, err := db.GetUser(id) + u, err := db.GetUser(ctx, id) u.AddLinks() return []users.User{u}, err } -func (s *fixedService) PostUser(u users.User) (string, error) { +func (s *fixedService) PostUser(ctx context.Context, u users.User) (string, error) { u.NewSalt() u.Password = calculatePassHash(u.Password, u.Salt) - err := db.CreateUser(&u) + err := db.CreateUser(ctx, &u) return u.UserID, err } -func (s *fixedService) GetAddresses(id string) ([]users.Address, error) { +func (s *fixedService) GetAddresses(ctx context.Context, id string) ([]users.Address, error) { if id == "" { - as, err := db.GetAddresses() + as, err := db.GetAddresses(ctx) for k, a := range as { a.AddLinks() as[k] = a } return as, err } - a, err := db.GetAddress(id) + a, err := db.GetAddress(ctx, id) a.AddLinks() return []users.Address{a}, err } -func (s *fixedService) PostAddress(add users.Address, userid string) (string, error) { - err := db.CreateAddress(&add, userid) +func (s *fixedService) PostAddress(ctx context.Context, add users.Address, userid string) (string, error) { + err := db.CreateAddress(ctx, &add, userid) return add.ID, err } -func (s *fixedService) GetCards(id string) ([]users.Card, error) { +func (s *fixedService) GetCards(ctx context.Context, id string) ([]users.Card, error) { if id == "" { - cs, err := db.GetCards() + cs, err := db.GetCards(ctx) for k, c := range cs { c.AddLinks() cs[k] = c } return cs, err } - c, err := db.GetCard(id) + c, err := db.GetCard(ctx, id) c.AddLinks() return []users.Card{c}, err } -func (s *fixedService) PostCard(card users.Card, userid string) (string, error) { - err := db.CreateCard(&card, userid) +func (s *fixedService) PostCard(ctx context.Context, card users.Card, userid string) (string, error) { + err := db.CreateCard(ctx, &card, userid) return card.ID, err } -func (s *fixedService) Delete(entity, id string) error { - return db.Delete(entity, id) +func (s *fixedService) Delete(ctx context.Context, entity, id string) error { + return db.Delete(ctx, entity, id) } func (s *fixedService) Health() []Health { diff --git a/db/db.go b/db/db.go index 9f4d28b3..d2c10dd7 100644 --- a/db/db.go +++ b/db/db.go @@ -1,6 +1,7 @@ package db import ( + "context" "errors" "flag" "fmt" @@ -31,7 +32,7 @@ type Database interface { var ( database string //DefaultDb is the database set for the microservice - DefaultDb Database + DefaultDb TracingMiddleware //DBTypes is a map of DB interfaces that can be used for this service DBTypes = map[string]Database{} //ErrNoDatabaseFound error returnes when database interface does not exists in DBTypes @@ -60,7 +61,7 @@ func Init() error { //Set the DefaultDb func Set() error { if v, ok := DBTypes[database]; ok { - DefaultDb = v + DefaultDb = DbTracingMiddleware()(v) return nil } return fmt.Errorf(ErrNoDatabaseFound, database) @@ -72,13 +73,13 @@ func Register(name string, db Database) { } //CreateUser invokes DefaultDb method -func CreateUser(u *users.User) error { - return DefaultDb.CreateUser(u) +func CreateUser(ctx context.Context, u *users.User) error { + return DefaultDb.CreateUser(ctx, u) } //GetUserByName invokes DefaultDb method -func GetUserByName(n string) (users.User, error) { - u, err := DefaultDb.GetUserByName(n) +func GetUserByName(ctx context.Context, n string) (users.User, error) { + u, err := DefaultDb.GetUserByName(ctx, n) if err == nil { u.AddLinks() } @@ -86,8 +87,8 @@ func GetUserByName(n string) (users.User, error) { } //GetUser invokes DefaultDb method -func GetUser(n string) (users.User, error) { - u, err := DefaultDb.GetUser(n) +func GetUser(ctx context.Context, n string) (users.User, error) { + u, err := DefaultDb.GetUser(ctx, n) if err == nil { u.AddLinks() } @@ -95,8 +96,8 @@ func GetUser(n string) (users.User, error) { } //GetUsers invokes DefaultDb method -func GetUsers() ([]users.User, error) { - us, err := DefaultDb.GetUsers() +func GetUsers(ctx context.Context) ([]users.User, error) { + us, err := DefaultDb.GetUsers(ctx) for k, _ := range us { us[k].AddLinks() } @@ -104,8 +105,8 @@ func GetUsers() ([]users.User, error) { } //GetUserAttributes invokes DefaultDb method -func GetUserAttributes(u *users.User) error { - err := DefaultDb.GetUserAttributes(u) +func GetUserAttributes(ctx context.Context, u *users.User) error { + err := DefaultDb.GetUserAttributes(ctx, u) if err != nil { return err } @@ -119,13 +120,13 @@ func GetUserAttributes(u *users.User) error { } //CreateAddress invokes DefaultDb method -func CreateAddress(a *users.Address, userid string) error { - return DefaultDb.CreateAddress(a, userid) +func CreateAddress(ctx context.Context, a *users.Address, userid string) error { + return DefaultDb.CreateAddress(ctx, a, userid) } //GetAddress invokes DefaultDb method -func GetAddress(n string) (users.Address, error) { - a, err := DefaultDb.GetAddress(n) +func GetAddress(ctx context.Context, n string) (users.Address, error) { + a, err := DefaultDb.GetAddress(ctx, n) if err == nil { a.AddLinks() } @@ -133,8 +134,8 @@ func GetAddress(n string) (users.Address, error) { } //GetAddresses invokes DefaultDb method -func GetAddresses() ([]users.Address, error) { - as, err := DefaultDb.GetAddresses() +func GetAddresses(ctx context.Context) ([]users.Address, error) { + as, err := DefaultDb.GetAddresses(ctx) for k, _ := range as { as[k].AddLinks() } @@ -142,18 +143,18 @@ func GetAddresses() ([]users.Address, error) { } //CreateCard invokes DefaultDb method -func CreateCard(c *users.Card, userid string) error { - return DefaultDb.CreateCard(c, userid) +func CreateCard(ctx context.Context, c *users.Card, userid string) error { + return DefaultDb.CreateCard(ctx, c, userid) } //GetCard invokes DefaultDb method -func GetCard(n string) (users.Card, error) { - return DefaultDb.GetCard(n) +func GetCard(ctx context.Context, n string) (users.Card, error) { + return DefaultDb.GetCard(ctx, n) } //GetCards invokes DefaultDb method -func GetCards() ([]users.Card, error) { - cs, err := DefaultDb.GetCards() +func GetCards(ctx context.Context) ([]users.Card, error) { + cs, err := DefaultDb.GetCards(ctx) for k, _ := range cs { cs[k].AddLinks() } @@ -161,8 +162,8 @@ func GetCards() ([]users.Card, error) { } //Delete invokes DefaultDb method -func Delete(entity, id string) error { - return DefaultDb.Delete(entity, id) +func Delete(ctx context.Context, entity, id string) error { + return DefaultDb.Delete(ctx, entity, id) } //Ping invokes DefaultDB method diff --git a/db/tracing_middleware.go b/db/tracing_middleware.go new file mode 100644 index 00000000..890477bc --- /dev/null +++ b/db/tracing_middleware.go @@ -0,0 +1,134 @@ +package db + +import ( + "context" + "os" + "unsafe" + + "github.com/microservices-demo/user/users" + + stdopentracing "github.com/opentracing/opentracing-go" +) + +type TracingMiddleware struct { + next Database +} + +// Middleware decorates a database. +type Middleware func(Database) TracingMiddleware + +// DbTracingMiddleware traces database calls. +func DbTracingMiddleware() Middleware { + return func(next Database) TracingMiddleware { + return TracingMiddleware{ + next: next, + } + } +} + +func (mw TracingMiddleware) Init() error { + return mw.next.Init() +} + +func (mw TracingMiddleware) CreateAddress(ctx context.Context, a *users.Address, userid string) error { + span := startSpan(ctx, "create address on db") + err := mw.next.CreateAddress(a, userid) + finishSpan(span, 0) + return err +} + +func (mw TracingMiddleware) CreateCard(ctx context.Context, c *users.Card, userid string) error { + span := startSpan(ctx, "create card on db") + err := mw.next.CreateCard(c, userid) + finishSpan(span, 0) + return err +} + +func (mw TracingMiddleware) CreateUser(ctx context.Context, u *users.User) error { + span := startSpan(ctx, "create card on db") + err := mw.next.CreateUser(u) + finishSpan(span, 0) + return err +} + +func (mw TracingMiddleware) Delete(ctx context.Context, entity, id string) error { + span := startSpan(ctx, "delete from db") + err := mw.next.Delete(entity, id) + finishSpan(span, 0) + return err +} + +func (mw TracingMiddleware) GetAddress(ctx context.Context, n string) (users.Address, error) { + span := startSpan(ctx, "address from db") + a, err := mw.next.GetAddress(n) + finishSpan(span, unsafe.Sizeof(a)) + return a, err +} + +func (mw TracingMiddleware) GetAddresses(ctx context.Context) ([]users.Address, error) { + span := startSpan(ctx, "addresses from db") + a, err := mw.next.GetAddresses() + finishSpan(span, unsafe.Sizeof(a)) + return a, err +} + +func (mw TracingMiddleware) GetCard(ctx context.Context, n string) (users.Card, error) { + span := startSpan(ctx, "card from db") + c, err := mw.next.GetCard(n) + finishSpan(span, unsafe.Sizeof(c)) + return c, err +} + +func (mw TracingMiddleware) GetCards(ctx context.Context) ([]users.Card, error) { + span := startSpan(ctx, "cards from db") + c, err := mw.next.GetCards() + finishSpan(span, unsafe.Sizeof(c)) + return c, err +} + + +func (mw TracingMiddleware) GetUserByName(ctx context.Context, n string) (users.User, error) { + span := startSpan(ctx, "user from db") + u, err := mw.next.GetUserByName(n) + finishSpan(span, unsafe.Sizeof(u)) + return u, err +} + +func (mw TracingMiddleware) GetUser(ctx context.Context, n string) (users.User, error) { + span := startSpan(ctx, "user from db") + u, err := mw.next.GetUser(n) + finishSpan(span, unsafe.Sizeof(u)) + return u, err +} + +func (mw TracingMiddleware) GetUsers(ctx context.Context) ([]users.User, error) { + span := startSpan(ctx, "users from db") + us, err := mw.next.GetUsers() + finishSpan(span, unsafe.Sizeof(us)) + return us, err +} + +func (mw TracingMiddleware) GetUserAttributes(ctx context.Context, u *users.User) error { + span := startSpan(ctx, "user attributes from db") + err := mw.next.GetUserAttributes(u) + finishSpan(span, unsafe.Sizeof(u)) + return err +} + +func (mw TracingMiddleware) Ping() error { + return mw.next.Ping() +} + +func startSpan(ctx context.Context, n string) stdopentracing.Span { + var span stdopentracing.Span + span, ctx = stdopentracing.StartSpanFromContext(ctx, n) + span.SetTag("span.kind", "client") + span.SetTag("db.type", os.Getenv("USER_DATABASE")) + span.SetTag("peer.address", os.Getenv("MONGO_HOST")) + return span +} + +func finishSpan(span stdopentracing.Span, size uintptr) { + span.SetTag("db.query.result.size", size) + span.Finish() +}