func WithTagLogFields(ctx context.Context, tags map[string]interface{}) context.Context {
	ctx = logger.WithFields(ctx, tags)
	ctx = WithTags(ctx, tags)
	return ctx
}
WithTagLogFields combines logger.WithFields(fields) and WithTags(tags)
This simplifies the common operation of adding fields to the logger and the metrics
This argument purposefully not typed as Tags, such that logrus.Fields and Tags can both be passed without additional casting.
package statsd
import (
	"context"
	"fmt"
	"sort"
	"github.com/Shopify/goose/logger"
)
type contextKey int
const (
	tagsKey contextKey = iota
)
type Tags map[string]interface{}
type Taggable interface {
	StatsTags() Tags
}
type keyValueContext struct {
	context.Context
	key   string
	value interface{}
}
func (c *keyValueContext) Value(key interface{}) interface{} {
	if key == tagsKey {
		prev := getStatsTagsMap(c.Context)
		prev[c.key] = c.value
		return prev
	}
	return c.Context.Value(key)
}
type taggableContext struct {
	context.Context
	taggable Taggable
}
func (c *taggableContext) Value(key interface{}) interface{} {
	if key == tagsKey {
		prev := getStatsTagsMap(c.Context)
		for k, v := range c.taggable.StatsTags() {
			prev[k] = v
		}
		return prev
	}
	return c.Context.Value(key)
}
func WithTag(ctx context.Context, k string, v interface{}) context.Context {
	return &keyValueContext{Context: ctx, key: k, value: v}
}
func WithTags(ctx context.Context, t Tags) context.Context {
	for k, v := range t {
		ctx = WithTag(ctx, k, v)
	}
	return ctx
}
func WithTaggable(ctx context.Context, t Taggable) context.Context {
	return WithTags(ctx, t.StatsTags())
}
func WatchingTaggable(ctx context.Context, t Taggable) context.Context {
	return &taggableContext{Context: ctx, taggable: t}
}