---
# System prepended metadata

title: Observability - Attributes

---

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