func SelectKeys(m map[string]interface{}, keys ...string) Tags {
	tags := Tags{}
	for _, k := range keys {
		if v, ok := m[k]; ok {
			tags[k] = v
		}
	}
	return tags
}
SelectKeys returns a map containing only the specified fields
This argument purposefully not typed as Tags, such that logrus.Fields and Tags can both be passed without additional casting.
Useful when specifying a Loggable/Taggable
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}
}
func WithTagLogFields(ctx context.Context, tags map[string]interface{}) context.Context {
	ctx = logger.WithFields(ctx, tags)
	ctx = WithTags(ctx, tags)
	return ctx
}
func WithTagLoggable(ctx context.Context, l logger.Loggable) context.Context {
	ctx = logger.WithLoggable(ctx, l)
	if taggable, ok := l.(Taggable); ok {
		ctx = WithTaggable(ctx, taggable)
	} else {
		ctx = WithTaggable(ctx, tagLoggable{l})
	}
	return ctx
}
type tagLoggable struct {
	logger.Loggable
}
func (l tagLoggable) StatsTags() Tags {
	return Tags(l.LogFields())
}
func WatchingTagLoggable(ctx context.Context, l logger.Loggable) context.Context {
	ctx = logger.WatchingLoggable(ctx, l)
	if taggable, ok := l.(Taggable); ok {
		ctx = WatchingTaggable(ctx, taggable)
	} else {
		ctx = WatchingTaggable(ctx, tagLoggable{l})
	}
	return ctx
}
func getStatsTags(ctx context.Context, extraTagList ...Tags) []string {
	tags := getStatsTagsMap(ctx)
	for _, extraTags := range extraTagList {
		for k, v := range extraTags {
			tags[k] = v
		}
	}
	list := make([]string, 0, len(tags))
	for k, v := range tags {
		list = append(list, fmt.Sprintf("%s:%v", k, v))
	}
	sort.Strings(list)
	return list
}
func getStatsTagsMap(ctx context.Context) Tags {
	if ctx != nil {
		fields, _ := ctx.Value(tagsKey).(Tags)
		if fields != nil {
			return fields
		}
	}
	return Tags{}
}