# Observability - Attributes ## What is attributes ### A structured metadata of a observability data [Log](https://app.datadoghq.eu/logs?query=service%3Adine-in-order-worker%20consumed%20&cols=host%2Cservice&event=AgAAAYiRSWuAK0nHEAAAAAAAAAAYAAAAAEFZaVJTWXRJQUFEUUxJVjRBeEY3elFEVAAAACQAAAAAMDE4ODkxNjEtMGJhNy00ZmUzLWJhNmYtNzg4YTE0NGNjNTA2&index=&messageDisplay=inline&stream_sort=time%2Cdesc&viz=stream&from_ts=1674444073548&to_ts=1675048873548&live=true) ![](https://hackmd.io/_uploads/Sy0IuD6Lh.png) ### A unified query parameter [customer log dashboard](https://app.datadoghq.eu/dashboard/2i5-p72-ara/pandoraall-log-messages-for-a-customer?tpl_var_CustomerCode=o0ddv1hj&from_ts=1684299380610&to_ts=1684904180610&live=true) ![](https://hackmd.io/_uploads/SJBjaUT8h.png) ### [Pandora Logging guideline](https://github.com/deliveryhero/pd-box/blob/master/docs/Pandora-Resources/Guidelines/observability/logging/README.md#application-messages) ![](https://hackmd.io/_uploads/HJaVC8a82.png) * In Dine in, the important domain object for us in the Pandora domain * Order * `pandora.order.code` * Customer * `pandora.customer.code` * Vendor * `pandora.vendor.code` * Tabsquare * dine-in specific * `pandora.tabsquare.intent_id` * Use `.` seperator, so the datadog can help us structure the [log](https://app.datadoghq.eu/logs?query=service%3Adine-in-order-worker%20consumed%20country%3Aph%20env%3Astaging%20&cols=host%2Cservice&event=AgAAAYiKtO0IRjseAQAAAAAAAAAYAAAAAEFZaUt0UHVwQUFCMUhhenliVjBKbFFFMgAAACQAAAAAMDE4ODhiNjgtODZkYi00MTY2LWJjYzYtMjc3MTkwZDkyMzNj&index=&messageDisplay=inline&stream_sort=time%2Cdesc&viz=stream&from_ts=1674444073548&to_ts=1675048873548&live=true) ![](https://hackmd.io/_uploads/Sy5DFPpLh.png) ## How we implement the attributes * [Context](https://go.dev/blog/context) * Cancel, Timeout * **Request Scoped Value** * [StartSpanFromContext](https://pkg.go.dev/gopkg.in/datadog/dd-trace-go.v1/ddtrace/tracer#StartSpanFromContext) * Pandora * Mikro - [attributes package](https://github.com/deliveryhero/mikro/blob/master/pkg/observability/attributes/attributes.go) * pd-go-kit - [LogData](https://github.com/deliveryhero/pd-go-kit/blob/master/logger.go#L69) * [dine-in logger](https://github.com/deliveryhero/pd-dine-in/blob/master/internal/infrastructure/logger/context.go) ```go // mikro attributes func NewContext(ctx context.Context, attrs *Attributes) context.Context { return context.WithValue(ctx, key, attrs) } func FromContext(ctx context.Context) (*Attributes, bool) { attrs := ctx.Value(key) if p, ok := attrs.(*Attributes); ok { return p, true } return New(nil), false } // LogData func ContextWithLogData(ctx context.Context, additionalLogData map[string]interface{}) context.Context { logMu.Lock() defer logMu.Unlock() logData, ok := ctx.Value(ContextKeyLogData).(map[string]interface{}) if !ok { return context.WithValue(ctx, ContextKeyLogData, additionalLogData) } for k, v := range additionalLogData { logData[k] = v } return context.WithValue(ctx, ContextKeyLogData, logData) } func AddLogData(ctx context.Context, field string, data interface{}) error { logMu.Lock() defer logMu.Unlock() logData, ok := ctx.Value(ContextKeyLogData).(map[string]interface{}) if !ok { logData = make(map[string]interface{}) } if data == nil { delete(logData, field) return nil } logData[field] = data if !ok { return errors.New("LogData was not initialized in this context") } return nil } ``` ### Example [DIOS consumer-handling middleware](https://github.com/deliveryhero/pd-dine-in-order-service/blob/master/internal/infra/events/middleware/consumer_handling_log.go) ```go func ConsumerHandlingLog(lgr logger.WithCustomAttrs) localsqs.Middleware { return func(handler localsqs.HandlerFunc) localsqs.HandlerFunc { return func(ctx context.Context, msg *sqs.Message) (err error) { err = handler(ctx, msg) attrs, _ := attributes.FromContext(ctx) attrs.Set(constants.AttrEventRawMessage, *msg.Body) loggerWithAttrs := lgr.AddAttrs(observability.GetAttrsForWorkerLogging(ctx)) if err == nil { loggerWithAttrs.Info("consumed successfully") } else { loggerWithAttrs.Errorf("failed to consume message") } return err } } } ``` [Payment update](https://app.datadoghq.eu/logs?query=service%3Adine-in-order-worker%20consumed%20&cols=host%2Cservice&event=AgAAAYiRSWuAK0nHEAAAAAAAAAAYAAAAAEFZaVJTWXRJQUFEUUxJVjRBeEY3elFEVAAAACQAAAAAMDE4ODkxNjEtMGJhNy00ZmUzLWJhNmYtNzg4YTE0NGNjNTA2&index=%2A&messageDisplay=inline&stream_sort=desc&viz=stream&from_ts=1685843849697&to_ts=1686103049697&live=true) ![](https://hackmd.io/_uploads/rynLVv6L2.png) [Dine in order update](https://app.datadoghq.eu/logs?query=service%3Adine-in-order-worker%20consumed%20&cols=host%2Cservice&event=AgAAAYiRSWuAK0nHDAAAAAAAAAAYAAAAAEFZaVJTWXRJQUFEUUxJVjRBeEY3elFEUAAAACQAAAAAMDE4ODkxNjEtMGJhNy00ZmUzLWJhNmYtNzg4YTE0NGNjNTA2&index=%2A&messageDisplay=inline&stream_sort=desc&viz=stream&from_ts=1685843849697&to_ts=1686103049697&live=true) ![](https://hackmd.io/_uploads/HJTI4Da8n.png) Question: Why the dine in order updated log does not have [event type](https://github.com/deliveryhero/pd-dine-in-order-service/blob/master/internal/infra/events/handlers/dinein/handler.go#L109) and [order code](https://github.com/deliveryhero/pd-dine-in-order-service/blob/718f0df01b0cd51db561df7333160414c2c145f7/internal/infra/events/handlers/dinein/handler.go#LL127C8-L127C8) attributes even we already set it in our code? In mikro, `attributes` is not only for logging attributes, but also for [trace span tag](https://github.com/deliveryhero/mikro/blob/04d544909fcdf1e626351e1442580d37a4b7395d/pkg/mikroworker/middleware/sqs/ddtracing.go#L38). note: Not implemented by dine-in-api, it would have seperate attributes for now. ![](https://hackmd.io/_uploads/Sy26rvaIn.png) ## Next Sharing - How to unified the attributes across services * Upstream - Downstream log * Http * Upstream - Request Response Log Middleware * DownStream - Http Client * Grpc * Upstream - Request Response Log interceptor * DownStream - grpc Client * Worker * Upstream - Middle ware * DownStream - AWS client * Pandora Guideline Attributes constants.