# 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)

### 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)

### [Pandora Logging guideline](https://github.com/deliveryhero/pd-box/blob/master/docs/Pandora-Resources/Guidelines/observability/logging/README.md#application-messages)

* 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)

## 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)

[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)

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.

## 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.