Repository: atlassian/gostatsd
Pull request #330 (2020-07-07 12:47:30)

Refactor source address
Writing the description of how `Source` is handled it possibly the most depressing thing I've done in this code base.  I don't even recall why I needed to do this anymore, but I know there was a good reason, which I'll remember tomorrow.

I'm very tempted to go one more level and remove `Source` as a field entirely, replacing it with a `Source()` function which just uses the `host` tag.

Generally the first 3 commits can be ignored, with the actual changes living in e8dedc3 and 06592ea.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27eb073..e981832 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+27.0.0
+------
+- Simplify internal tracking of the source address of a metric.  The current rules are:
+
+If ignore-host is set, it will be set to the `host` tag if present, otherwise blank.  If ignore-host is not set, it will be set to the sending IP
+If the cloud provider is enabled, it will attempt to perform a lookup of this value to find a new value (instance ID, pod ID, etc)
+If the tag handler matches a `drop-host` filter, it will be removed
+Backends use it inconsistently
+
+This really is simpler than it was before.
+
 26.0.0
 ------
 - Adds new options `flush-offset` and `flush-aligned` to align the flush interval to a configurable multiple.  See [README.md](README.md) for details.
diff --git a/cloudprovider.go b/cloudprovider.go
index b17dc43..d410d8e 100644
--- a/cloudprovider.go
+++ b/cloudprovider.go
@@ -13,7 +13,7 @@ type CloudProviderFactory func(v *viper.Viper, logger logrus.FieldLogger, versio
 
 // Instance represents a cloud instance.
 type Instance struct {
-	ID   string
+	ID   Source
 	Tags Tags
 }
 
@@ -25,17 +25,15 @@ type CloudProvider interface {
 	// Instance returns instances details from the cloud provider.
 	// ip -> nil pointer if instance was not found.
 	// map is returned even in case of errors because it may contain partial data.
-	Instance(context.Context, ...IP) (map[IP]*Instance, error)
+	Instance(context.Context, ...Source) (map[Source]*Instance, error)
 	// MaxInstancesBatch returns maximum number of instances that could be requested via the Instance method.
 	MaxInstancesBatch() int
-	// SelfIP returns host's IPv4 address.
-	SelfIP() (IP, error)
 	// EstimatedTags returns a guess of how many tags are likely to be added by the CloudProvider
 	EstimatedTags() int
 }
 
 type InstanceInfo struct {
-	IP IP
+	IP Source
 	// Instance may be nil if the lookup resulted in an error or instance was not found.
 	Instance *Instance
 }
@@ -46,10 +44,10 @@ type CachedInstancesFactory func(v *viper.Viper, logger logrus.FieldLogger, vers
 type CachedInstances interface {
 	// Peek fetches instance information from the cache.
 	// The cache is also a negative cache - may be a cache hit but the returned instance is nil.
-	Peek(IP) (*Instance, bool /*is a cache hit*/)
+	Peek(Source) (*Instance, bool /*is a cache hit*/)
 	// IpSink returns a channel that can be used to supply IP addresses for which information needs
 	// to be fetched and cached.
-	IpSink() chan<- IP
+	IpSink() chan<- Source
 	// InfoSource returns a channel that can be used to receive information about IPs.
 	InfoSource() <-chan InstanceInfo
 	// EstimatedTags returns a guess for how many tags to pre-allocate
diff --git a/cmd/gostatsd/main.go b/cmd/gostatsd/main.go
index 594edec..0e625f9 100644
--- a/cmd/gostatsd/main.go
+++ b/cmd/gostatsd/main.go
@@ -93,7 +93,6 @@ func constructServer(v *viper.Viper) (*statsd.Server, error) {
 
 	// Cached instances
 	var cachedInstances gostatsd.CachedInstances
-	selfIP := gostatsd.UnknownIP
 	cloudProviderName := v.GetString(gostatsd.ParamCloudProvider)
 	if cloudProviderName == "" {
 		logger.Info("No cloud provider specified")
@@ -110,12 +109,6 @@ func constructServer(v *viper.Viper) (*statsd.Server, error) {
 				return nil, err
 			}
 			runnables = gostatsd.MaybeAppendRunnable(runnables, cloudProvider)
-			selfIPtmp, err := cloudProvider.SelfIP()
-			if err != nil {
-				logger.WithError(err).Warn("Failed to get self ip")
-			} else {
-				selfIP = selfIPtmp
-			}
 			cachedInstances = newCachedInstancesFromViper(logger, cloudProvider, v)
 		default:
 			return nil, err
@@ -153,8 +146,7 @@ func constructServer(v *viper.Viper) (*statsd.Server, error) {
 		InternalTags:          v.GetStringSlice(gostatsd.ParamInternalTags),
 		InternalNamespace:     v.GetString(gostatsd.ParamInternalNamespace),
 		DefaultTags:           v.GetStringSlice(gostatsd.ParamDefaultTags),
-		Hostname:              v.GetString(gostatsd.ParamHostname),
-		SelfIP:                selfIP,
+		Hostname:              gostatsd.Source(v.GetString(gostatsd.ParamHostname)),
 		ExpiryIntervalCounter: v.GetDuration(gostatsd.ParamExpiryIntervalCounter),
 		ExpiryIntervalGauge:   v.GetDuration(gostatsd.ParamExpiryIntervalGauge),
 		ExpiryIntervalSet:     v.GetDuration(gostatsd.ParamExpiryIntervalSet),
diff --git a/counters.go b/counters.go
index e32b60c..6ac842a 100644
--- a/counters.go
+++ b/counters.go
@@ -5,13 +5,13 @@ type Counter struct {
 	PerSecond float64  // The calculated per second rate
 	Value     int64    // The numeric value of the metric
 	Timestamp Nanotime // Last time value was updated
-	Hostname  string   // Hostname of the source of the metric
+	Source    Source   // Source of the metric
 	Tags      Tags     // The tags for the counter
 }
 
 // NewCounter initialises a new counter.
-func NewCounter(timestamp Nanotime, value int64, hostname string, tags Tags) Counter {
-	return Counter{Value: value, Timestamp: timestamp, Hostname: hostname, Tags: tags.Copy()}
+func NewCounter(timestamp Nanotime, value int64, source Source, tags Tags) Counter {
+	return Counter{Value: value, Timestamp: timestamp, Source: source, Tags: tags.Copy()}
 }
 
 // Counters stores a map of counters by tags.
diff --git a/events.go b/events.go
index fc2a597..a0ced8e 100644
--- a/events.go
+++ b/events.go
@@ -78,16 +78,14 @@ type Event struct {
 	Text string
 	// DateHappened of the event. Unix epoch timestamp. Default is now when not specified in incoming metric.
 	DateHappened int64
-	// Hostname of the event. This field contains information that is received in the body of the event (optional).
-	Hostname string
 	// AggregationKey of the event, to group it with some other events.
 	AggregationKey string
 	// SourceTypeName of the event.
 	SourceTypeName string
 	// Tags of the event.
 	Tags Tags
-	// IP of the source of the metric
-	SourceIP IP
+	// Source of the metric
+	Source Source
 	// Priority of the event.
 	Priority Priority
 	// AlertType of the event.
diff --git a/gauges.go b/gauges.go
index 41356c5..68c567c 100644
--- a/gauges.go
+++ b/gauges.go
@@ -4,13 +4,13 @@ package gostatsd
 type Gauge struct {
 	Value     float64  // The numeric value of the metric
 	Timestamp Nanotime // Last time value was updated
-	Hostname  string   // Hostname of the source of the metric
+	Source    Source   // Source of the metric
 	Tags      Tags     // The tags for the gauge
 }
 
 // NewGauge initialises a new gauge.
-func NewGauge(timestamp Nanotime, value float64, hostname string, tags Tags) Gauge {
-	return Gauge{Value: value, Timestamp: timestamp, Hostname: hostname, Tags: tags.Copy()}
+func NewGauge(timestamp Nanotime, value float64, source Source, tags Tags) Gauge {
+	return Gauge{Value: value, Timestamp: timestamp, Source: source, Tags: tags.Copy()}
 }
 
 // Gauges stores a map of gauges by tags.
diff --git a/metric_map.go b/metric_map.go
index 21bc6de..ffdf61e 100644
--- a/metric_map.go
+++ b/metric_map.go
@@ -142,7 +142,7 @@ func (mm *MetricMap) Split(count int) []*MetricMap {
 	}
 
 	mm.Counters.Each(func(metricName string, tagsKey string, c Counter) {
-		mmSplit := maps[Bucket(metricName, c.Hostname, count)]
+		mmSplit := maps[Bucket(metricName, c.Source, count)]
 		if v, ok := mmSplit.Counters[metricName]; ok {
 			v[tagsKey] = c
 		} else {
@@ -150,7 +150,7 @@ func (mm *MetricMap) Split(count int) []*MetricMap {
 		}
 	})
 	mm.Gauges.Each(func(metricName string, tagsKey string, g Gauge) {
-		mmSplit := maps[Bucket(metricName, g.Hostname, count)]
+		mmSplit := maps[Bucket(metricName, g.Source, count)]
 		if v, ok := mmSplit.Gauges[metricName]; ok {
 			v[tagsKey] = g
 		} else {
@@ -158,7 +158,7 @@ func (mm *MetricMap) Split(count int) []*MetricMap {
 		}
 	})
 	mm.Timers.Each(func(metricName string, tagsKey string, t Timer) {
-		mmSplit := maps[Bucket(metricName, t.Hostname, count)]
+		mmSplit := maps[Bucket(metricName, t.Source, count)]
 		if v, ok := mmSplit.Timers[metricName]; ok {
 			v[tagsKey] = t
 		} else {
@@ -166,7 +166,7 @@ func (mm *MetricMap) Split(count int) []*MetricMap {
 		}
 	})
 	mm.Sets.Each(func(metricName string, tagsKey string, s Set) {
-		mmSplit := maps[Bucket(metricName, s.Hostname, count)]
+		mmSplit := maps[Bucket(metricName, s.Source, count)]
 		if v, ok := mmSplit.Sets[metricName]; ok {
 			v[tagsKey] = s
 		} else {
@@ -265,12 +265,12 @@ func (mm *MetricMap) receiveCounter(m *Metric, tagsKey string) {
 				c.Timestamp = m.Timestamp
 			}
 		} else {
-			c = NewCounter(m.Timestamp, value, m.Hostname, m.Tags)
+			c = NewCounter(m.Timestamp, value, m.Source, m.Tags)
 		}
 		v[tagsKey] = c
 	} else {
 		mm.Counters[m.Name] = map[string]Counter{
-			tagsKey: NewCounter(m.Timestamp, value, m.Hostname, m.Tags),
+			tagsKey: NewCounter(m.Timestamp, value, m.Source, m.Tags),
 		}
 	}
 }
@@ -285,12 +285,12 @@ func (mm *MetricMap) receiveGauge(m *Metric, tagsKey string) {
 				g.Timestamp = m.Timestamp
 			}
 		} else {
-			g = NewGauge(m.Timestamp, m.Value, m.Hostname, m.Tags)
+			g = NewGauge(m.Timestamp, m.Value, m.Source, m.Tags)
 		}
 		v[tagsKey] = g
 	} else {
 		mm.Gauges[m.Name] = map[string]Gauge{
-			tagsKey: NewGauge(m.Timestamp, m.Value, m.Hostname, m.Tags),
+			tagsKey: NewGauge(m.Timestamp, m.Value, m.Source, m.Tags),
 		}
 	}
 }
@@ -306,12 +306,12 @@ func (mm *MetricMap) receiveTimer(m *Metric, tagsKey string) {
 			}
 			t.SampledCount += 1.0 / m.Rate
 		} else {
-			t = NewTimer(m.Timestamp, []float64{m.Value}, m.Hostname, m.Tags)
+			t = NewTimer(m.Timestamp, []float64{m.Value}, m.Source, m.Tags)
 			t.SampledCount = 1.0 / m.Rate
 		}
 		v[tagsKey] = t
 	} else {
-		t := NewTimer(m.Timestamp, []float64{m.Value}, m.Hostname, m.Tags)
+		t := NewTimer(m.Timestamp, []float64{m.Value}, m.Source, m.Tags)
 		t.SampledCount = 1.0 / m.Rate
 
 		mm.Timers[m.Name] = map[string]Timer{
@@ -330,12 +330,12 @@ func (mm *MetricMap) receiveSet(m *Metric, tagsKey string) {
 				s.Timestamp = m.Timestamp
 			}
 		} else {
-			s = NewSet(m.Timestamp, map[string]struct{}{m.StringValue: {}}, m.Hostname, m.Tags)
+			s = NewSet(m.Timestamp, map[string]struct{}{m.StringValue: {}}, m.Source, m.Tags)
 		}
 		v[tagsKey] = s
 	} else {
 		mm.Sets[m.Name] = map[string]Set{
-			tagsKey: NewSet(m.Timestamp, map[string]struct{}{m.StringValue: {}}, m.Hostname, m.Tags),
+			tagsKey: NewSet(m.Timestamp, map[string]struct{}{m.StringValue: {}}, m.Source, m.Tags),
 		}
 	}
 }
@@ -372,7 +372,7 @@ func (mm *MetricMap) DispatchMetrics(ctx context.Context, handler RawMetricHandl
 			Tags:      c.Tags.Copy(),
 			TagsKey:   tagsKey,
 			Timestamp: c.Timestamp,
-			Hostname:  c.Hostname,
+			Source:    c.Source,
 		}
 		metrics = append(metrics, m)
 	})
@@ -386,7 +386,7 @@ func (mm *MetricMap) DispatchMetrics(ctx context.Context, handler RawMetricHandl
 			Tags:      g.Tags.Copy(),
 			TagsKey:   tagsKey,
 			Timestamp: g.Timestamp,
-			Hostname:  g.Hostname,
+			Source:    g.Source,
 		}
 		metrics = append(metrics, m)
 	})
@@ -404,7 +404,7 @@ func (mm *MetricMap) DispatchMetrics(ctx context.Context, handler RawMetricHandl
 				Tags:      t.Tags.Copy(),
 				TagsKey:   tagsKey,
 				Timestamp: t.Timestamp,
-				Hostname:  t.Hostname,
+				Source:    t.Source,
 			}
 			metrics = append(metrics, m)
 		}
@@ -420,7 +420,7 @@ func (mm *MetricMap) DispatchMetrics(ctx context.Context, handler RawMetricHandl
 				Tags:        s.Tags.Copy(),
 				TagsKey:     tagsKey,
 				Timestamp:   s.Timestamp,
-				Hostname:    s.Hostname,
+				Source:      s.Source,
 			}
 			metrics = append(metrics, m)
 		}
diff --git a/metrics.go b/metrics.go
index 4aa2fe5..374a256 100644
--- a/metrics.go
+++ b/metrics.go
@@ -36,17 +36,21 @@ func (m MetricType) String() string {
 
 // Metric represents a single data collected datapoint.
 type Metric struct {
-	Name        string     // The name of the metric
-	Value       float64    // The numeric value of the metric
-	Rate        float64    // The sampling rate of the metric
-	Tags        Tags       // The tags for the metric
-	TagsKey     string     // The tags rendered as a string to uniquely identify the tagset in a map.  Sort of a cache.  Will be removed at some point.
-	StringValue string     // The string value for some metrics e.g. Set
-	Hostname    string     // Hostname of the source of the metric
-	SourceIP    IP         // IP of the source of the metric
-	Timestamp   Nanotime   // Most accurate known timestamp of this metric
-	Type        MetricType // The type of metric
-	DoneFunc    func()     // Returns the metric to the pool. May be nil. Call Metric.Done(), not this.
+	Name        string  // The name of the metric
+	Value       float64 // The numeric value of the metric
+	Rate        float64 // The sampling rate of the metric
+	Tags        Tags    // The tags for the metric
+	TagsKey     string  // The tags rendered as a string to uniquely identify the tagset in a map.  Sort of a cache.  Will be removed at some point.
+	StringValue string  // The string value for some metrics e.g. Set
+	// Source is the source of the metric, its lifecycle is:
+	// - If ignore-host is set, it will be set to the `host` tag if present, otherwise blank.  If ignore-host is not set, it will be set to the sending IP
+	// - If the cloud provider is enabled, it will attempt to perform a lookup of this value to find a new value (instance ID, pod ID, etc)
+	// - If the tag handler matches a `drop-host` filter, it will be removed
+	// - Backends treat it inconsistently
+	Source    Source     // Source of the metric.  In order of
+	Timestamp Nanotime   // Most accurate known timestamp of this metric
+	Type      MetricType // The type of metric
+	DoneFunc  func()     // Returns the metric to the pool. May be nil. Call Metric.Done(), not this.
 }
 
 // Reset is used to reset a metric to as clean state, called on re-use from the pool.
@@ -57,21 +61,20 @@ func (m *Metric) Reset() {
 	m.Tags = m.Tags[:0]
 	m.TagsKey = ""
 	m.StringValue = ""
-	m.Hostname = ""
-	m.SourceIP = ""
+	m.Source = ""
 	m.Timestamp = 0
 	m.Type = 0
 }
 
 // Bucket will pick a distribution bucket for this metric to land in.  max is exclusive.
 func (m *Metric) Bucket(max int) int {
-	return Bucket(m.Name, m.Hostname, max)
+	return Bucket(m.Name, m.Source, max)
 }
 
-func Bucket(metricName, hostname string, max int) int {
+func Bucket(metricName string, source Source, max int) int {
 	// Consider hashing the tags here too
 	bucket := adler32.Checksum([]byte(metricName))
-	bucket += adler32.Checksum([]byte(hostname))
+	bucket += adler32.Checksum([]byte(source))
 	return int(bucket % uint32(max))
 }
 
@@ -88,17 +91,17 @@ func (m *Metric) Done() {
 
 func (m *Metric) FormatTagsKey() string {
 	if m.TagsKey == "" {
-		m.TagsKey = FormatTagsKey(m.Hostname, m.Tags)
+		m.TagsKey = FormatTagsKey(m.Source, m.Tags)
 	}
 	return m.TagsKey
 }
 
-func FormatTagsKey(hostname string, tags Tags) string {
+func FormatTagsKey(source Source, tags Tags) string {
 	t := tags.SortedString()
-	if hostname == "" {
+	if source == "" {
 		return t
 	}
-	return t + "," + StatsdSourceID + ":" + hostname
+	return t + "," + StatsdSourceID + ":" + string(source)
 }
 
 // AggregatedMetrics is an interface for aggregated metrics.
diff --git a/pkg/backends/datadog/datadog.go b/pkg/backends/datadog/datadog.go
index 4b47bee..f1256f4 100644
--- a/pkg/backends/datadog/datadog.go
+++ b/pkg/backends/datadog/datadog.go
@@ -168,8 +168,8 @@ func (d *Client) processMetrics(now float64, metrics *gostatsd.MetricMap, cb fun
 	}
 
 	metrics.Counters.Each(func(key, tagsKey string, counter gostatsd.Counter) {
-		fl.addMetric(rate, counter.PerSecond, counter.Hostname, counter.Tags, key)
-		fl.addMetricf(gauge, float64(counter.Value), counter.Hostname, counter.Tags, "%s.count", key)
+		fl.addMetric(rate, counter.PerSecond, counter.Source, counter.Tags, key)
+		fl.addMetricf(gauge, float64(counter.Value), counter.Source, counter.Tags, "%s.count", key)
 		fl.maybeFlush()
 	})
 
@@ -181,51 +181,51 @@ func (d *Client) processMetrics(now float64, metrics *gostatsd.MetricMap, cb fun
 					bucketTag = "le:" + strconv.FormatFloat(float64(histogramThreshold), 'f', -1, 64)
 				}
 				newTags := timer.Tags.Concat(gostatsd.Tags{bucketTag})
-				fl.addMetricf(counter, float64(count), timer.Hostname, newTags, "%s.histogram", key)
+				fl.addMetricf(counter, float64(count), timer.Source, newTags, "%s.histogram", key)
 			}
 		} else {
 
 			if !d.disabledSubtypes.Lower {
-				fl.addMetricf(gauge, timer.Min, timer.Hostname, timer.Tags, "%s.lower", key)
+				fl.addMetricf(gauge, timer.Min, timer.Source, timer.Tags, "%s.lower", key)
 			}
 			if !d.disabledSubtypes.Upper {
-				fl.addMetricf(gauge, timer.Max, timer.Hostname, timer.Tags, "%s.upper", key)
+				fl.addMetricf(gauge, timer.Max, timer.Source, timer.Tags, "%s.upper", key)
 			}
 			if !d.disabledSubtypes.Count {
-				fl.addMetricf(gauge, float64(timer.Count), timer.Hostname, timer.Tags, "%s.count", key)
+				fl.addMetricf(gauge, float64(timer.Count), timer.Source, timer.Tags, "%s.count", key)
 			}
 			if !d.disabledSubtypes.CountPerSecond {
-				fl.addMetricf(rate, timer.PerSecond, timer.Hostname, timer.Tags, "%s.count_ps", key)
+				fl.addMetricf(rate, timer.PerSecond, timer.Source, timer.Tags, "%s.count_ps", key)
 			}
 			if !d.disabledSubtypes.Mean {
-				fl.addMetricf(gauge, timer.Mean, timer.Hostname, timer.Tags, "%s.mean", key)
+				fl.addMetricf(gauge, timer.Mean, timer.Source, timer.Tags, "%s.mean", key)
 			}
 			if !d.disabledSubtypes.Median {
-				fl.addMetricf(gauge, timer.Median, timer.Hostname, timer.Tags, "%s.median", key)
+				fl.addMetricf(gauge, timer.Median, timer.Source, timer.Tags, "%s.median", key)
 			}
 			if !d.disabledSubtypes.StdDev {
-				fl.addMetricf(gauge, timer.StdDev, timer.Hostname, timer.Tags, "%s.std", key)
+				fl.addMetricf(gauge, timer.StdDev, timer.Source, timer.Tags, "%s.std", key)
 			}
 			if !d.disabledSubtypes.Sum {
-				fl.addMetricf(gauge, timer.Sum, timer.Hostname, timer.Tags, "%s.sum", key)
+				fl.addMetricf(gauge, timer.Sum, timer.Source, timer.Tags, "%s.sum", key)
 			}
 			if !d.disabledSubtypes.SumSquares {
-				fl.addMetricf(gauge, timer.SumSquares, timer.Hostname, timer.Tags, "%s.sum_squares", key)
+				fl.addMetricf(gauge, timer.SumSquares, timer.Source, timer.Tags, "%s.sum_squares", key)
 			}
 			for _, pct := range timer.Percentiles {
-				fl.addMetricf(gauge, pct.Float, timer.Hostname, timer.Tags, "%s.%s", key, pct.Str)
+				fl.addMetricf(gauge, pct.Float, timer.Source, timer.Tags, "%s.%s", key, pct.Str)
 			}
 		}
 		fl.maybeFlush()
 	})
 
 	metrics.Gauges.Each(func(key, tagsKey string, g gostatsd.Gauge) {
-		fl.addMetric(gauge, g.Value, g.Hostname, g.Tags, key)
+		fl.addMetric(gauge, g.Value, g.Source, g.Tags, key)
 		fl.maybeFlush()
 	})
 
 	metrics.Sets.Each(func(key, tagsKey string, set gostatsd.Set) {
-		fl.addMetric(gauge, float64(len(set.Values)), set.Hostname, set.Tags, key)
+		fl.addMetric(gauge, float64(len(set.Values)), set.Source, set.Tags, key)
 		fl.maybeFlush()
 	})
 
@@ -254,7 +254,7 @@ func (d *Client) SendEvent(ctx context.Context, e *gostatsd.Event) error {
 			Title:          e.Title,
 			Text:           e.Text,
 			DateHappened:   e.DateHappened,
-			Hostname:       e.Hostname,
+			Hostname:       string(e.Source),
 			AggregationKey: e.AggregationKey,
 			SourceTypeName: e.SourceTypeName,
 			Tags:           e.Tags,
diff --git a/pkg/backends/datadog/flush.go b/pkg/backends/datadog/flush.go
index 53d00c1..567ac73 100644
--- a/pkg/backends/datadog/flush.go
+++ b/pkg/backends/datadog/flush.go
@@ -45,14 +45,14 @@ type metric struct {
 type point [2]float64
 
 // addMetricf adds a metric to the series.
-func (f *flush) addMetricf(metricType metricType, value float64, hostname string, tags gostatsd.Tags, nameFormat string, a ...interface{}) {
-	f.addMetric(metricType, value, hostname, tags, fmt.Sprintf(nameFormat, a...))
+func (f *flush) addMetricf(metricType metricType, value float64, source gostatsd.Source, tags gostatsd.Tags, nameFormat string, a ...interface{}) {
+	f.addMetric(metricType, value, source, tags, fmt.Sprintf(nameFormat, a...))
 }
 
 // addMetric adds a metric to the series.
-func (f *flush) addMetric(metricType metricType, value float64, hostname string, tags gostatsd.Tags, name string) {
+func (f *flush) addMetric(metricType metricType, value float64, source gostatsd.Source, tags gostatsd.Tags, name string) {
 	f.ts.Series = append(f.ts.Series, metric{
-		Host:     hostname,
+		Host:     string(source),
 		Interval: f.flushIntervalSec,
 		Metric:   name,
 		Points:   [1]point{{f.timestamp, value}},
diff --git a/pkg/backends/graphite/graphite.go b/pkg/backends/graphite/graphite.go
index 544e9da..f239863 100644
--- a/pkg/backends/graphite/graphite.go
+++ b/pkg/backends/graphite/graphite.go
@@ -111,7 +111,7 @@ func asGraphiteTag(tag string) string {
 
 // prepareName will create a metric name, handling correct prefix, suffixes, and tags, with an optional host tag if
 // not overridden by a tag on the metric.
-func (client *Client) prepareName(namespace, name, suffix, hostname string, tags gostatsd.Tags) string {
+func (client *Client) prepareName(namespace, name, suffix string, source gostatsd.Source, tags gostatsd.Tags) string {
 	buf := bytes.Buffer{}
 	if namespace != "" {
 		buf.WriteString(namespace)
@@ -137,9 +137,9 @@ func (client *Client) prepareName(namespace, name, suffix, hostname string, tags
 				haveHost = true
 			}
 		}
-		if !haveHost && hostname != "" {
+		if !haveHost && source != "" {
 			buf.WriteString(";host=")
-			buf.WriteString(hostname)
+			buf.WriteString(string(source))
 		}
 	}
 
@@ -151,13 +151,13 @@ func (client *Client) preparePayload(metrics *gostatsd.MetricMap, ts time.Time)
 	now := ts.Unix()
 	if client.legacyNamespace {
 		metrics.Counters.Each(func(key, tagsKey string, counter gostatsd.Counter) {
-			_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName("stats_counts", key, "", counter.Hostname, counter.Tags), counter.Value, now)
-			_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.counterNamespace, key, "", counter.Hostname, counter.Tags), counter.PerSecond, now)
+			_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName("stats_counts", key, "", counter.Source, counter.Tags), counter.Value, now)
+			_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.counterNamespace, key, "", counter.Source, counter.Tags), counter.PerSecond, now)
 		})
 	} else {
 		metrics.Counters.Each(func(key, tagsKey string, counter gostatsd.Counter) {
-			_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.counterNamespace, key, "count", counter.Hostname, counter.Tags), counter.Value, now)
-			_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.counterNamespace, key, "rate", counter.Hostname, counter.Tags), counter.PerSecond, now)
+			_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.counterNamespace, key, "count", counter.Source, counter.Tags), counter.Value, now)
+			_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.counterNamespace, key, "rate", counter.Source, counter.Tags), counter.PerSecond, now)
 		})
 	}
 	metrics.Timers.Each(func(key, tagsKey string, timer gostatsd.Timer) {
@@ -168,46 +168,46 @@ func (client *Client) preparePayload(metrics *gostatsd.MetricMap, ts time.Time)
 					bucketTag = "le:" + strconv.FormatFloat(float64(histogramThreshold), 'f', -1, 64)
 				}
 				newTags := timer.Tags.Concat(gostatsd.Tags{bucketTag})
-				_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.counterNamespace, key, "histogram", timer.Hostname, newTags), count, now)
+				_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.counterNamespace, key, "histogram", timer.Source, newTags), count, now)
 			}
 		} else {
 			if !client.disabledSubtypes.Lower {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "lower", timer.Hostname, timer.Tags), timer.Min, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "lower", timer.Source, timer.Tags), timer.Min, now)
 			}
 			if !client.disabledSubtypes.Upper {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "upper", timer.Hostname, timer.Tags), timer.Max, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "upper", timer.Source, timer.Tags), timer.Max, now)
 			}
 			if !client.disabledSubtypes.Count {
-				_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.timerNamespace, key, "count", timer.Hostname, timer.Tags), timer.Count, now)
+				_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.timerNamespace, key, "count", timer.Source, timer.Tags), timer.Count, now)
 			}
 			if !client.disabledSubtypes.CountPerSecond {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "count_ps", timer.Hostname, timer.Tags), timer.PerSecond, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "count_ps", timer.Source, timer.Tags), timer.PerSecond, now)
 			}
 			if !client.disabledSubtypes.Mean {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "mean", timer.Hostname, timer.Tags), timer.Mean, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "mean", timer.Source, timer.Tags), timer.Mean, now)
 			}
 			if !client.disabledSubtypes.Median {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "median", timer.Hostname, timer.Tags), timer.Median, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "median", timer.Source, timer.Tags), timer.Median, now)
 			}
 			if !client.disabledSubtypes.StdDev {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "std", timer.Hostname, timer.Tags), timer.StdDev, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "std", timer.Source, timer.Tags), timer.StdDev, now)
 			}
 			if !client.disabledSubtypes.Sum {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "sum", timer.Hostname, timer.Tags), timer.Sum, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "sum", timer.Source, timer.Tags), timer.Sum, now)
 			}
 			if !client.disabledSubtypes.SumSquares {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "sum_squares", timer.Hostname, timer.Tags), timer.SumSquares, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, "sum_squares", timer.Source, timer.Tags), timer.SumSquares, now)
 			}
 			for _, pct := range timer.Percentiles {
-				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, pct.Str, timer.Hostname, timer.Tags), pct.Float, now)
+				_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.timerNamespace, key, pct.Str, timer.Source, timer.Tags), pct.Float, now)
 			}
 		}
 	})
 	metrics.Gauges.Each(func(key, tagsKey string, gauge gostatsd.Gauge) {
-		_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.gaugesNamespace, key, "", gauge.Hostname, gauge.Tags), gauge.Value, now)
+		_, _ = fmt.Fprintf(buf, "%s %f %d\n", client.prepareName(client.gaugesNamespace, key, "", gauge.Source, gauge.Tags), gauge.Value, now)
 	})
 	metrics.Sets.Each(func(key, tagsKey string, set gostatsd.Set) {
-		_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.setsNamespace, key, "", set.Hostname, set.Tags), len(set.Values), now)
+		_, _ = fmt.Fprintf(buf, "%s %d %d\n", client.prepareName(client.setsNamespace, key, "", set.Source, set.Tags), len(set.Values), now)
 	})
 	return buf
 }
diff --git a/pkg/backends/influxdb/influxdb.go b/pkg/backends/influxdb/influxdb.go
index efb4989..43e112e 100644
--- a/pkg/backends/influxdb/influxdb.go
+++ b/pkg/backends/influxdb/influxdb.go
@@ -366,8 +366,8 @@ func writeEvent(w io.Writer, e *gostatsd.Event) {
 	if e.SourceTypeName != "" {
 		tags = append(tags, "sourcetypename:"+e.SourceTypeName)
 	}
-	if e.Hostname != "" && !hasHost {
-		tags = append(tags, "host:"+e.Hostname)
+	if e.Source != "" && !hasHost {
+		tags = append(tags, "host:"+string(e.Source))
 	}
 
 	writeName(w, "events", tags)
diff --git a/pkg/backends/newrelic/flush.go b/pkg/backends/newrelic/flush.go
index 5efbd8d..5f2d1c7 100644
--- a/pkg/backends/newrelic/flush.go
+++ b/pkg/backends/newrelic/flush.go
@@ -23,7 +23,7 @@ type timeSeries struct {
 }
 
 // addMetric adds a metric to the series.
-func (f *flush) addMetric(n *Client, metricType string, value float64, persecond float64, hostname string, tags gostatsd.Tags, name string) {
+func (f *flush) addMetric(n *Client, metricType string, value float64, persecond float64, tags gostatsd.Tags, name string) {
 	if n.flushType == flushTypeMetrics {
 		metricName := name
 		if metricType == "counter" {
diff --git a/pkg/backends/newrelic/newrelic.go b/pkg/backends/newrelic/newrelic.go
index adcd28c..fb17f9b 100644
--- a/pkg/backends/newrelic/newrelic.go
+++ b/pkg/backends/newrelic/newrelic.go
@@ -207,17 +207,17 @@ func (n *Client) processMetrics(now float64, metrics *gostatsd.MetricMap, cb fun
 	}
 
 	metrics.Gauges.Each(func(key, tagsKey string, g gostatsd.Gauge) {
-		fl.addMetric(n, "gauge", g.Value, 0, g.Hostname, g.Tags, key)
+		fl.addMetric(n, "gauge", g.Value, 0, g.Tags, key)
 		fl.maybeFlush()
 	})
 
 	metrics.Counters.Each(func(key, tagsKey string, counter gostatsd.Counter) {
-		fl.addMetric(n, "counter", float64(counter.Value), counter.PerSecond, counter.Hostname, counter.Tags, key)
+		fl.addMetric(n, "counter", float64(counter.Value), counter.PerSecond, counter.Tags, key)
 		fl.maybeFlush()
 	})
 
 	metrics.Sets.Each(func(key, tagsKey string, set gostatsd.Set) {
-		fl.addMetric(n, "set", float64(len(set.Values)), 0, set.Hostname, set.Tags, key)
+		fl.addMetric(n, "set", float64(len(set.Values)), 0, set.Tags, key)
 		fl.maybeFlush()
 	})
 
@@ -229,7 +229,7 @@ func (n *Client) processMetrics(now float64, metrics *gostatsd.MetricMap, cb fun
 					bucketTag = "le:" + strconv.FormatFloat(float64(histogramThreshold), 'f', -1, 64)
 				}
 				newTags := timer.Tags.Concat(gostatsd.Tags{bucketTag})
-				fl.addMetric(n, "counter", float64(count), 0, timer.Hostname, newTags, key+".histogram")
+				fl.addMetric(n, "counter", float64(count), 0, newTags, key+".histogram")
 			}
 		} else {
 			fl.addTimerMetric(n, "timer", timer, tagsKey, key)
@@ -267,7 +267,7 @@ func (n *Client) EventFormatter(e *gostatsd.Event) interface{} {
 		"Title":          e.Title,
 		"Text":           e.Text,
 		"DateHappened":   e.DateHappened,
-		"Hostname":       e.Hostname,
+		"Hostname":       e.Source,
 		"AggregationKey": e.AggregationKey,
 		"SourceTypeName": e.SourceTypeName,
 		"Priority":       e.Priority.StringWithEmptyDefault(),
diff --git a/pkg/backends/statsdaemon/statsdaemon.go b/pkg/backends/statsdaemon/statsdaemon.go
index 303dcff..8ec8e79 100644
--- a/pkg/backends/statsdaemon/statsdaemon.go
+++ b/pkg/backends/statsdaemon/statsdaemon.go
@@ -165,9 +165,9 @@ func constructEventMessage(e *gostatsd.Event) *bytes.Buffer {
 		buf.WriteString("|d:")
 		buf.WriteString(strconv.FormatInt(e.DateHappened, 10))
 	}
-	if e.Hostname != "" {
+	if e.Source != "" {
 		buf.WriteString("|h:")
-		buf.WriteString(e.Hostname)
+		buf.WriteString(string(e.Source))
 	}
 	if e.AggregationKey != "" {
 		buf.WriteString("|k:")
diff --git a/pkg/cachedinstances/cloudprovider/cached_cloud_provider.go b/pkg/cachedinstances/cloudprovider/cached_cloud_provider.go
index c6d539f..8324724 100644
--- a/pkg/cachedinstances/cloudprovider/cached_cloud_provider.go
+++ b/pkg/cachedinstances/cloudprovider/cached_cloud_provider.go
@@ -21,10 +21,10 @@ func NewCachedCloudProvider(logger logrus.FieldLogger, limiter *rate.Limiter, cl
 		limiter:        limiter,
 		cloudProvider:  cloudProvider,
 		cacheOpts:      cacheOpts,
-		ipSinkSource:   make(chan gostatsd.IP),
+		ipSinkSource:   make(chan gostatsd.Source),
 		infoSinkSource: make(chan gostatsd.InstanceInfo),
 		emitChan:       make(chan stats.Statser),
-		cache:          make(map[gostatsd.IP]*instanceHolder),
+		cache:          make(map[gostatsd.Source]*instanceHolder),
 	}
 }
 
@@ -39,22 +39,22 @@ type CachedCloudProvider struct {
 	limiter        *rate.Limiter
 	cloudProvider  gostatsd.CloudProvider
 	cacheOpts      gostatsd.CacheOptions
-	ipSinkSource   chan gostatsd.IP
+	ipSinkSource   chan gostatsd.Source
 	infoSinkSource chan gostatsd.InstanceInfo
 
 	// emitChan triggers a write of all the current stats when it is given a Statser
 	emitChan     chan stats.Statser
 	rw           sync.RWMutex // Protects cache
-	cache        map[gostatsd.IP]*instanceHolder
-	toLookupIPs  []gostatsd.IP
+	cache        map[gostatsd.Source]*instanceHolder
+	toLookupIPs  []gostatsd.Source
 	toReturnInfo []gostatsd.InstanceInfo
 }
 
 func (ccp *CachedCloudProvider) Run(ctx context.Context) {
 	clck := clock.FromContext(ctx)
 	var (
-		toLookupC     chan<- gostatsd.IP
-		toLookupIP    gostatsd.IP
+		toLookupC     chan<- gostatsd.Source
+		toLookupIP    gostatsd.Source
 		toReturnInfoC chan<- gostatsd.InstanceInfo
 		toReturnInfo  gostatsd.InstanceInfo
 		wg            wait.Group
@@ -89,8 +89,8 @@ func (ccp *CachedCloudProvider) Run(ctx context.Context) {
 		case <-ctx.Done():
 			return
 		case toLookupC <- toLookupIP:
-			toLookupIP = gostatsd.UnknownIP // enable GC
-			toLookupC = nil                 // ip has been sent; if there is nothing to send, the case is disabled
+			toLookupIP = gostatsd.UnknownSource // enable GC
+			toLookupC = nil                     // ip has been sent; if there is nothing to send, the case is disabled
 		case toReturnInfoC <- toReturnInfo:
 			toReturnInfo = gostatsd.InstanceInfo{} // enable GC
 			toReturnInfoC = nil                    // info has been sent; if there is nothing to send, the case is disabled
@@ -104,7 +104,7 @@ func (ccp *CachedCloudProvider) Run(ctx context.Context) {
 		if toLookupC == nil && len(ccp.toLookupIPs) > 0 {
 			last := len(ccp.toLookupIPs) - 1
 			toLookupIP = ccp.toLookupIPs[last]
-			ccp.toLookupIPs[last] = gostatsd.UnknownIP // enable GC
+			ccp.toLookupIPs[last] = gostatsd.UnknownSource // enable GC
 			ccp.toLookupIPs = ccp.toLookupIPs[:last]
 			toLookupC = ccp.ipSinkSource
 		}
@@ -118,7 +118,7 @@ func (ccp *CachedCloudProvider) Run(ctx context.Context) {
 	}
 }
 
-func (ccp *CachedCloudProvider) Peek(ip gostatsd.IP) (*gostatsd.Instance, bool /*is a cache hit*/) {
+func (ccp *CachedCloudProvider) Peek(ip gostatsd.Source) (*gostatsd.Instance, bool /*is a cache hit*/) {
 	ccp.rw.RLock()
 	holder, existsInCache := ccp.cache[ip]
 	ccp.rw.RUnlock()
@@ -129,7 +129,7 @@ func (ccp *CachedCloudProvider) Peek(ip gostatsd.IP) (*gostatsd.Instance, bool /
 	return holder.instance, true // can be nil, true
 }
 
-func (ccp *CachedCloudProvider) IpSink() chan<- gostatsd.IP {
+func (ccp *CachedCloudProvider) IpSink() chan<- gostatsd.Source {
 	return ccp.ipSinkSource
 }
 
@@ -179,7 +179,7 @@ func (ccp *CachedCloudProvider) emit(statser stats.Statser) {
 }
 
 func (ccp *CachedCloudProvider) doRefresh(t time.Time) {
-	var toDelete []gostatsd.IP
+	var toDelete []gostatsd.Source
 	now := t.UnixNano()
 	idleNano := ccp.cacheOpts.CacheEvictAfterIdlePeriod.Nanoseconds()
 
diff --git a/pkg/cachedinstances/cloudprovider/cached_cloud_provider_lookup.go b/pkg/cachedinstances/cloudprovider/cached_cloud_provider_lookup.go
index 44f0599..f14b547 100644
--- a/pkg/cachedinstances/cloudprovider/cached_cloud_provider_lookup.go
+++ b/pkg/cachedinstances/cloudprovider/cached_cloud_provider_lookup.go
@@ -18,13 +18,13 @@ type cloudProviderLookupDispatcher struct {
 	logger        logrus.FieldLogger
 	limiter       *rate.Limiter
 	cloudProvider gostatsd.CloudProvider
-	ipSource      <-chan gostatsd.IP
+	ipSource      <-chan gostatsd.Source
 	infoSink      chan<- gostatsd.InstanceInfo
 }
 
 func (ld *cloudProviderLookupDispatcher) run(ctx context.Context) {
 	maxLookupIPs := ld.cloudProvider.MaxInstancesBatch()
-	ips := make([]gostatsd.IP, 0, maxLookupIPs)
+	ips := make([]gostatsd.Source, 0, maxLookupIPs)
 	var c <-chan time.Time
 	for {
 		select {
@@ -53,13 +53,13 @@ func (ld *cloudProviderLookupDispatcher) run(ctx context.Context) {
 		}
 		ld.doLookup(ctx, ips)
 		for i := range ips { // cleanup pointers for GC
-			ips[i] = gostatsd.UnknownIP
+			ips[i] = gostatsd.UnknownSource
 		}
 		ips = ips[:0] // reset slice
 	}
 }
 
-func (ld *cloudProviderLookupDispatcher) doLookup(ctx context.Context, ips []gostatsd.IP) {
+func (ld *cloudProviderLookupDispatcher) doLookup(ctx context.Context, ips []gostatsd.Source) {
 	// instances may contain partial result even if err != nil
 	instances, err := ld.cloudProvider.Instance(ctx, ips...)
 	if err != nil {
diff --git a/pkg/cachedinstances/k8s/k8s.go b/pkg/cachedinstances/k8s/k8s.go
index 3e21700..b3c9bc9 100644
--- a/pkg/cachedinstances/k8s/k8s.go
+++ b/pkg/cachedinstances/k8s/k8s.go
@@ -109,14 +109,14 @@ type Provider struct {
 	annotationRegex *regexp.Regexp // can be nil to disable annotation matching
 	labelRegex      *regexp.Regexp // can be nil to disable label matching
 
-	ipSinkSource   chan gostatsd.IP
+	ipSinkSource   chan gostatsd.Source
 	infoSinkSource chan gostatsd.InstanceInfo
 
 	rw    sync.RWMutex // Protects cache
-	cache map[gostatsd.IP]*gostatsd.Instance
+	cache map[gostatsd.Source]*gostatsd.Instance
 }
 
-func (p *Provider) IpSink() chan<- gostatsd.IP {
+func (p *Provider) IpSink() chan<- gostatsd.Source {
 	return p.ipSinkSource
 }
 
@@ -129,7 +129,7 @@ func (p *Provider) EstimatedTags() int {
 	return 0
 }
 
-func (p *Provider) Peek(ip gostatsd.IP) (*gostatsd.Instance, bool /*is a cache hit*/) {
+func (p *Provider) Peek(ip gostatsd.Source) (*gostatsd.Instance, bool /*is a cache hit*/) {
 	// it's always a cache hit
 	return p.instanceFromCache(ip), true
 }
@@ -165,7 +165,7 @@ func (p *Provider) Run(ctx context.Context) {
 	}
 }
 
-func (p *Provider) instanceFromCache(ip gostatsd.IP) *gostatsd.Instance {
+func (p *Provider) instanceFromCache(ip gostatsd.Source) *gostatsd.Instance {
 	p.rw.RLock()
 	instance := p.cache[ip]
 	p.rw.RUnlock()
@@ -184,7 +184,7 @@ func (p *Provider) instanceFromCache(ip gostatsd.IP) *gostatsd.Instance {
 	return instance
 }
 
-func (p *Provider) instanceFromInformer(ip gostatsd.IP) *gostatsd.Instance {
+func (p *Provider) instanceFromInformer(ip gostatsd.Source) *gostatsd.Instance {
 	logger := p.logger.WithField("ip", ip)
 	// Instance not found in cache. Fetch it from informer's cache and post-process.
 	objs, err := p.podsInf.GetIndexer().ByIndex(PodsByIPIndexName, string(ip))
@@ -226,7 +226,7 @@ func (p *Provider) instanceFromInformer(ip gostatsd.IP) *gostatsd.Instance {
 		"tags":     tags,
 	}).Debug("Added tags")
 	return &gostatsd.Instance{
-		ID:   instanceID,
+		ID:   gostatsd.Source(instanceID),
 		Tags: tags,
 	}
 }
@@ -317,9 +317,9 @@ func NewProvider(logger logrus.FieldLogger, clientset kubernetes.Interface, podI
 		factory:         factory,
 		annotationRegex: annotationRegex,
 		labelRegex:      labelRegex,
-		ipSinkSource:    make(chan gostatsd.IP),
+		ipSinkSource:    make(chan gostatsd.Source),
 		infoSinkSource:  make(chan gostatsd.InstanceInfo),
-		cache:           make(map[gostatsd.IP]*gostatsd.Instance),
+		cache:           make(map[gostatsd.Source]*gostatsd.Instance),
 	}
 	podsInf.AddEventHandler(cacheInvalidationHandler{p: p})
 
@@ -463,6 +463,6 @@ func (e cacheInvalidationHandler) maybeInvalidateCacheForPod(pod *core_v1.Pod) {
 		return
 	}
 	e.p.rw.Lock()
-	delete(e.p.cache, gostatsd.IP(pod.Status.PodIP))
+	delete(e.p.cache, gostatsd.Source(pod.Status.PodIP))
 	e.p.rw.Unlock()
 }
diff --git a/pkg/cloudproviders/aws/aws.go b/pkg/cloudproviders/aws/aws.go
index dd65886..2f20ffd 100644
--- a/pkg/cloudproviders/aws/aws.go
+++ b/pkg/cloudproviders/aws/aws.go
@@ -72,8 +72,8 @@ func (p *Provider) RunMetrics(ctx context.Context, statser stats.Statser) {
 // Instance returns instances details from AWS.
 // ip -> nil pointer if instance was not found.
 // map is returned even in case of errors because it may contain partial data.
-func (p *Provider) Instance(ctx context.Context, IP ...gostatsd.IP) (map[gostatsd.IP]*gostatsd.Instance, error) {
-	instances := make(map[gostatsd.IP]*gostatsd.Instance, len(IP))
+func (p *Provider) Instance(ctx context.Context, IP ...gostatsd.Source) (map[gostatsd.Source]*gostatsd.Instance, error) {
+	instances := make(map[gostatsd.Source]*gostatsd.Instance, len(IP))
 	values := make([]*string, len(IP))
 	for i, ip := range IP {
 		instances[ip] = nil // initialize map. Used for lookups to see if info for IP was requested
@@ -99,7 +99,7 @@ func (p *Provider) Instance(ctx context.Context, IP ...gostatsd.IP) (map[gostats
 		for _, reservation := range page.Reservations {
 			for _, instance := range reservation.Instances {
 				ip := getInterestingInstanceIP(instance, instances)
-				if ip == gostatsd.UnknownIP {
+				if ip == gostatsd.UnknownSource {
 					p.logger.Warnf("AWS returned unexpected EC2 instance: %#v", instance)
 					continue
 				}
@@ -116,7 +116,7 @@ func (p *Provider) Instance(ctx context.Context, IP ...gostatsd.IP) (map[gostats
 				}
 				tags[len(tags)-1] = "region:" + region
 				instances[ip] = &gostatsd.Instance{
-					ID:   aws.StringValue(instance.InstanceId),
+					ID:   gostatsd.Source(aws.StringValue(instance.InstanceId)),
 					Tags: tags,
 				}
 				p.logger.WithFields(logrus.Fields{
@@ -151,9 +151,9 @@ func (p *Provider) Instance(ctx context.Context, IP ...gostatsd.IP) (map[gostats
 	return instances, nil
 }
 
-func getInterestingInstanceIP(instance *ec2.Instance, instances map[gostatsd.IP]*gostatsd.Instance) gostatsd.IP {
+func getInterestingInstanceIP(instance *ec2.Instance, instances map[gostatsd.Source]*gostatsd.Instance) gostatsd.Source {
 	// Check primary private IPv4 address
-	ip := gostatsd.IP(aws.StringValue(instance.PrivateIpAddress))
+	ip := gostatsd.Source(aws.StringValue(instance.PrivateIpAddress))
 	if _, ok := instances[ip]; ok {
 		return ip
 	}
@@ -161,20 +161,20 @@ func getInterestingInstanceIP(instance *ec2.Instance, instances map[gostatsd.IP]
 	for _, iface := range instance.NetworkInterfaces {
 		// Check private IPv4 addresses on interface
 		for _, privateIP := range iface.PrivateIpAddresses {
-			ip = gostatsd.IP(aws.StringValue(privateIP.PrivateIpAddress))
+			ip = gostatsd.Source(aws.StringValue(privateIP.PrivateIpAddress))
 			if _, ok := instances[ip]; ok {
 				return ip
 			}
 		}
 		// Check private IPv6 addresses on interface
 		for _, IPv6 := range iface.Ipv6Addresses {
-			ip = gostatsd.IP(aws.StringValue(IPv6.Ipv6Address))
+			ip = gostatsd.Source(aws.StringValue(IPv6.Ipv6Address))
 			if _, ok := instances[ip]; ok {
 				return ip
 			}
 		}
 	}
-	return gostatsd.UnknownIP
+	return gostatsd.UnknownSource
 }
 
 // MaxInstancesBatch returns maximum number of instances that could be requested via the Instance method.
@@ -187,12 +187,6 @@ func (p *Provider) Name() string {
 	return ProviderName
 }
 
-// SelfIP returns host's IPv4 address.
-func (p *Provider) SelfIP() (gostatsd.IP, error) {
-	ip, err := p.Metadata.GetMetadata("local-ipv4")
-	return gostatsd.IP(ip), err
-}
-
 // Derives the region from a valid az name.
 // Returns an error if the az is known invalid (empty).
 func azToRegion(az string) (string, error) {
diff --git a/pkg/cloudproviders/fakeprovider/fake.go b/pkg/cloudproviders/fakeprovider/fake.go
index fa2cda9..2bd1fbd 100644
--- a/pkg/cloudproviders/fakeprovider/fake.go
+++ b/pkg/cloudproviders/fakeprovider/fake.go
@@ -11,14 +11,14 @@ import (
 
 type Counting struct {
 	mu          sync.Mutex
-	ips         []gostatsd.IP
+	ips         []gostatsd.Source
 	invocations uint64
 }
 
-func (fp *Counting) IPs() []gostatsd.IP {
+func (fp *Counting) IPs() []gostatsd.Source {
 	fp.mu.Lock()
 	defer fp.mu.Unlock()
-	result := make([]gostatsd.IP, len(fp.ips))
+	result := make([]gostatsd.Source, len(fp.ips))
 	copy(result, fp.ips)
 	return result
 }
@@ -37,17 +37,13 @@ func (fp *Counting) Invocations() uint64 {
 	return fp.invocations
 }
 
-func (fp *Counting) count(ips ...gostatsd.IP) {
+func (fp *Counting) count(ips ...gostatsd.Source) {
 	fp.mu.Lock()
 	defer fp.mu.Unlock()
 	fp.ips = append(fp.ips, ips...)
 	fp.invocations++
 }
 
-func (fp *Counting) SelfIP() (gostatsd.IP, error) {
-	return gostatsd.UnknownIP, nil
-}
-
 type IP struct {
 	Counting
 	Region string
@@ -58,12 +54,12 @@ func (fp *IP) Name() string {
 	return "FakeProviderIP"
 }
 
-func (fp *IP) Instance(ctx context.Context, ips ...gostatsd.IP) (map[gostatsd.IP]*gostatsd.Instance, error) {
+func (fp *IP) Instance(ctx context.Context, ips ...gostatsd.Source) (map[gostatsd.Source]*gostatsd.Instance, error) {
 	fp.count(ips...)
-	instances := make(map[gostatsd.IP]*gostatsd.Instance, len(ips))
+	instances := make(map[gostatsd.Source]*gostatsd.Instance, len(ips))
 	for _, ip := range ips {
 		instances[ip] = &gostatsd.Instance{
-			ID:   "i-" + string(ip),
+			ID:   "i-" + ip,
 			Tags: fp.Tags,
 		}
 	}
@@ -78,7 +74,7 @@ func (fp *NotFound) Name() string {
 	return "FakeProviderNotFound"
 }
 
-func (fp *NotFound) Instance(ctx context.Context, ips ...gostatsd.IP) (map[gostatsd.IP]*gostatsd.Instance, error) {
+func (fp *NotFound) Instance(ctx context.Context, ips ...gostatsd.Source) (map[gostatsd.Source]*gostatsd.Instance, error) {
 	fp.count(ips...)
 	return nil, nil
 }
@@ -91,7 +87,7 @@ func (fp *Failing) Name() string {
 	return "FakeFailingProvider"
 }
 
-func (fp *Failing) Instance(ctx context.Context, ips ...gostatsd.IP) (map[gostatsd.IP]*gostatsd.Instance, error) {
+func (fp *Failing) Instance(ctx context.Context, ips ...gostatsd.Source) (map[gostatsd.Source]*gostatsd.Instance, error) {
 	fp.count(ips...)
 	return nil, errors.New("clear skies, no clouds available")
 }
@@ -113,17 +109,13 @@ func (fpt *Transient) MaxInstancesBatch() int {
 	return 1
 }
 
-func (fpt *Transient) SelfIP() (gostatsd.IP, error) {
-	return gostatsd.UnknownIP, nil
-}
-
 // Instance emulates a lookup based on the supplied criteria.
 // A failure mode of 0 is a successful lookup
 // A failure mode of 1 is nil instance, no error (lookup failure)
 // A failure mode of 2 is nil instance, with error
 // Repeats the last specified failure mode
-func (fpt *Transient) Instance(ctx context.Context, ips ...gostatsd.IP) (map[gostatsd.IP]*gostatsd.Instance, error) {
-	r := make(map[gostatsd.IP]*gostatsd.Instance)
+func (fpt *Transient) Instance(ctx context.Context, ips ...gostatsd.Source) (map[gostatsd.Source]*gostatsd.Instance, error) {
+	r := make(map[gostatsd.Source]*gostatsd.Instance)
 
 	c := atomic.AddUint64(&fpt.call, 1) - 1
 	if c >= uint64(len(fpt.FailureMode)) {
@@ -133,7 +125,7 @@ func (fpt *Transient) Instance(ctx context.Context, ips ...gostatsd.IP) (map[gos
 	case 0:
 		for _, ip := range ips {
 			r[ip] = &gostatsd.Instance{
-				ID:   string(ip),
+				ID:   ip,
 				Tags: gostatsd.Tags{"tag:value"},
 			}
 		}
diff --git a/pkg/stats/statser_internal.go b/pkg/stats/statser_internal.go
index 345cdd0..e23d61f 100644
--- a/pkg/stats/statser_internal.go
+++ b/pkg/stats/statser_internal.go
@@ -23,7 +23,7 @@ type InternalStatser struct {
 
 	tags      gostatsd.Tags
 	namespace string
-	hostname  string
+	hostname  gostatsd.Source
 	handler   gostatsd.PipelineHandler
 	dropped   uint64
 }
@@ -32,7 +32,10 @@ const bufferSize = 1000 // estimating this is difficult and tends to cause probl
 
 // NewInternalStatser creates a new Statser which sends metrics to the
 // supplied InternalHandler.
-func NewInternalStatser(tags gostatsd.Tags, namespace, hostname string, handler gostatsd.PipelineHandler) *InternalStatser {
+func NewInternalStatser(tags gostatsd.Tags, namespace string, hostname gostatsd.Source, handler gostatsd.PipelineHandler) *InternalStatser {
+	if hostname != gostatsd.UnknownSource {
+		tags = tags.Concat(gostatsd.Tags{"host:" + string(hostname)})
+	}
 	return &InternalStatser{
 		buffer:    make(chan *gostatsd.Metric, bufferSize),
 		tags:      tags,
@@ -63,12 +66,12 @@ func (is *InternalStatser) Run(ctx context.Context) {
 // Gauge sends a gauge metric
 func (is *InternalStatser) Gauge(name string, value float64, tags gostatsd.Tags) {
 	g := &gostatsd.Metric{
-		Name:     name,
-		Value:    value,
-		Tags:     tags,
-		Hostname: is.hostname,
-		Rate:     1,
-		Type:     gostatsd.GAUGE,
+		Name:   name,
+		Value:  value,
+		Tags:   tags,
+		Source: is.hostname,
+		Rate:   1,
+		Type:   gostatsd.GAUGE,
 	}
 	is.dispatchInternal(g)
 }
@@ -76,12 +79,12 @@ func (is *InternalStatser) Gauge(name string, value float64, tags gostatsd.Tags)
 // Count sends a counter metric
 func (is *InternalStatser) Count(name string, amount float64, tags gostatsd.Tags) {
 	c := &gostatsd.Metric{
-		Name:     name,
-		Value:    amount,
-		Tags:     tags,
-		Hostname: is.hostname,
-		Rate:     1,
-		Type:     gostatsd.COUNTER,
+		Name:   name,
+		Value:  amount,
+		Tags:   tags,
+		Source: is.hostname,
+		Rate:   1,
+		Type:   gostatsd.COUNTER,
 	}
 	is.dispatchInternal(c)
 }
@@ -94,12 +97,12 @@ func (is *InternalStatser) Increment(name string, tags gostatsd.Tags) {
 // TimingMS sends a timing metric from a millisecond value
 func (is *InternalStatser) TimingMS(name string, ms float64, tags gostatsd.Tags) {
 	c := &gostatsd.Metric{
-		Name:     name,
-		Value:    ms,
-		Tags:     tags,
-		Hostname: is.hostname,
-		Rate:     1,
-		Type:     gostatsd.TIMER,
+		Name:   name,
+		Value:  ms,
+		Tags:   tags,
+		Source: is.hostname,
+		Rate:   1,
+		Type:   gostatsd.TIMER,
 	}
 	is.dispatchInternal(c)
 }
diff --git a/pkg/statsd/aggregator.go b/pkg/statsd/aggregator.go
index b1be409..862cbad 100644
--- a/pkg/statsd/aggregator.go
+++ b/pkg/statsd/aggregator.go
@@ -225,7 +225,7 @@ func (a *MetricAggregator) Reset() {
 		} else {
 			a.metricMap.Counters[key][tagsKey] = gostatsd.Counter{
 				Timestamp: counter.Timestamp,
-				Hostname:  counter.Hostname,
+				Source:    counter.Source,
 				Tags:      counter.Tags,
 			}
 		}
@@ -238,7 +238,7 @@ func (a *MetricAggregator) Reset() {
 			if hasHistogramTag(timer) {
 				a.metricMap.Timers[key][tagsKey] = gostatsd.Timer{
 					Timestamp: timer.Timestamp,
-					Hostname:  timer.Hostname,
+					Source:    timer.Source,
 					Tags:      timer.Tags,
 					Values:    timer.Values[:0],
 					Histogram: emptyHistogram(timer, a.histogramLimit),
@@ -246,7 +246,7 @@ func (a *MetricAggregator) Reset() {
 			} else {
 				a.metricMap.Timers[key][tagsKey] = gostatsd.Timer{
 					Timestamp: timer.Timestamp,
-					Hostname:  timer.Hostname,
+					Source:    timer.Source,
 					Tags:      timer.Tags,
 					Values:    timer.Values[:0],
 				}
@@ -268,7 +268,7 @@ func (a *MetricAggregator) Reset() {
 			a.metricMap.Sets[key][tagsKey] = gostatsd.Set{
 				Values:    make(map[string]struct{}),
 				Timestamp: set.Timestamp,
-				Hostname:  set.Hostname,
+				Source:    set.Source,
 				Tags:      set.Tags,
 			}
 		}
diff --git a/pkg/statsd/handler_cloud.go b/pkg/statsd/handler_cloud.go
index 7f2f79d..0145cc6 100644
--- a/pkg/statsd/handler_cloud.go
+++ b/pkg/statsd/handler_cloud.go
@@ -30,9 +30,9 @@ type CloudHandler struct {
 
 	// emitChan triggers a write of all the current stats when it is given a Statser
 	emitChan        chan stats.Statser
-	awaitingEvents  map[gostatsd.IP][]*gostatsd.Event
-	awaitingMetrics map[gostatsd.IP][]*gostatsd.Metric
-	toLookupIPs     []gostatsd.IP
+	awaitingEvents  map[gostatsd.Source][]*gostatsd.Event
+	awaitingMetrics map[gostatsd.Source][]*gostatsd.Metric
+	toLookupIPs     []gostatsd.Source
 	wg              sync.WaitGroup
 
 	estimatedTags int
@@ -46,8 +46,8 @@ func NewCloudHandler(cachedInstances gostatsd.CachedInstances, handler gostatsd.
 		incomingMetrics: make(chan []*gostatsd.Metric),
 		incomingEvents:  make(chan *gostatsd.Event),
 		emitChan:        make(chan stats.Statser),
-		awaitingEvents:  make(map[gostatsd.IP][]*gostatsd.Event),
-		awaitingMetrics: make(map[gostatsd.IP][]*gostatsd.Metric),
+		awaitingEvents:  make(map[gostatsd.Source][]*gostatsd.Event),
+		awaitingMetrics: make(map[gostatsd.Source][]*gostatsd.Metric),
 		estimatedTags:   handler.EstimatedTags() + cachedInstances.EstimatedTags(),
 	}
 }
@@ -61,7 +61,7 @@ func (ch *CloudHandler) DispatchMetrics(ctx context.Context, metrics []*gostatsd
 	var toDispatch []*gostatsd.Metric
 	var toHandle []*gostatsd.Metric
 	for _, m := range metrics {
-		if ch.updateTagsAndHostname(m.SourceIP, &m.Tags, &m.Hostname) {
+		if ch.updateTagsAndHostname(&m.Tags, &m.Source) {
 			toDispatch = append(toDispatch, m)
 		} else {
 			toHandle = append(toHandle, m)
@@ -89,7 +89,7 @@ func (ch *CloudHandler) DispatchMetricMap(ctx context.Context, mm *gostatsd.Metr
 }
 
 func (ch *CloudHandler) DispatchEvent(ctx context.Context, e *gostatsd.Event) {
-	if ch.updateTagsAndHostname(e.SourceIP, &e.Tags, &e.Hostname) {
+	if ch.updateTagsAndHostname(&e.Tags, &e.Source) {
 		ch.handler.DispatchEvent(ctx, e)
 		return
 	}
@@ -158,8 +158,8 @@ func (ch *CloudHandler) emit(statser stats.Statser) {
 
 func (ch *CloudHandler) Run(ctx context.Context) {
 	var (
-		toLookupC  chan<- gostatsd.IP
-		toLookupIP gostatsd.IP
+		toLookupC  chan<- gostatsd.Source
+		toLookupIP gostatsd.Source
 	)
 	infoSource := ch.cachedInstances.InfoSource()
 	ipSink := ch.cachedInstances.IpSink()
@@ -168,8 +168,8 @@ func (ch *CloudHandler) Run(ctx context.Context) {
 		case <-ctx.Done():
 			return
 		case toLookupC <- toLookupIP:
-			toLookupIP = gostatsd.UnknownIP // Enable GC
-			toLookupC = nil                 // ip has been sent; if there is nothing to send, will block
+			toLookupIP = gostatsd.UnknownSource // Enable GC
+			toLookupC = nil                     // ip has been sent; if there is nothing to send, will block
 		case info := <-infoSource:
 			ch.handleInstanceInfo(ctx, info)
 		case metrics := <-ch.incomingMetrics:
@@ -184,7 +184,7 @@ func (ch *CloudHandler) Run(ctx context.Context) {
 		if toLookupC == nil && len(ch.toLookupIPs) > 0 {
 			last := len(ch.toLookupIPs) - 1
 			toLookupIP = ch.toLookupIPs[last]
-			ch.toLookupIPs[last] = gostatsd.UnknownIP // Enable GC
+			ch.toLookupIPs[last] = gostatsd.UnknownSource // Enable GC
 			ch.toLookupIPs = ch.toLookupIPs[:last]
 			toLookupC = ipSink
 		}
@@ -210,11 +210,11 @@ func (ch *CloudHandler) handleInstanceInfo(ctx context.Context, info gostatsd.In
 
 func (ch *CloudHandler) handleIncomingMetrics(metrics []*gostatsd.Metric) {
 	for _, m := range metrics {
-		queue := ch.awaitingMetrics[m.SourceIP]
-		ch.awaitingMetrics[m.SourceIP] = append(queue, m)
-		if len(queue) == 0 && len(ch.awaitingEvents[m.SourceIP]) == 0 {
+		queue := ch.awaitingMetrics[m.Source]
+		ch.awaitingMetrics[m.Source] = append(queue, m)
+		if len(queue) == 0 && len(ch.awaitingEvents[m.Source]) == 0 {
 			// This is the first metric for that IP in the queue. Need to fetch an Instance for this IP.
-			ch.toLookupIPs = append(ch.toLookupIPs, m.SourceIP)
+			ch.toLookupIPs = append(ch.toLookupIPs, m.Source)
 			ch.statsMetricHostsQueued++
 		}
 	}
@@ -222,11 +222,11 @@ func (ch *CloudHandler) handleIncomingMetrics(metrics []*gostatsd.Metric) {
 }
 
 func (ch *CloudHandler) handleIncomingEvent(e *gostatsd.Event) {
-	queue := ch.awaitingEvents[e.SourceIP]
-	ch.awaitingEvents[e.SourceIP] = append(queue, e)
-	if len(queue) == 0 && len(ch.awaitingMetrics[e.SourceIP]) == 0 {
+	queue := ch.awaitingEvents[e.Source]
+	ch.awaitingEvents[e.Source] = append(queue, e)
+	if len(queue) == 0 && len(ch.awaitingMetrics[e.Source]) == 0 {
 		// This is the first event for that IP in the queue. Need to fetch an Instance for this IP.
-		ch.toLookupIPs = append(ch.toLookupIPs, e.SourceIP)
+		ch.toLookupIPs = append(ch.toLookupIPs, e.Source)
 		ch.statsEventHostsQueued++
 	}
 	ch.statsEventItemsQueued++
@@ -234,7 +234,7 @@ func (ch *CloudHandler) handleIncomingEvent(e *gostatsd.Event) {
 
 func (ch *CloudHandler) updateAndDispatchMetrics(ctx context.Context, instance *gostatsd.Instance, metrics []*gostatsd.Metric) {
 	for _, m := range metrics {
-		updateInplace(&m.Tags, &m.Hostname, instance)
+		updateInplace(&m.Tags, &m.Source, instance)
 	}
 	ch.handler.DispatchMetrics(ctx, metrics)
 }
@@ -245,22 +245,22 @@ func (ch *CloudHandler) updateAndDispatchEvents(ctx context.Context, instance *g
 		ch.wg.Add(-dispatched)
 	}()
 	for _, e := range events {
-		updateInplace(&e.Tags, &e.Hostname, instance)
+		updateInplace(&e.Tags, &e.Source, instance)
 		dispatched++
 		ch.handler.DispatchEvent(ctx, e)
 	}
 }
 
-func (ch *CloudHandler) updateTagsAndHostname(ip gostatsd.IP, tags *gostatsd.Tags, hostname *string) bool /*is a cache hit*/ {
-	instance, cacheHit := ch.getInstance(ip)
+func (ch *CloudHandler) updateTagsAndHostname(tags *gostatsd.Tags, source *gostatsd.Source) bool /*is a cache hit*/ {
+	instance, cacheHit := ch.getInstance(*source)
 	if cacheHit {
-		updateInplace(tags, hostname, instance)
+		updateInplace(tags, source, instance)
 	}
 	return cacheHit
 }
 
-func (ch *CloudHandler) getInstance(ip gostatsd.IP) (*gostatsd.Instance, bool /*is a cache hit*/) {
-	if ip == gostatsd.UnknownIP {
+func (ch *CloudHandler) getInstance(ip gostatsd.Source) (*gostatsd.Instance, bool /*is a cache hit*/) {
+	if ip == gostatsd.UnknownSource {
 		return nil, true
 	}
 	instance, cacheHit := ch.cachedInstances.Peek(ip)
@@ -272,10 +272,10 @@ func (ch *CloudHandler) getInstance(ip gostatsd.IP) (*gostatsd.Instance, bool /*
 	return instance, true
 }
 
-func updateInplace(tags *gostatsd.Tags, hostname *string, instance *gostatsd.Instance) {
+func updateInplace(tags *gostatsd.Tags, source *gostatsd.Source, instance *gostatsd.Instance) {
 	if instance != nil { // It was a positive cache hit (successful lookup cache, not failed lookup cache)
 		// Update hostname inplace
-		*hostname = instance.ID
+		*source = instance.ID
 		// Update tag list inplace
 		*tags = append(*tags, instance.Tags...)
 	}
diff --git a/pkg/statsd/handler_http_forwarder_v2.go b/pkg/statsd/handler_http_forwarder_v2.go
index aed497b..6a9419f 100644
--- a/pkg/statsd/handler_http_forwarder_v2.go
+++ b/pkg/statsd/handler_http_forwarder_v2.go
@@ -275,7 +275,7 @@ func translateToProtobufV2(metricMap *gostatsd.MetricMap) *pb.RawMessageV2 {
 		for tagsKey, metric := range m {
 			pbMetricMap.Gauges[metricName].TagMap[tagsKey] = &pb.RawGaugeV2{
 				Tags:     metric.Tags,
-				Hostname: metric.Hostname,
+				Hostname: string(metric.Source),
 				Value:    metric.Value,
 			}
 		}
@@ -287,7 +287,7 @@ func translateToProtobufV2(metricMap *gostatsd.MetricMap) *pb.RawMessageV2 {
 		for tagsKey, metric := range m {
 			pbMetricMap.Counters[metricName].TagMap[tagsKey] = &pb.RawCounterV2{
 				Tags:     metric.Tags,
-				Hostname: metric.Hostname,
+				Hostname: string(metric.Source),
 				Value:    metric.Value,
 			}
 		}
@@ -303,7 +303,7 @@ func translateToProtobufV2(metricMap *gostatsd.MetricMap) *pb.RawMessageV2 {
 			}
 			pbMetricMap.Sets[metricName].TagMap[tagsKey] = &pb.RawSetV2{
 				Tags:     metric.Tags,
-				Hostname: metric.Hostname,
+				Hostname: string(metric.Source),
 				Values:   values,
 			}
 		}
@@ -315,7 +315,7 @@ func translateToProtobufV2(metricMap *gostatsd.MetricMap) *pb.RawMessageV2 {
 		for tagsKey, metric := range m {
 			pbMetricMap.Timers[metricName].TagMap[tagsKey] = &pb.RawTimerV2{
 				Tags:        metric.Tags,
-				Hostname:    metric.Hostname,
+				Hostname:    string(metric.Source),
 				SampleCount: metric.SampledCount,
 				Values:      metric.Values,
 			}
@@ -486,11 +486,11 @@ func (hfh *HttpForwarderHandlerV2) dispatchEvent(ctx context.Context, e *gostats
 		Title:          e.Title,
 		Text:           e.Text,
 		DateHappened:   e.DateHappened,
-		Hostname:       e.Hostname,
+		Hostname:       string(e.Source),
 		AggregationKey: e.AggregationKey,
 		SourceTypeName: e.SourceTypeName,
 		Tags:           e.Tags,
-		SourceIP:       string(e.SourceIP),
+		SourceIP:       string(e.Source),
 	}
 
 	switch e.Priority {
diff --git a/pkg/statsd/handler_tags.go b/pkg/statsd/handler_tags.go
index 73ca4bd..18f7db5 100644
--- a/pkg/statsd/handler_tags.go
+++ b/pkg/statsd/handler_tags.go
@@ -55,9 +55,6 @@ func (th *TagHandler) DispatchMetrics(ctx context.Context, metrics []*gostatsd.M
 	var toDispatch []*gostatsd.Metric
 
 	for _, m := range metrics {
-		if m.Hostname == "" {
-			m.Hostname = string(m.SourceIP)
-		}
 		if th.uniqueFilterMetricAndAddTags(m) {
 			toDispatch = append(toDispatch, m)
 		}
@@ -76,8 +73,8 @@ func (th *TagHandler) DispatchMetricMap(ctx context.Context, mm *gostatsd.Metric
 	mmNew := gostatsd.NewMetricMap()
 
 	mm.Counters.Each(func(metricName, _ string, cOriginal gostatsd.Counter) {
-		if th.uniqueFilterAndAddTags(metricName, &cOriginal.Hostname, &cOriginal.Tags) {
-			newTagsKey := gostatsd.FormatTagsKey(cOriginal.Hostname, cOriginal.Tags)
+		if th.uniqueFilterAndAddTags(metricName, &cOriginal.Source, &cOriginal.Tags) {
+			newTagsKey := gostatsd.FormatTagsKey(cOriginal.Source, cOriginal.Tags)
 			if cs, ok := mmNew.Counters[metricName]; ok {
 				if cNew, ok := cs[newTagsKey]; ok {
 					cNew.Value += cOriginal.Value
@@ -93,8 +90,8 @@ func (th *TagHandler) DispatchMetricMap(ctx context.Context, mm *gostatsd.Metric
 	})
 
 	mm.Gauges.Each(func(metricName, _ string, gOriginal gostatsd.Gauge) {
-		if th.uniqueFilterAndAddTags(metricName, &gOriginal.Hostname, &gOriginal.Tags) {
-			newTagsKey := gostatsd.FormatTagsKey(gOriginal.Hostname, gOriginal.Tags)
+		if th.uniqueFilterAndAddTags(metricName, &gOriginal.Source, &gOriginal.Tags) {
+			newTagsKey := gostatsd.FormatTagsKey(gOriginal.Source, gOriginal.Tags)
 			if gs, ok := mmNew.Gauges[metricName]; ok {
 				if gNew, ok := gs[newTagsKey]; ok {
 					if gOriginal.Timestamp > gNew.Timestamp {
@@ -112,8 +109,8 @@ func (th *TagHandler) DispatchMetricMap(ctx context.Context, mm *gostatsd.Metric
 	})
 
 	mm.Timers.Each(func(metricName, _ string, tOriginal gostatsd.Timer) {
-		if th.uniqueFilterAndAddTags(metricName, &tOriginal.Hostname, &tOriginal.Tags) {
-			newTagsKey := gostatsd.FormatTagsKey(tOriginal.Hostname, tOriginal.Tags)
+		if th.uniqueFilterAndAddTags(metricName, &tOriginal.Source, &tOriginal.Tags) {
+			newTagsKey := gostatsd.FormatTagsKey(tOriginal.Source, tOriginal.Tags)
 			if ts, ok := mmNew.Timers[metricName]; ok {
 				if tNew, ok := ts[newTagsKey]; ok {
 					tNew.Values = append(tNew.Values, tOriginal.Values...)
@@ -130,8 +127,8 @@ func (th *TagHandler) DispatchMetricMap(ctx context.Context, mm *gostatsd.Metric
 	})
 
 	mm.Sets.Each(func(metricName, _ string, sOriginal gostatsd.Set) {
-		if th.uniqueFilterAndAddTags(metricName, &sOriginal.Hostname, &sOriginal.Tags) {
-			newTagsKey := gostatsd.FormatTagsKey(sOriginal.Hostname, sOriginal.Tags)
+		if th.uniqueFilterAndAddTags(metricName, &sOriginal.Source, &sOriginal.Tags) {
+			newTagsKey := gostatsd.FormatTagsKey(sOriginal.Source, sOriginal.Tags)
 			if ss, ok := mmNew.Sets[metricName]; ok {
 				if sNew, ok := ss[newTagsKey]; ok {
 					for key := range sOriginal.Values {
@@ -162,7 +159,7 @@ func (th *TagHandler) DispatchMetricMap(ctx context.Context, mm *gostatsd.Metric
 // hot code path.
 //
 // Returns true if the metric should be processed further, or false to drop it.
-func (th *TagHandler) uniqueFilterAndAddTags(mName string, mHostname *string, mTags *gostatsd.Tags) bool {
+func (th *TagHandler) uniqueFilterAndAddTags(mName string, mHostname *gostatsd.Source, mTags *gostatsd.Tags) bool {
 	if len(th.filters) == 0 {
 		*mTags = uniqueTags(*mTags, th.tags)
 		return true
@@ -209,14 +206,11 @@ func (th *TagHandler) uniqueFilterAndAddTags(mName string, mHostname *string, mT
 }
 
 func (th *TagHandler) uniqueFilterMetricAndAddTags(m *gostatsd.Metric) bool {
-	return th.uniqueFilterAndAddTags(m.Name, &m.Hostname, &m.Tags)
+	return th.uniqueFilterAndAddTags(m.Name, &m.Source, &m.Tags)
 }
 
 // DispatchEvent adds the unique tags from the TagHandler to the event and passes it to the next stage in the pipeline
 func (th *TagHandler) DispatchEvent(ctx context.Context, e *gostatsd.Event) {
-	if e.Hostname == "" {
-		e.Hostname = string(e.SourceIP)
-	}
 	e.Tags = uniqueTags(e.Tags, th.tags)
 	th.handler.DispatchEvent(ctx, e)
 }
diff --git a/pkg/statsd/lexer.go b/pkg/statsd/lexer.go
index 6a7218e..270b6ee 100644
--- a/pkg/statsd/lexer.go
+++ b/pkg/statsd/lexer.go
@@ -199,7 +199,7 @@ func lexEventAttribute(l *lexer) stateFn {
 		}))
 	case 'h':
 		return lexAssert(':', lexUntil('|', func(l *lexer, data []byte) stateFn {
-			l.e.Hostname = string(data)
+			l.e.Source = gostatsd.Source(data)
 			return lexEventAttributes
 		}))
 	case 'k':
diff --git a/pkg/statsd/parser.go b/pkg/statsd/parser.go
index 7fff7c0..01e248d 100644
--- a/pkg/statsd/parser.go
+++ b/pkg/statsd/parser.go
@@ -123,7 +123,7 @@ func (dp *DatagramParser) Run(ctx context.Context) {
 }
 
 // logBadLineRateLimited will log a line which failed to decode, if the current rate limit has not been exceeded.
-func (dp *DatagramParser) logBadLineRateLimited(line []byte, ip gostatsd.IP, err error) {
+func (dp *DatagramParser) logBadLineRateLimited(line []byte, ip gostatsd.Source, err error) {
 	if dp.badLineLimiter.Allow() {
 		logrus.WithFields(logrus.Fields{
 			"line":  string(line),
@@ -135,7 +135,7 @@ func (dp *DatagramParser) logBadLineRateLimited(line []byte, ip gostatsd.IP, err
 
 // handleDatagram handles the contents of a datagram and parsers it in to Metrics (which are returned), or
 // Events (which are sent to the pipeline via DispatchEvent).
-func (dp *DatagramParser) handleDatagram(ctx context.Context, now gostatsd.Nanotime, ip gostatsd.IP, msg []byte) (metrics []*gostatsd.Metric, eventCount uint64, badLineCount uint64) {
+func (dp *DatagramParser) handleDatagram(ctx context.Context, now gostatsd.Nanotime, ip gostatsd.Source, msg []byte) (metrics []*gostatsd.Metric, eventCount uint64, badLineCount uint64) {
 	var numEvents, numBad uint64
 	for {
 		idx := bytes.IndexByte(msg, '\n')
@@ -163,7 +163,7 @@ func (dp *DatagramParser) handleDatagram(ctx context.Context, now gostatsd.Nanot
 			if dp.ignoreHost {
 				for idx, tag := range metric.Tags {
 					if strings.HasPrefix(tag, "host:") {
-						metric.Hostname = tag[5:]
+						metric.Source = gostatsd.Source(tag[5:])
 						if len(metric.Tags) > 1 {
 							metric.Tags = append(metric.Tags[:idx], metric.Tags[idx+1:]...)
 						} else {
@@ -173,13 +173,13 @@ func (dp *DatagramParser) handleDatagram(ctx context.Context, now gostatsd.Nanot
 					}
 				}
 			} else {
-				metric.SourceIP = ip
+				metric.Source = ip
 			}
 			metric.Timestamp = now
 			metrics = append(metrics, metric)
 		} else if event != nil {
 			numEvents++
-			event.SourceIP = ip // Always keep the source ip for events
+			event.Source = ip // Always keep the source ip for events
 			if event.DateHappened == 0 {
 				event.DateHappened = time.Now().Unix()
 			}
diff --git a/pkg/statsd/receiver.go b/pkg/statsd/receiver.go
index b6a0e8c..ac206da 100644
--- a/pkg/statsd/receiver.go
+++ b/pkg/statsd/receiver.go
@@ -160,10 +160,10 @@ func (dr *DatagramReceiver) Receive(ctx context.Context, c net.PacketConn) {
 	}
 }
 
-func getIP(addr net.Addr) gostatsd.IP {
+func getIP(addr net.Addr) gostatsd.Source {
 	if a, ok := addr.(*net.UDPAddr); ok {
-		return gostatsd.IP(a.IP.String())
+		return gostatsd.Source(a.IP.String())
 	}
 	logrus.Errorf("Cannot get source address %q of type %T", addr, addr)
-	return gostatsd.UnknownIP
+	return gostatsd.UnknownSource
 }
diff --git a/pkg/statsd/statsd.go b/pkg/statsd/statsd.go
index af7d550..d3c7453 100644
--- a/pkg/statsd/statsd.go
+++ b/pkg/statsd/statsd.go
@@ -55,8 +55,7 @@ type Server struct {
 	HistogramLimit            uint32
 	BadLineRateLimitPerSecond rate.Limit
 	ServerMode                string
-	Hostname                  string
-	SelfIP                    gostatsd.IP
+	Hostname                  gostatsd.Source
 	LogRawMetric              bool
 	Viper                     *viper.Viper
 	TransportPool             *transport.TransportPool
@@ -205,15 +204,15 @@ func (s *Server) RunWithCustomSocket(ctx context.Context, sf SocketFactory) erro
 
 	// Send events on start and on stop
 	// TODO: Push these in to statser
-	defer sendStopEvent(handler, s.SelfIP, hostname)
-	sendStartEvent(runCtx, handler, s.SelfIP, hostname)
+	defer sendStopEvent(handler, hostname)
+	sendStartEvent(runCtx, handler, hostname)
 
 	// Listen until done
 	<-ctx.Done()
 	return ctx.Err()
 }
 
-func (s *Server) createStatser(hostname string, handler gostatsd.PipelineHandler, logger logrus.FieldLogger) stats.Statser {
+func (s *Server) createStatser(hostname gostatsd.Source, handler gostatsd.PipelineHandler, logger logrus.FieldLogger) stats.Statser {
 	switch s.StatserType {
 	case gostatsd.StatserNull:
 		return stats.NewNullStatser()
@@ -232,26 +231,24 @@ func (s *Server) createStatser(hostname string, handler gostatsd.PipelineHandler
 	}
 }
 
-func sendStartEvent(ctx context.Context, handler gostatsd.PipelineHandler, selfIP gostatsd.IP, hostname string) {
+func sendStartEvent(ctx context.Context, handler gostatsd.PipelineHandler, hostname gostatsd.Source) {
 	handler.DispatchEvent(ctx, &gostatsd.Event{
 		Title:        "Gostatsd started",
 		Text:         "Gostatsd started",
 		DateHappened: time.Now().Unix(),
-		Hostname:     hostname,
-		SourceIP:     selfIP,
+		Source:       hostname,
 		Priority:     gostatsd.PriLow,
 	})
 }
 
-func sendStopEvent(handler gostatsd.PipelineHandler, selfIP gostatsd.IP, hostname string) {
+func sendStopEvent(handler gostatsd.PipelineHandler, hostname gostatsd.Source) {
 	ctx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second)
 	defer cancelFunc()
 	handler.DispatchEvent(ctx, &gostatsd.Event{
 		Title:        "Gostatsd stopped",
 		Text:         "Gostatsd stopped",
 		DateHappened: time.Now().Unix(),
-		Hostname:     hostname,
-		SourceIP:     selfIP,
+		Source:       hostname,
 		Priority:     gostatsd.PriLow,
 	})
 	handler.WaitForEvents()
diff --git a/pkg/statsd/types.go b/pkg/statsd/types.go
index b23c888..33534e5 100644
--- a/pkg/statsd/types.go
+++ b/pkg/statsd/types.go
@@ -34,7 +34,7 @@ type Aggregator interface {
 
 // Datagram is a received UDP datagram that has not been parsed into Metric/Event(s)
 type Datagram struct {
-	IP        gostatsd.IP
+	IP        gostatsd.Source
 	Msg       []byte
 	Timestamp gostatsd.Nanotime
 	DoneFunc  func() // to be called once the datagram has been parsed and msg can be freed
diff --git a/pkg/web/http_receiver_v2.go b/pkg/web/http_receiver_v2.go
index c3a5da8..0e7dd4c 100644
--- a/pkg/web/http_receiver_v2.go
+++ b/pkg/web/http_receiver_v2.go
@@ -148,11 +148,10 @@ func (rhh *rawHttpHandlerV2) EventHandler(w http.ResponseWriter, req *http.Reque
 		Title:          msg.Title,
 		Text:           msg.Text,
 		DateHappened:   msg.DateHappened,
-		Hostname:       msg.Hostname,
+		Source:         gostatsd.Source(msg.Hostname),
 		AggregationKey: msg.AggregationKey,
 		SourceTypeName: msg.SourceTypeName,
 		Tags:           msg.Tags,
-		SourceIP:       gostatsd.IP(msg.SourceIP),
 	}
 
 	switch msg.Priority {
@@ -194,7 +193,7 @@ func translateFromProtobufV2(pbMetricMap *pb.RawMessageV2) *gostatsd.MetricMap {
 			mm.Gauges[metricName][tagsKey] = gostatsd.Gauge{
 				Value:     gauge.Value,
 				Timestamp: now,
-				Hostname:  gauge.Hostname,
+				Source:    gostatsd.Source(gauge.Hostname),
 				Tags:      gauge.Tags,
 			}
 		}
@@ -207,7 +206,7 @@ func translateFromProtobufV2(pbMetricMap *pb.RawMessageV2) *gostatsd.MetricMap {
 				Value:     counter.Value,
 				Timestamp: now,
 				Tags:      counter.Tags,
-				Hostname:  counter.Hostname,
+				Source:    gostatsd.Source(counter.Hostname),
 			}
 		}
 	}
@@ -219,7 +218,7 @@ func translateFromProtobufV2(pbMetricMap *pb.RawMessageV2) *gostatsd.MetricMap {
 				Values:       timer.Values,
 				Timestamp:    now,
 				Tags:         timer.Tags,
-				Hostname:     timer.Hostname,
+				Source:       gostatsd.Source(timer.Hostname),
 				SampledCount: timer.SampleCount,
 			}
 		}
@@ -232,7 +231,7 @@ func translateFromProtobufV2(pbMetricMap *pb.RawMessageV2) *gostatsd.MetricMap {
 				Values:    map[string]struct{}{},
 				Timestamp: now,
 				Tags:      set.Tags,
-				Hostname:  set.Hostname,
+				Source:    gostatsd.Source(set.Hostname),
 			}
 			for _, value := range set.Values {
 				mm.Sets[metricName][tagsKey].Values[value] = struct{}{}
diff --git a/sets.go b/sets.go
index 6236fb6..b186840 100644
--- a/sets.go
+++ b/sets.go
@@ -4,13 +4,13 @@ package gostatsd
 type Set struct {
 	Values    map[string]struct{}
 	Timestamp Nanotime // Last time value was updated
-	Hostname  string   // Hostname of the source of the metric
+	Source    Source   // Hostname of the source of the metric
 	Tags      Tags     // The tags for the set
 }
 
 // NewSet initialises a new set.
-func NewSet(timestamp Nanotime, values map[string]struct{}, hostname string, tags Tags) Set {
-	return Set{Values: values, Timestamp: timestamp, Hostname: hostname, Tags: tags.Copy()}
+func NewSet(timestamp Nanotime, values map[string]struct{}, source Source, tags Tags) Set {
+	return Set{Values: values, Timestamp: timestamp, Source: source, Tags: tags.Copy()}
 }
 
 // Sets stores a map of sets by tags.
diff --git a/timers.go b/timers.go
index b164a92..fd78231 100644
--- a/timers.go
+++ b/timers.go
@@ -17,7 +17,7 @@ type Timer struct {
 	Values       []float64   // The numeric value of the metric
 	Percentiles  Percentiles // The percentile aggregations of the metric
 	Timestamp    Nanotime    // Last time value was updated
-	Hostname     string      // Hostname of the source of the metric
+	Source       Source      // Hostname of the source of the metric
 	Tags         Tags        // The tags for the timer
 
 	// Map bounds to count of measures seen in that bucket.
@@ -28,8 +28,8 @@ type Timer struct {
 type HistogramThreshold float64
 
 // NewTimer initialises a new timer.
-func NewTimer(timestamp Nanotime, values []float64, hostname string, tags Tags) Timer {
-	return Timer{Values: values, Timestamp: timestamp, Hostname: hostname, Tags: tags.Copy(), SampledCount: float64(len(values))}
+func NewTimer(timestamp Nanotime, values []float64, source Source, tags Tags) Timer {
+	return Timer{Values: values, Timestamp: timestamp, Source: source, Tags: tags.Copy(), SampledCount: float64(len(values))}
 }
 
 // NewTimerValues initialises a new timer only from Values array
diff --git a/types.go b/types.go
index 29a2ac2..445365e 100644
--- a/types.go
+++ b/types.go
@@ -20,12 +20,12 @@ func NanoMax(t1, t2 Nanotime) Nanotime {
 	return t2
 }
 
-// IP is a v4/v6 IP address.
+// Source is a v4/v6 IP address.
 // We do not use net.IP because it will involve conversion to string and back several times.
-type IP string
+type Source string
 
-// UnknownIP is an IP of an unknown source.
-const UnknownIP IP = ""
+// UnknownSource is an IP of an unknown source.
+const UnknownSource Source = ""
 
 type Wait func()
 


Test patch:
diff --git a/metric_consolidator_test.go b/metric_consolidator_test.go
index 12954e8..cd76d2b 100644
--- a/metric_consolidator_test.go
+++ b/metric_consolidator_test.go
@@ -48,7 +48,7 @@ func TestConsolidation(t *testing.T) {
 			PerSecond: 0,
 			Value:     1,
 			Timestamp: 10,
-			Hostname:  "",
+			Source:    "",
 			Tags:      nil,
 		},
 	}
@@ -57,7 +57,7 @@ func TestConsolidation(t *testing.T) {
 			PerSecond: 0,
 			Value:     30,
 			Timestamp: 20,
-			Hostname:  "",
+			Source:    "",
 			Tags:      nil,
 		},
 	}
diff --git a/metric_map_test.go b/metric_map_test.go
index 36c6e6d..e5c14aa 100644
--- a/metric_map_test.go
+++ b/metric_map_test.go
@@ -270,32 +270,32 @@ func TestMetricMapMerge(t *testing.T) {
 func TestMetricMapSplit(t *testing.T) {
 	mmOriginal := NewMetricMap()
 	mmOriginal.Counters["m"] = map[string]Counter{
-		"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Value: 10},
-		"t.s.h2": {Tags: Tags{"t"}, Hostname: "h2", Value: 20},
-		"t.s.h3": {Tags: Tags{"t"}, Hostname: "h3", Value: 30},
-		"t.s.h4": {Tags: Tags{"t"}, Hostname: "h4", Value: 40},
-		"t.s.h5": {Tags: Tags{"t"}, Hostname: "h5", Value: 50},
+		"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Value: 10},
+		"t.s.h2": {Tags: Tags{"t"}, Source: "h2", Value: 20},
+		"t.s.h3": {Tags: Tags{"t"}, Source: "h3", Value: 30},
+		"t.s.h4": {Tags: Tags{"t"}, Source: "h4", Value: 40},
+		"t.s.h5": {Tags: Tags{"t"}, Source: "h5", Value: 50},
 	}
 	mmOriginal.Gauges["m"] = map[string]Gauge{
-		"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Value: 10},
-		"t.s.h2": {Tags: Tags{"t"}, Hostname: "h2", Value: 20},
-		"t.s.h3": {Tags: Tags{"t"}, Hostname: "h3", Value: 30},
-		"t.s.h4": {Tags: Tags{"t"}, Hostname: "h4", Value: 40},
-		"t.s.h5": {Tags: Tags{"t"}, Hostname: "h5", Value: 50},
+		"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Value: 10},
+		"t.s.h2": {Tags: Tags{"t"}, Source: "h2", Value: 20},
+		"t.s.h3": {Tags: Tags{"t"}, Source: "h3", Value: 30},
+		"t.s.h4": {Tags: Tags{"t"}, Source: "h4", Value: 40},
+		"t.s.h5": {Tags: Tags{"t"}, Source: "h5", Value: 50},
 	}
 	mmOriginal.Timers["m"] = map[string]Timer{
-		"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Values: []float64{10, 50}},
-		"t.s.h2": {Tags: Tags{"t"}, Hostname: "h2", Values: []float64{20, 40}},
-		"t.s.h3": {Tags: Tags{"t"}, Hostname: "h3", Values: []float64{30, 30}},
-		"t.s.h4": {Tags: Tags{"t"}, Hostname: "h4", Values: []float64{40, 20}},
-		"t.s.h5": {Tags: Tags{"t"}, Hostname: "h5", Values: []float64{50, 10}},
+		"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Values: []float64{10, 50}},
+		"t.s.h2": {Tags: Tags{"t"}, Source: "h2", Values: []float64{20, 40}},
+		"t.s.h3": {Tags: Tags{"t"}, Source: "h3", Values: []float64{30, 30}},
+		"t.s.h4": {Tags: Tags{"t"}, Source: "h4", Values: []float64{40, 20}},
+		"t.s.h5": {Tags: Tags{"t"}, Source: "h5", Values: []float64{50, 10}},
 	}
 	mmOriginal.Sets["m"] = map[string]Set{
-		"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Values: map[string]struct{}{"10": {}, "50": {}}},
-		"t.s.h2": {Tags: Tags{"t"}, Hostname: "h2", Values: map[string]struct{}{"20": {}, "40": {}}},
-		"t.s.h3": {Tags: Tags{"t"}, Hostname: "h3", Values: map[string]struct{}{"30": {}, "3.0": {}}},
-		"t.s.h4": {Tags: Tags{"t"}, Hostname: "h4", Values: map[string]struct{}{"40": {}, "20": {}}},
-		"t.s.h5": {Tags: Tags{"t"}, Hostname: "h5", Values: map[string]struct{}{"50": {}, "10": {}}},
+		"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Values: map[string]struct{}{"10": {}, "50": {}}},
+		"t.s.h2": {Tags: Tags{"t"}, Source: "h2", Values: map[string]struct{}{"20": {}, "40": {}}},
+		"t.s.h3": {Tags: Tags{"t"}, Source: "h3", Values: map[string]struct{}{"30": {}, "3.0": {}}},
+		"t.s.h4": {Tags: Tags{"t"}, Source: "h4", Values: map[string]struct{}{"40": {}, "20": {}}},
+		"t.s.h5": {Tags: Tags{"t"}, Source: "h5", Values: map[string]struct{}{"50": {}, "10": {}}},
 	}
 
 	mmMerged := NewMetricMap()
@@ -317,25 +317,25 @@ func TestMetricMapIsEmpty(t *testing.T) {
 	require.True(t, mm.IsEmpty())
 
 	// Counter
-	mm.Counters["m"] = map[string]Counter{"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Value: 10}}
+	mm.Counters["m"] = map[string]Counter{"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Value: 10}}
 	require.False(t, mm.IsEmpty())
 	mm.Counters.Delete("m")
 	require.True(t, mm.IsEmpty())
 
 	// Gauge
-	mm.Gauges["m"] = map[string]Gauge{"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Value: 10}}
+	mm.Gauges["m"] = map[string]Gauge{"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Value: 10}}
 	require.False(t, mm.IsEmpty())
 	mm.Gauges.Delete("m")
 	require.True(t, mm.IsEmpty())
 
 	// Timer
-	mm.Timers["m"] = map[string]Timer{"t.s.h1": {Tags: Tags{"t"}, Hostname: "h1", Values: []float64{10}}}
+	mm.Timers["m"] = map[string]Timer{"t.s.h1": {Tags: Tags{"t"}, Source: "h1", Values: []float64{10}}}
 	require.False(t, mm.IsEmpty())
 	mm.Timers.Delete("m")
 	require.True(t, mm.IsEmpty())
 
 	// Set
-	mm.Sets["m"] = map[string]Set{"t.s.h1": {Tags: Tags{"t"}, Hostname: "h5", Values: map[string]struct{}{"10": {}}}}
+	mm.Sets["m"] = map[string]Set{"t.s.h1": {Tags: Tags{"t"}, Source: "h5", Values: map[string]struct{}{"10": {}}}}
 	require.False(t, mm.IsEmpty())
 	mm.Sets.Delete("m")
 	require.True(t, mm.IsEmpty())
@@ -352,32 +352,32 @@ func TestTagsMatch(t *testing.T) {
 func TestMetricMapSplitByTags(t *testing.T) {
 	mmOriginal := NewMetricMap()
 	mmOriginal.Counters["m"] = map[string]Counter{
-		"t:x,s:h1":     {Tags: Tags{"t:x"}, Hostname: "h1", Value: 10},
-		"t:x,s:h2":     {Tags: Tags{"t:x"}, Hostname: "h2", Value: 20},
-		"t:x,v:1,s:h3": {Tags: Tags{"t:x", "v:1"}, Hostname: "h3", Value: 30},
-		"t:y,v:2,s:h4": {Tags: Tags{"t:y", "v:2"}, Hostname: "h4", Value: 40},
-		"t:y,x,s:h5":   {Tags: Tags{"t:y", "x"}, Hostname: "h5", Value: 50},
+		"t:x,s:h1":     {Tags: Tags{"t:x"}, Source: "h1", Value: 10},
+		"t:x,s:h2":     {Tags: Tags{"t:x"}, Source: "h2", Value: 20},
+		"t:x,v:1,s:h3": {Tags: Tags{"t:x", "v:1"}, Source: "h3", Value: 30},
+		"t:y,v:2,s:h4": {Tags: Tags{"t:y", "v:2"}, Source: "h4", Value: 40},
+		"t:y,x,s:h5":   {Tags: Tags{"t:y", "x"}, Source: "h5", Value: 50},
 	}
 	mmOriginal.Gauges["m"] = map[string]Gauge{
-		"t:x,s:h1":     {Tags: Tags{"t:x"}, Hostname: "h1", Value: 10},
-		"t:x,s:h2":     {Tags: Tags{"t:x"}, Hostname: "h2", Value: 20},
-		"t:x,v:1,s:h3": {Tags: Tags{"t:x", "v:1"}, Hostname: "h3", Value: 30},
-		"t:y,v:2,s:h4": {Tags: Tags{"t:y", "v:2"}, Hostname: "h4", Value: 40},
-		"t:y,x,s:h5":   {Tags: Tags{"t:y", "x"}, Hostname: "h5", Value: 50},
+		"t:x,s:h1":     {Tags: Tags{"t:x"}, Source: "h1", Value: 10},
+		"t:x,s:h2":     {Tags: Tags{"t:x"}, Source: "h2", Value: 20},
+		"t:x,v:1,s:h3": {Tags: Tags{"t:x", "v:1"}, Source: "h3", Value: 30},
+		"t:y,v:2,s:h4": {Tags: Tags{"t:y", "v:2"}, Source: "h4", Value: 40},
+		"t:y,x,s:h5":   {Tags: Tags{"t:y", "x"}, Source: "h5", Value: 50},
 	}
 	mmOriginal.Timers["m"] = map[string]Timer{
-		"t:x,s:h1":     {Values: []float64{10, 50}, Tags: Tags{"t:x"}, Hostname: "h1"},
-		"t:x,s:h2":     {Values: []float64{20, 40}, Tags: Tags{"t:x"}, Hostname: "h2"},
-		"t:x,v:1,s:h3": {Values: []float64{30, 30}, Tags: Tags{"t:x", "v:1"}, Hostname: "h3"},
-		"t:y,v:2,s:h4": {Values: []float64{40, 20}, Tags: Tags{"t:y", "v:2"}, Hostname: "h4"},
-		"t:y,x,s:h5":   {Values: []float64{50, 10}, Tags: Tags{"t:y", "x"}, Hostname: "h5"},
+		"t:x,s:h1":     {Values: []float64{10, 50}, Tags: Tags{"t:x"}, Source: "h1"},
+		"t:x,s:h2":     {Values: []float64{20, 40}, Tags: Tags{"t:x"}, Source: "h2"},
+		"t:x,v:1,s:h3": {Values: []float64{30, 30}, Tags: Tags{"t:x", "v:1"}, Source: "h3"},
+		"t:y,v:2,s:h4": {Values: []float64{40, 20}, Tags: Tags{"t:y", "v:2"}, Source: "h4"},
+		"t:y,x,s:h5":   {Values: []float64{50, 10}, Tags: Tags{"t:y", "x"}, Source: "h5"},
 	}
 	mmOriginal.Sets["m"] = map[string]Set{
-		"t:x,s:h1":     {Values: map[string]struct{}{"10": {}, "50": {}}, Tags: Tags{"t:x"}, Hostname: "h1"},
-		"t:x,s:h2":     {Values: map[string]struct{}{"20": {}, "40": {}}, Tags: Tags{"t:x"}, Hostname: "h2"},
-		"t:x,v:1,s:h3": {Values: map[string]struct{}{"30": {}, "3.0": {}}, Tags: Tags{"t:x", "v:1"}, Hostname: "h3"},
-		"t:y,v:2,s:h4": {Values: map[string]struct{}{"40": {}, "20": {}}, Tags: Tags{"t:y", "v:2"}, Hostname: "h4"},
-		"t:y,x,s:h5":   {Values: map[string]struct{}{"50": {}, "10": {}}, Tags: Tags{"t:y", "x"}, Hostname: "h5"},
+		"t:x,s:h1":     {Values: map[string]struct{}{"10": {}, "50": {}}, Tags: Tags{"t:x"}, Source: "h1"},
+		"t:x,s:h2":     {Values: map[string]struct{}{"20": {}, "40": {}}, Tags: Tags{"t:x"}, Source: "h2"},
+		"t:x,v:1,s:h3": {Values: map[string]struct{}{"30": {}, "3.0": {}}, Tags: Tags{"t:x", "v:1"}, Source: "h3"},
+		"t:y,v:2,s:h4": {Values: map[string]struct{}{"40": {}, "20": {}}, Tags: Tags{"t:y", "v:2"}, Source: "h4"},
+		"t:y,x,s:h5":   {Values: map[string]struct{}{"50": {}, "10": {}}, Tags: Tags{"t:y", "x"}, Source: "h5"},
 	}
 
 	// no-op if given empty tagNames
diff --git a/pkg/backends/cloudwatch/cloudwatch_test.go b/pkg/backends/cloudwatch/cloudwatch_test.go
index cef7f46..37b4037 100644
--- a/pkg/backends/cloudwatch/cloudwatch_test.go
+++ b/pkg/backends/cloudwatch/cloudwatch_test.go
@@ -97,7 +97,7 @@ func TestSendMetricDimensions(t *testing.T) {
 					PerSecond: 1.1,
 					Value:     5,
 					Timestamp: gostatsd.Nanotime(100),
-					Hostname:  "h1",
+					Source:    "h1",
 					Tags:      gostatsd.Tags{"tag1", "tag2:value2"},
 				},
 			},
@@ -142,7 +142,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 	return &gostatsd.MetricMap{
 		Counters: gostatsd.Counters{
 			"c1": map[string]gostatsd.Counter{
-				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: gostatsd.Nanotime(100), Hostname: "h1", Tags: gostatsd.Tags{"tag1"}},
+				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: gostatsd.Nanotime(100), Source: "h1", Tags: gostatsd.Tags{"tag1"}},
 			},
 		},
 		Timers: gostatsd.Timers{
@@ -162,14 +162,14 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						gostatsd.Percentile{Float: 0.1, Str: "count_90"},
 					},
 					Timestamp: gostatsd.Nanotime(200),
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2"},
 				},
 			},
 		},
 		Gauges: gostatsd.Gauges{
 			"g1": map[string]gostatsd.Gauge{
-				"tag3": {Value: 3, Timestamp: gostatsd.Nanotime(300), Hostname: "h3", Tags: gostatsd.Tags{"tag3"}},
+				"tag3": {Value: 3, Timestamp: gostatsd.Nanotime(300), Source: "h3", Tags: gostatsd.Tags{"tag3"}},
 			},
 		},
 		Sets: gostatsd.Sets{
@@ -181,7 +181,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						"john": {},
 					},
 					Timestamp: gostatsd.Nanotime(400),
-					Hostname:  "h4",
+					Source:    "h4",
 					Tags:      gostatsd.Tags{"tag4"},
 				},
 			},
@@ -202,7 +202,7 @@ func TestSendHistogram(t *testing.T) {
 				"tag2": {
 					Values:    []float64{0, 1},
 					Timestamp: gostatsd.Nanotime(200),
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2", "gsd_histogram:20_30_40_50_60"},
 					Histogram: map[gostatsd.HistogramThreshold]int{
 						20:                                       5,
diff --git a/pkg/backends/datadog/datadog_test.go b/pkg/backends/datadog/datadog_test.go
index 13eae10..8eb47ae 100644
--- a/pkg/backends/datadog/datadog_test.go
+++ b/pkg/backends/datadog/datadog_test.go
@@ -181,7 +181,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 	return &gostatsd.MetricMap{
 		Counters: gostatsd.Counters{
 			"c1": map[string]gostatsd.Counter{
-				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: gostatsd.Nanotime(100), Hostname: "h1", Tags: gostatsd.Tags{"tag1"}},
+				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: gostatsd.Nanotime(100), Source: "h1", Tags: gostatsd.Tags{"tag1"}},
 			},
 		},
 		Timers: gostatsd.Timers{
@@ -201,14 +201,14 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						gostatsd.Percentile{Float: 0.1, Str: "count_90"},
 					},
 					Timestamp: gostatsd.Nanotime(200),
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2"},
 				},
 			},
 		},
 		Gauges: gostatsd.Gauges{
 			"g1": map[string]gostatsd.Gauge{
-				"tag3": {Value: 3, Timestamp: gostatsd.Nanotime(300), Hostname: "h3", Tags: gostatsd.Tags{"tag3"}},
+				"tag3": {Value: 3, Timestamp: gostatsd.Nanotime(300), Source: "h3", Tags: gostatsd.Tags{"tag3"}},
 			},
 		},
 		Sets: gostatsd.Sets{
@@ -220,7 +220,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						"john": {},
 					},
 					Timestamp: gostatsd.Nanotime(400),
-					Hostname:  "h4",
+					Source:    "h4",
 					Tags:      gostatsd.Tags{"tag4"},
 				},
 			},
@@ -285,7 +285,7 @@ func metricsWithHistogram() *gostatsd.MetricMap {
 				"tag2": {
 					Values:    []float64{0, 1},
 					Timestamp: gostatsd.Nanotime(200),
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2", "gsd_histogram:20_30_40_50_60"},
 					Histogram: map[gostatsd.HistogramThreshold]int{
 						20:                                       5,
diff --git a/pkg/backends/influxdb/influxdb_test.go b/pkg/backends/influxdb/influxdb_test.go
index 6841b54..d1ffbad 100644
--- a/pkg/backends/influxdb/influxdb_test.go
+++ b/pkg/backends/influxdb/influxdb_test.go
@@ -266,7 +266,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 	return &gostatsd.MetricMap{
 		Counters: gostatsd.Counters{
 			"c1": map[string]gostatsd.Counter{
-				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: gostatsd.Nanotime(100), Hostname: "h1", Tags: gostatsd.Tags{"tag1"}},
+				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: gostatsd.Nanotime(100), Source: "h1", Tags: gostatsd.Tags{"tag1"}},
 			},
 		},
 		Timers: gostatsd.Timers{
@@ -286,14 +286,14 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						gostatsd.Percentile{Float: 0.1, Str: "count_90"},
 					},
 					Timestamp: gostatsd.Nanotime(200),
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2"},
 				},
 			},
 		},
 		Gauges: gostatsd.Gauges{
 			"g1": map[string]gostatsd.Gauge{
-				"tag3": {Value: 3, Timestamp: gostatsd.Nanotime(300), Hostname: "h3", Tags: gostatsd.Tags{"tag3"}},
+				"tag3": {Value: 3, Timestamp: gostatsd.Nanotime(300), Source: "h3", Tags: gostatsd.Tags{"tag3"}},
 			},
 		},
 		Sets: gostatsd.Sets{
@@ -305,7 +305,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						"john": {},
 					},
 					Timestamp: gostatsd.Nanotime(400),
-					Hostname:  "h4",
+					Source:    "h4",
 					Tags:      gostatsd.Tags{"tag4"},
 				},
 			},
@@ -392,7 +392,7 @@ func metricsWithHistogram() *gostatsd.MetricMap {
 				"tag2": {
 					Values:    []float64{0, 1},
 					Timestamp: gostatsd.Nanotime(200),
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2", "gsd_histogram:20_30_40_50_60"},
 					Histogram: map[gostatsd.HistogramThreshold]int{
 						20:                                       5,
@@ -413,9 +413,9 @@ func TestSendEvent(t *testing.T) {
 	mux := http.NewServeMux()
 
 	expectedEvents := []string{
-		"events,alerttype=info,host=test-host,priority=normal,sourcetypename=test-sourcename title=\"test-title\",text=\"test-text\" 100\n",
+		"events,alerttype=info,host=test-source,priority=normal,sourcetypename=test-sourcename title=\"test-title\",text=\"test-text\" 100\n",
 		"events,alerttype=info,host=tag-host,priority=normal,sourcetypename=test-sourcename title=\"test-title\",text=\"test-text\" 100\n",
-		"events,alerttype=info,host=test-host,priority=normal,sourcetypename=test-sourcename title=\"test-title\",text=\"test-text\",tags=\"abc,def\" 100\n",
+		"events,alerttype=info,host=test-source,priority=normal,sourcetypename=test-sourcename title=\"test-title\",text=\"test-text\",tags=\"abc,def\" 100\n",
 	}
 
 	mux.HandleFunc("/write", func(w http.ResponseWriter, r *http.Request) {
@@ -477,11 +477,10 @@ func TestSendEvent(t *testing.T) {
 		Title:          "test-title",
 		Text:           "test-text",
 		DateHappened:   time.Unix(100, 0).Unix(),
-		Hostname:       "test-host",
 		AggregationKey: "test-ak",
 		SourceTypeName: "test-sourcename",
 		Tags:           nil,
-		SourceIP:       "test-sourceip",
+		Source:         "test-source",
 		Priority:       0,
 		AlertType:      0,
 	})
@@ -491,13 +490,12 @@ func TestSendEvent(t *testing.T) {
 		Title:          "test-title",
 		Text:           "test-text",
 		DateHappened:   time.Unix(100, 0).Unix(),
-		Hostname:       "test-host",
 		AggregationKey: "test-ak",
 		SourceTypeName: "test-sourcename",
 		Tags: gostatsd.Tags{
 			"host:tag-host",
 		},
-		SourceIP:  "test-sourceip",
+		Source:    "test-source",
 		Priority:  0,
 		AlertType: 0,
 	})
@@ -507,14 +505,13 @@ func TestSendEvent(t *testing.T) {
 		Title:          "test-title",
 		Text:           "test-text",
 		DateHappened:   time.Unix(100, 0).Unix(),
-		Hostname:       "test-host",
 		AggregationKey: "test-ak",
 		SourceTypeName: "test-sourcename",
 		Tags: gostatsd.Tags{
 			"eventtags:abc",
 			"eventtags:def",
 		},
-		SourceIP:  "test-sourceip",
+		Source:    "test-source",
 		Priority:  0,
 		AlertType: 0,
 	})
diff --git a/pkg/backends/newrelic/newrelic_test.go b/pkg/backends/newrelic/newrelic_test.go
index 03cb9c7..33d7848 100644
--- a/pkg/backends/newrelic/newrelic_test.go
+++ b/pkg/backends/newrelic/newrelic_test.go
@@ -295,7 +295,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 	return &gostatsd.MetricMap{
 		Counters: gostatsd.Counters{
 			"c1": map[string]gostatsd.Counter{
-				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: 0, Hostname: "h1", Tags: gostatsd.Tags{"tag1"}},
+				"tag1": {PerSecond: 1.1, Value: 5, Timestamp: 0, Source: "h1", Tags: gostatsd.Tags{"tag1"}},
 			},
 		},
 		Timers: gostatsd.Timers{
@@ -315,14 +315,14 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						gostatsd.Percentile{Float: 0.1, Str: "count_90"},
 					},
 					Timestamp: 0,
-					Hostname:  "h2",
+					Source:    "h2",
 					Tags:      gostatsd.Tags{"tag2"},
 				},
 			},
 		},
 		Gauges: gostatsd.Gauges{
 			"g1": map[string]gostatsd.Gauge{
-				"tag3": {Value: 3, Timestamp: 0, Hostname: "h3", Tags: gostatsd.Tags{"tag3"}},
+				"tag3": {Value: 3, Timestamp: 0, Source: "h3", Tags: gostatsd.Tags{"tag3"}},
 			},
 		},
 		Sets: gostatsd.Sets{
@@ -334,7 +334,7 @@ func metricsOneOfEach() *gostatsd.MetricMap {
 						"john": {},
 					},
 					Timestamp: 0,
-					Hostname:  "h4",
+					Source:    "h4",
 					Tags:      gostatsd.Tags{"tag4"},
 				},
 			},
@@ -393,7 +393,7 @@ func TestEventFormatter(t *testing.T) {
 				defaultMetricsPerBatch, defaultMaxRequests, 2*time.Second, 1*time.Second, gostatsd.TimerSubtypes{}, logrus.New(), p)
 			require.NoError(t, err)
 
-			gostatsdEvent := gostatsd.Event{Title: "EventTitle", Text: "hi", Hostname: "blah", Priority: 1}
+			gostatsdEvent := gostatsd.Event{Title: "EventTitle", Text: "hi", Source: "blah", Priority: 1}
 			formattedEvent := client.EventFormatter(&gostatsdEvent)
 			fevent, err := json.Marshal(formattedEvent)
 			require.NoError(t, err)
diff --git a/pkg/cachedinstances/cloudprovider/cached_cloud_provider_test.go b/pkg/cachedinstances/cloudprovider/cached_cloud_provider_test.go
index 3bfbba7..522b11f 100644
--- a/pkg/cachedinstances/cloudprovider/cached_cloud_provider_test.go
+++ b/pkg/cachedinstances/cloudprovider/cached_cloud_provider_test.go
@@ -49,7 +49,7 @@ func TestCachedCloudProviderExpirationAndRefresh(t *testing.T) {
 	ctx, cancelFunc := context.WithCancel(context.Background())
 	defer cancelFunc()
 	wg.StartWithContext(ctx, ci.Run)
-	const peekIp gostatsd.IP = "1.2.3.4"
+	const peekIp gostatsd.Source = "1.2.3.4"
 	instance, exists := ci.Peek(peekIp)
 	require.Nil(t, instance)
 	require.False(t, exists)
diff --git a/pkg/cachedinstances/k8s/k8s_test.go b/pkg/cachedinstances/k8s/k8s_test.go
index f015da5..2c26464 100644
--- a/pkg/cachedinstances/k8s/k8s_test.go
+++ b/pkg/cachedinstances/k8s/k8s_test.go
@@ -222,7 +222,7 @@ func TestIPToTags(t *testing.T) {
 				instance, cacheHit := fixtures.provider.Peek(ipAddr)
 				require.True(ttt, cacheHit)
 				require.NotNil(ttt, instance)
-				assert.Equal(ttt, instance.ID, fmt.Sprintf("%s/%s", namespace, podName1))
+				assert.Equal(ttt, instance.ID, gostatsd.Source(fmt.Sprintf("%s/%s", namespace, podName1)))
 				assert.Len(ttt, instance.Tags, testCase.expectedNumTags)
 				for _, expectedTag := range testCase.expectedTagsContains {
 					assert.Contains(ttt, instance.Tags, fmt.Sprintf("%s:%s", expectedTag.expectedKey, expectedTag.value))
@@ -308,7 +308,7 @@ func TestCacheInvalidation1(t *testing.T) {
 			fixtures.provider.rw.RLock()
 			defer fixtures.provider.rw.RUnlock()
 			require.Len(t, fixtures.provider.cache, 1)
-			require.Contains(t, fixtures.provider.cache, gostatsd.IP(ipAddr))
+			require.Contains(t, fixtures.provider.cache, gostatsd.Source(ipAddr))
 		}()
 		fixtures.podsWatch.Delete(p1)
 		fixtures.waitForCacheSize(t, 0)
diff --git a/pkg/statsd/aggregator_test.go b/pkg/statsd/aggregator_test.go
index 359a867..87c07ca 100644
--- a/pkg/statsd/aggregator_test.go
+++ b/pkg/statsd/aggregator_test.go
@@ -226,7 +226,7 @@ func TestReset(t *testing.T) {
 	now := time.Now()
 	nowNano := gostatsd.Nanotime(now.UnixNano())
 	nowFn := func() time.Time { return now }
-	host := "hostname"
+	host := gostatsd.Source("hostname")
 
 	// non expired
 	actual := newFakeAggregator()
@@ -512,11 +512,11 @@ func BenchmarkHotMetric(b *testing.B) {
 		stage.Start(func() {
 			for n := 0; n < b.N; n++ {
 				m := &gostatsd.Metric{
-					Name:     "metric.name",
-					Value:    5,
-					Tags:     gostatsd.Tags{"aaaa:aaaa", "aaab:aaab", "aaac:aaac", "aaad:aaad", "aaae:aaae", "aaaf:aaaf"},
-					Hostname: "local",
-					Type:     gostatsd.GAUGE,
+					Name:   "metric.name",
+					Value:  5,
+					Tags:   gostatsd.Tags{"aaaa:aaaa", "aaab:aaab", "aaac:aaac", "aaad:aaad", "aaae:aaae", "aaaf:aaaf"},
+					Source: "local",
+					Type:   gostatsd.GAUGE,
 				}
 				beh.DispatchMetrics(ctx, []*gostatsd.Metric{m})
 			}
diff --git a/pkg/statsd/handler_cloud_test.go b/pkg/statsd/handler_cloud_test.go
index a133359..758e8f5 100644
--- a/pkg/statsd/handler_cloud_test.go
+++ b/pkg/statsd/handler_cloud_test.go
@@ -108,9 +108,9 @@ func TestTransientInstanceFailure(t *testing.T) {
 	}
 
 	expectedMetrics[0].Tags = gostatsd.Tags{"a1", "tag:value"}
-	expectedMetrics[0].Hostname = "1.2.3.4"
+	expectedMetrics[0].Source = "1.2.3.4"
 	expectedMetrics[1].Tags = gostatsd.Tags{"a1", "tag:value"}
-	expectedMetrics[1].Hostname = "1.2.3.4"
+	expectedMetrics[1].Source = "1.2.3.4"
 
 	assert.Equal(t, expectedMetrics, expecting.Metrics())
 }
@@ -121,39 +121,35 @@ func TestCloudHandlerDispatch(t *testing.T) {
 		Tags: gostatsd.Tags{"region:us-west-3", "tag1", "tag2:234"},
 	}
 
-	expectedIps := []gostatsd.IP{"1.2.3.4", "4.3.2.1"}
+	expectedIps := []gostatsd.Source{"1.2.3.4", "4.3.2.1"}
 	expectedMetrics := []gostatsd.Metric{
 		{
-			Name:     "t1",
-			Value:    42.42,
-			Tags:     gostatsd.Tags{"a1", "region:us-west-3", "tag1", "tag2:234"},
-			Hostname: "i-1.2.3.4",
-			SourceIP: "1.2.3.4",
-			Type:     gostatsd.COUNTER,
+			Name:   "t1",
+			Value:  42.42,
+			Tags:   gostatsd.Tags{"a1", "region:us-west-3", "tag1", "tag2:234"},
+			Source: "i-1.2.3.4",
+			Type:   gostatsd.COUNTER,
 		},
 		{
-			Name:     "t1",
-			Value:    45.45,
-			Tags:     gostatsd.Tags{"a4", "region:us-west-3", "tag1", "tag2:234"},
-			Hostname: "i-1.2.3.4",
-			SourceIP: "1.2.3.4",
-			Type:     gostatsd.COUNTER,
+			Name:   "t1",
+			Value:  45.45,
+			Tags:   gostatsd.Tags{"a4", "region:us-west-3", "tag1", "tag2:234"},
+			Source: "i-1.2.3.4",
+			Type:   gostatsd.COUNTER,
 		},
 	}
 	expectedEvents := gostatsd.Events{
 		gostatsd.Event{
-			Title:    "t12",
-			Text:     "asrasdfasdr",
-			Tags:     gostatsd.Tags{"a2", "region:us-west-3", "tag1", "tag2:234"},
-			Hostname: "i-4.3.2.1",
-			SourceIP: "4.3.2.1",
+			Title:  "t12",
+			Text:   "asrasdfasdr",
+			Tags:   gostatsd.Tags{"a2", "region:us-west-3", "tag1", "tag2:234"},
+			Source: "i-4.3.2.1",
 		},
 		gostatsd.Event{
-			Title:    "t1asdas",
-			Text:     "asdr",
-			Tags:     gostatsd.Tags{"a2-35", "region:us-west-3", "tag1", "tag2:234"},
-			Hostname: "i-4.3.2.1",
-			SourceIP: "4.3.2.1",
+			Title:  "t1asdas",
+			Text:   "asdr",
+			Tags:   gostatsd.Tags{"a2-35", "region:us-west-3", "tag1", "tag2:234"},
+			Source: "i-4.3.2.1",
 		},
 	}
 	doCheck(t, fp, sm1(), se1(), sm2(), se2(), fp.IPs, expectedIps, expectedMetrics, expectedEvents)
@@ -162,7 +158,7 @@ func TestCloudHandlerDispatch(t *testing.T) {
 func TestCloudHandlerInstanceNotFound(t *testing.T) {
 	t.Parallel()
 	fp := &fakeprovider.NotFound{}
-	expectedIps := []gostatsd.IP{"1.2.3.4", "4.3.2.1"}
+	expectedIps := []gostatsd.Source{"1.2.3.4", "4.3.2.1"}
 	expectedMetrics := []gostatsd.Metric{
 		sm1(),
 		sm2(),
@@ -177,7 +173,7 @@ func TestCloudHandlerInstanceNotFound(t *testing.T) {
 func TestCloudHandlerFailingProvider(t *testing.T) {
 	t.Parallel()
 	fp := &fakeprovider.Failing{}
-	expectedIps := []gostatsd.IP{"1.2.3.4", "4.3.2.1"}
+	expectedIps := []gostatsd.Source{"1.2.3.4", "4.3.2.1"}
 	expectedMetrics := []gostatsd.Metric{
 		sm1(),
 		sm2(),
@@ -189,7 +185,7 @@ func TestCloudHandlerFailingProvider(t *testing.T) {
 	doCheck(t, fp, sm1(), se1(), sm2(), se2(), fp.IPs, expectedIps, expectedMetrics, expectedEvents)
 }
 
-func doCheck(t *testing.T, cloud CountingProvider, m1 gostatsd.Metric, e1 gostatsd.Event, m2 gostatsd.Metric, e2 gostatsd.Event, ipsFunc func() []gostatsd.IP, expectedIps []gostatsd.IP, expectedM []gostatsd.Metric, expectedE gostatsd.Events) {
+func doCheck(t *testing.T, cloud CountingProvider, m1 gostatsd.Metric, e1 gostatsd.Event, m2 gostatsd.Metric, e2 gostatsd.Event, ipsFunc func() []gostatsd.Source, expectedIps []gostatsd.Source, expectedM []gostatsd.Metric, expectedE gostatsd.Events) {
 	expecting := &expectingHandler{}
 	ci := cloudprovider.NewCachedCloudProvider(logrus.StandardLogger(), rate.NewLimiter(100, 120), cloud, gostatsd.CacheOptions{
 		CacheRefreshPeriod:        gostatsd.DefaultCacheRefreshPeriod,
@@ -231,43 +227,39 @@ func doCheck(t *testing.T, cloud CountingProvider, m1 gostatsd.Metric, e1 gostat
 
 func sm1() gostatsd.Metric {
 	return gostatsd.Metric{
-		Name:     "t1",
-		Value:    42.42,
-		Tags:     gostatsd.Tags{"a1"},
-		Hostname: "somehost",
-		SourceIP: "1.2.3.4",
-		Type:     gostatsd.COUNTER,
+		Name:   "t1",
+		Value:  42.42,
+		Tags:   gostatsd.Tags{"a1"},
+		Source: "1.2.3.4",
+		Type:   gostatsd.COUNTER,
 	}
 }
 
 func sm2() gostatsd.Metric {
 	return gostatsd.Metric{
-		Name:     "t1",
-		Value:    45.45,
-		Tags:     gostatsd.Tags{"a4"},
-		Hostname: "somehost",
-		SourceIP: "1.2.3.4",
-		Type:     gostatsd.COUNTER,
+		Name:   "t1",
+		Value:  45.45,
+		Tags:   gostatsd.Tags{"a4"},
+		Source: "1.2.3.4",
+		Type:   gostatsd.COUNTER,
 	}
 }
 
 func se1() gostatsd.Event {
 	return gostatsd.Event{
-		Title:    "t12",
-		Text:     "asrasdfasdr",
-		Tags:     gostatsd.Tags{"a2"},
-		Hostname: "some_random_host",
-		SourceIP: "4.3.2.1",
+		Title:  "t12",
+		Text:   "asrasdfasdr",
+		Tags:   gostatsd.Tags{"a2"},
+		Source: "4.3.2.1",
 	}
 }
 
 func se2() gostatsd.Event {
 	return gostatsd.Event{
-		Title:    "t1asdas",
-		Text:     "asdr",
-		Tags:     gostatsd.Tags{"a2-35"},
-		Hostname: "some_random_host",
-		SourceIP: "4.3.2.1",
+		Title:  "t1asdas",
+		Text:   "asdr",
+		Tags:   gostatsd.Tags{"a2-35"},
+		Source: "4.3.2.1",
 	}
 }
 
diff --git a/pkg/statsd/handler_http_forwarder_v2_test.go b/pkg/statsd/handler_http_forwarder_v2_test.go
index 43a0d1d..e38cc28 100644
--- a/pkg/statsd/handler_http_forwarder_v2_test.go
+++ b/pkg/statsd/handler_http_forwarder_v2_test.go
@@ -18,58 +18,58 @@ func TestHttpForwarderV2Translation(t *testing.T) {
 
 	metrics := []*gostatsd.Metric{
 		{
-			Name:     "TestHttpForwarderTranslation.gauge",
-			Value:    12345,
-			Tags:     gostatsd.Tags{"TestHttpForwarderTranslation.gauge.tag1", "TestHttpForwarderTranslation.gauge.tag2"},
-			Hostname: "TestHttpForwarderTranslation.gauge.host",
-			Rate:     1,
-			Type:     gostatsd.GAUGE,
+			Name:   "TestHttpForwarderTranslation.gauge",
+			Value:  12345,
+			Tags:   gostatsd.Tags{"TestHttpForwarderTranslation.gauge.tag1", "TestHttpForwarderTranslation.gauge.tag2"},
+			Source: "TestHttpForwarderTranslation.gauge.host",
+			Rate:   1,
+			Type:   gostatsd.GAUGE,
 		},
 		{
-			Name:     "TestHttpForwarderTranslation.gaugerate",
-			Value:    12346,
-			Tags:     gostatsd.Tags{"TestHttpForwarderTranslation.gaugerate.tag1", "TestHttpForwarderTranslation.gaugerate.tag2"},
-			Hostname: "TestHttpForwarderTranslation.gaugerate.host",
-			Rate:     0.1, // ignored
-			Type:     gostatsd.GAUGE,
+			Name:   "TestHttpForwarderTranslation.gaugerate",
+			Value:  12346,
+			Tags:   gostatsd.Tags{"TestHttpForwarderTranslation.gaugerate.tag1", "TestHttpForwarderTranslation.gaugerate.tag2"},
+			Source: "TestHttpForwarderTranslation.gaugerate.host",
+			Rate:   0.1, // ignored
+			Type:   gostatsd.GAUGE,
 		},
 		{
-			Name:     "TestHttpForwarderTranslation.counter",
-			Value:    12347,
-			Tags:     gostatsd.Tags{"TestHttpForwarderTranslation.counter.tag1", "TestHttpForwarderTranslation.counter.tag2"},
-			Hostname: "TestHttpForwarderTranslation.counter.host",
-			Rate:     1,
-			Type:     gostatsd.COUNTER,
+			Name:   "TestHttpForwarderTranslation.counter",
+			Value:  12347,
+			Tags:   gostatsd.Tags{"TestHttpForwarderTranslation.counter.tag1", "TestHttpForwarderTranslation.counter.tag2"},
+			Source: "TestHttpForwarderTranslation.counter.host",
+			Rate:   1,
+			Type:   gostatsd.COUNTER,
 		},
 		{
-			Name:     "TestHttpForwarderTranslation.counterrate",
-			Value:    12348,
-			Tags:     gostatsd.Tags{"TestHttpForwarderTranslation.counterrate.tag1", "TestHttpForwarderTranslation.counterrate.tag2"},
-			Hostname: "TestHttpForwarderTranslation.counterrate.host",
-			Rate:     0.1, // multiplied out
-			Type:     gostatsd.COUNTER,
+			Name:   "TestHttpForwarderTranslation.counterrate",
+			Value:  12348,
+			Tags:   gostatsd.Tags{"TestHttpForwarderTranslation.counterrate.tag1", "TestHttpForwarderTranslation.counterrate.tag2"},
+			Source: "TestHttpForwarderTranslation.counterrate.host",
+			Rate:   0.1, // multiplied out
+			Type:   gostatsd.COUNTER,
 		},
 		{
-			Name:     "TestHttpForwarderTranslation.timer",
-			Value:    12349,
-			Tags:     gostatsd.Tags{"TestHttpForwarderTranslation.timer.tag1", "TestHttpForwarderTranslation.timer.tag2"},
-			Hostname: "TestHttpForwarderTranslation.timer.host",
-			Rate:     1,
-			Type:     gostatsd.TIMER,
+			Name:   "TestHttpForwarderTranslation.timer",
+			Value:  12349,
+			Tags:   gostatsd.Tags{"TestHttpForwarderTranslation.timer.tag1", "TestHttpForwarderTranslation.timer.tag2"},
+			Source: "TestHttpForwarderTranslation.timer.host",
+			Rate:   1,
+			Type:   gostatsd.TIMER,
 		},
 		{
-			Name:     "TestHttpForwarderTranslation.timerrate",
-			Value:    12350,
-			Tags:     gostatsd.Tags{"TestHttpForwarderTranslation.timerrate.tag1", "TestHttpForwarderTranslation.timerrate.tag2"},
-			Hostname: "TestHttpForwarderTranslation.timerrate.host",
-			Rate:     0.1, // propagated
-			Type:     gostatsd.TIMER,
+			Name:   "TestHttpForwarderTranslation.timerrate",
+			Value:  12350,
+			Tags:   gostatsd.Tags{"TestHttpForwarderTranslation.timerrate.tag1", "TestHttpForwarderTranslation.timerrate.tag2"},
+			Source: "TestHttpForwarderTranslation.timerrate.host",
+			Rate:   0.1, // propagated
+			Type:   gostatsd.TIMER,
 		},
 		{
 			Name:        "TestHttpForwarderTranslation.set",
 			StringValue: "12351",
 			Tags:        gostatsd.Tags{"TestHttpForwarderTranslation.set.tag1", "TestHttpForwarderTranslation.set.tag2"},
-			Hostname:    "TestHttpForwarderTranslation.set.host",
+			Source:      "TestHttpForwarderTranslation.set.host",
 			Rate:        1,
 			Type:        gostatsd.SET,
 		},
@@ -77,7 +77,7 @@ func TestHttpForwarderV2Translation(t *testing.T) {
 			Name:        "TestHttpForwarderTranslation.setrate",
 			StringValue: "12352",
 			Tags:        gostatsd.Tags{"TestHttpForwarderTranslation.setrate.tag1", "TestHttpForwarderTranslation.setrate.tag2"},
-			Hostname:    "TestHttpForwarderTranslation.setrate.host",
+			Source:      "TestHttpForwarderTranslation.setrate.host",
 			Rate:        0.1, // ignored
 			Type:        gostatsd.SET,
 		},
@@ -190,8 +190,7 @@ func BenchmarkHttpForwarderV2TranslateAll(b *testing.B) {
 			Value:       123.456,
 			StringValue: "123.456",
 			Tags:        gostatsd.Tags{"tag1", "tag2"},
-			Hostname:    "hostname",
-			SourceIP:    "sourceip",
+			Source:      "hostname",
 			Timestamp:   10,
 			Type:        1 + gostatsd.MetricType(i%4), // Use all types
 		})
diff --git a/pkg/statsd/handler_tags_test.go b/pkg/statsd/handler_tags_test.go
index ea809da..b0453cc 100644
--- a/pkg/statsd/handler_tags_test.go
+++ b/pkg/statsd/handler_tags_test.go
@@ -94,7 +94,7 @@ func TestFilterPassesNoFilters(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	expected := []*gostatsd.Metric{
 		{
@@ -103,7 +103,7 @@ func TestFilterPassesNoFilters(t *testing.T) {
 				"foo:bar",
 				"host:baz",
 			},
-			Hostname: "baz",
+			Source: "baz",
 		},
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
@@ -120,7 +120,7 @@ func TestFilterPassesEmptyFilters(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	expected := []*gostatsd.Metric{
 		{
@@ -129,7 +129,7 @@ func TestFilterPassesEmptyFilters(t *testing.T) {
 				"foo:bar",
 				"host:baz",
 			},
-			Hostname: "baz",
+			Source: "baz",
 		},
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
@@ -151,7 +151,7 @@ func TestFilterKeepNonMatch(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	expected := []*gostatsd.Metric{
@@ -161,7 +161,7 @@ func TestFilterKeepNonMatch(t *testing.T) {
 				"foo:bar",
 				"host:baz",
 			},
-			Hostname: "baz",
+			Source: "baz",
 		},
 	}
 	assert.Equal(t, expected, tch.m)
@@ -182,7 +182,7 @@ func TestFilterDropsBadName(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	assert.Equal(t, 0, len(tch.m))
@@ -203,7 +203,7 @@ func TestFilterDropsBadPrefix(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	assert.Equal(t, 0, len(tch.m))
@@ -226,7 +226,7 @@ func TestFilterKeepsWhitelist(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 
@@ -236,7 +236,7 @@ func TestFilterKeepsWhitelist(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 
@@ -247,7 +247,7 @@ func TestFilterKeepsWhitelist(t *testing.T) {
 				"foo:bar",
 				"host:baz",
 			},
-			Hostname: "baz",
+			Source: "baz",
 		},
 	}
 	assert.Equal(t, expected, tch.m)
@@ -269,7 +269,7 @@ func TestFilterDropsTag(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 
@@ -279,7 +279,7 @@ func TestFilterDropsTag(t *testing.T) {
 			Tags: gostatsd.Tags{
 				"host:baz",
 			},
-			Hostname: "baz",
+			Source: "baz",
 		},
 	}
 	assert.Equal(t, expected, tch.m)
@@ -301,7 +301,7 @@ func TestFilterDropsHost(t *testing.T) {
 			"foo:bar",
 			"host:baz",
 		},
-		Hostname: "baz",
+		Source: "baz",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 
@@ -312,7 +312,7 @@ func TestFilterDropsHost(t *testing.T) {
 				"foo:bar",
 				"host:baz",
 			},
-			Hostname: "",
+			Source: "",
 		},
 	}
 	assert.Equal(t, expected, tch.m)
@@ -415,7 +415,7 @@ func TestTagMetricHandlerAddsNoTags(t *testing.T) {
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	assert.Equal(t, 1, len(tch.m)) // Metric tracked
 	assertHasAllTags(t, tch.m[0].Tags)
-	assert.Equal(t, "", tch.m[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.m[0].Source) // No hostname added
 }
 
 func TestTagMetricHandlerAddsSingleTag(t *testing.T) {
@@ -425,7 +425,7 @@ func TestTagMetricHandlerAddsSingleTag(t *testing.T) {
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	assert.Equal(t, 1, len(tch.m)) // Metric tracked
 	assertHasAllTags(t, tch.m[0].Tags, "tag1")
-	assert.Equal(t, "", tch.m[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.m[0].Source) // No hostname added
 }
 
 func TestTagMetricHandlerAddsMultipleTags(t *testing.T) {
@@ -435,19 +435,19 @@ func TestTagMetricHandlerAddsMultipleTags(t *testing.T) {
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	assert.Equal(t, 1, len(tch.m)) // Metric tracked
 	assertHasAllTags(t, tch.m[0].Tags, "tag1", "tag2")
-	assert.Equal(t, "", tch.m[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.m[0].Source) // No hostname added
 }
 
 func TestTagMetricHandlerAddsHostname(t *testing.T) {
 	tch := &capturingHandler{}
 	th := NewTagHandler(tch, gostatsd.Tags{}, nil)
 	m := &gostatsd.Metric{
-		SourceIP: "1.2.3.4",
+		Source: "1.2.3.4",
 	}
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
-	assert.Equal(t, 1, len(tch.m))                // Metric tracked
-	assert.Equal(t, 0, len(tch.m[0].Tags))        // No tags added
-	assert.Equal(t, "1.2.3.4", tch.m[0].Hostname) // Hostname injected
+	assert.Equal(t, 1, len(tch.m))                               // Metric tracked
+	assert.Equal(t, 0, len(tch.m[0].Tags))                       // No tags added
+	assert.Equal(t, gostatsd.Source("1.2.3.4"), tch.m[0].Source) // Hostname injected
 }
 
 func TestTagMetricHandlerAddsDuplicateTags(t *testing.T) {
@@ -457,7 +457,7 @@ func TestTagMetricHandlerAddsDuplicateTags(t *testing.T) {
 	th.DispatchMetrics(context.Background(), []*gostatsd.Metric{m})
 	assert.Equal(t, 1, len(tch.m)) // Metric tracked
 	assertHasAllTags(t, tch.m[0].Tags, "tag1", "tag2", "tag3")
-	assert.Equal(t, "", tch.m[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.m[0].Source) // No hostname added
 }
 
 func TestTagEventHandlerAddsNoTags(t *testing.T) {
@@ -467,7 +467,7 @@ func TestTagEventHandlerAddsNoTags(t *testing.T) {
 	th.DispatchEvent(context.Background(), e)
 	assert.Equal(t, 1, len(tch.e)) // Metric tracked
 	assertHasAllTags(t, tch.e[0].Tags)
-	assert.Equal(t, "", tch.e[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.e[0].Source) // No hostname added
 }
 
 func TestTagEventHandlerAddsSingleTag(t *testing.T) {
@@ -477,7 +477,7 @@ func TestTagEventHandlerAddsSingleTag(t *testing.T) {
 	th.DispatchEvent(context.Background(), e)
 	assert.Equal(t, 1, len(tch.e)) // Metric tracked
 	assertHasAllTags(t, tch.e[0].Tags, "tag1")
-	assert.Equal(t, "", tch.e[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.e[0].Source) // No hostname added
 }
 
 func TestTagEventHandlerAddsMultipleTags(t *testing.T) {
@@ -487,19 +487,19 @@ func TestTagEventHandlerAddsMultipleTags(t *testing.T) {
 	th.DispatchEvent(context.Background(), e)
 	assert.Equal(t, 1, len(tch.e)) // Metric tracked
 	assertHasAllTags(t, tch.e[0].Tags, "tag1", "tag2")
-	assert.Equal(t, "", tch.e[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.e[0].Source) // No hostname added
 }
 
 func TestTagEventHandlerAddsHostname(t *testing.T) {
 	tch := &capturingHandler{}
 	th := NewTagHandler(tch, gostatsd.Tags{}, nil)
 	e := &gostatsd.Event{
-		SourceIP: "1.2.3.4",
+		Source: "1.2.3.4",
 	}
 	th.DispatchEvent(context.Background(), e)
 	assert.Equal(t, 1, len(tch.e)) // Metric tracked
 	assertHasAllTags(t, tch.e[0].Tags)
-	assert.Equal(t, "1.2.3.4", tch.e[0].Hostname) // Hostname injected
+	assert.Equal(t, gostatsd.Source("1.2.3.4"), tch.e[0].Source) // Hostname injected
 }
 
 func TestTagEventHandlerAddsDuplicateTags(t *testing.T) {
@@ -509,7 +509,7 @@ func TestTagEventHandlerAddsDuplicateTags(t *testing.T) {
 	th.DispatchEvent(context.Background(), e)
 	assert.Equal(t, 1, len(tch.e)) // Metric tracked
 	assertHasAllTags(t, tch.e[0].Tags, "tag1", "tag2", "tag3")
-	assert.Equal(t, "", tch.e[0].Hostname) // No hostname added
+	assert.Equal(t, gostatsd.UnknownSource, tch.e[0].Source) // No hostname added
 }
 
 func BenchmarkTagMetricHandlerAddsDuplicateTagsSmall(b *testing.B) {
diff --git a/pkg/statsd/lexer_test.go b/pkg/statsd/lexer_test.go
index 4dc0fe1..7552f4b 100644
--- a/pkg/statsd/lexer_test.go
+++ b/pkg/statsd/lexer_test.go
@@ -73,15 +73,15 @@ func TestEventsLexer(t *testing.T) {
 		"_e{1,1}:a|b":                                               {Title: "a", Text: "b"},
 		"_e{6,18}:ab|| c|hello,\\nmy friend!":                       {Title: "ab|| c", Text: "hello,\nmy friend!"},
 		"_e{1,1}:a|b|d:123123":                                      {Title: "a", Text: "b", DateHappened: 123123},
-		"_e{1,1}:a|b|d:123123|h:hoost":                              {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost"},
-		"_e{1,1}:a|b|d:123123|h:hoost|p:low":                        {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost", Priority: gostatsd.PriLow},
-		"_e{1,1}:a|b|d:123123|h:hoost|p:low|t:warning":              {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning},
-		"_e{1,1}:a|b|d:123123|h:hoost|p:low|t:warning|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
-		"_e{1,1}:a|b|t:warning|d:123123|h:hoost|p:low|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
-		"_e{1,1}:a|b|p:low|t:warning|d:123123|h:hoost|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
-		"_e{1,1}:a|b|h:hoost|p:low|t:warning|d:123123|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Hostname: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
-
-		"_e{1,1}:a|b|h:hoost":      {Title: "a", Text: "b", Hostname: "hoost"},
+		"_e{1,1}:a|b|d:123123|h:hoost":                              {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost"},
+		"_e{1,1}:a|b|d:123123|h:hoost|p:low":                        {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost", Priority: gostatsd.PriLow},
+		"_e{1,1}:a|b|d:123123|h:hoost|p:low|t:warning":              {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning},
+		"_e{1,1}:a|b|d:123123|h:hoost|p:low|t:warning|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
+		"_e{1,1}:a|b|t:warning|d:123123|h:hoost|p:low|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
+		"_e{1,1}:a|b|p:low|t:warning|d:123123|h:hoost|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
+		"_e{1,1}:a|b|h:hoost|p:low|t:warning|d:123123|#tag1,t:tag2": {Title: "a", Text: "b", DateHappened: 123123, Source: "hoost", Priority: gostatsd.PriLow, AlertType: gostatsd.AlertWarning, Tags: []string{"tag1", "t:tag2"}},
+
+		"_e{1,1}:a|b|h:hoost":      {Title: "a", Text: "b", Source: "hoost"},
 		"_e{1,1}:a|b|p:low":        {Title: "a", Text: "b", Priority: gostatsd.PriLow},
 		"_e{1,1}:a|b|t:warning":    {Title: "a", Text: "b", AlertType: gostatsd.AlertWarning},
 		"_e{1,1}:a|b|#tag1,t:tag2": {Title: "a", Text: "b", Tags: []string{"tag1", "t:tag2"}},
@@ -89,7 +89,7 @@ func TestEventsLexer(t *testing.T) {
 			Title:          "Deployment completed",
 			Text:           "Deployment completed in 7 minutes.",
 			DateHappened:   1463746133,
-			Hostname:       "9c00cf070c14",
+			Source:         "9c00cf070c14",
 			SourceTypeName: "Micros Server",
 			Tags:           []string{"topic:service.deploy", "message_env:pdev", "service_id:node-refapp-ci-internal", "deployment_id:72e95b0f-37b0-4cf9-8e92-3e47d006b63f"},
 			AlertType:      gostatsd.AlertSuccess,
diff --git a/pkg/statsd/parser_test.go b/pkg/statsd/parser_test.go
index 63084c0..2164c10 100644
--- a/pkg/statsd/parser_test.go
+++ b/pkg/statsd/parser_test.go
@@ -17,7 +17,7 @@ type metricAndEvent struct {
 	events  gostatsd.Events
 }
 
-const fakeIP = gostatsd.IP("127.0.0.1")
+const fakeIP = gostatsd.Source("127.0.0.1")
 
 func newTestParser(ignoreHost bool) (*DatagramParser, *countingHandler) {
 	ch := &countingHandler{}
@@ -36,7 +36,7 @@ func TestParseEmptyDatagram(t *testing.T) {
 		t.Run(strconv.Itoa(pos), func(t *testing.T) {
 			t.Parallel()
 			mr, ch := newTestParser(false)
-			_, _, _ = mr.handleDatagram(context.Background(), 0, gostatsd.UnknownIP, inp)
+			_, _, _ = mr.handleDatagram(context.Background(), 0, gostatsd.UnknownSource, inp)
 			assert.Zero(t, len(ch.events), ch.events)
 			assert.Zero(t, len(ch.metrics), ch.metrics)
 		})
@@ -48,42 +48,42 @@ func TestParseDatagram(t *testing.T) {
 	input := map[string]metricAndEvent{
 		"f:2|c": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "f", Value: 2, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
 			},
 		},
 		"f:2|c\n": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "f", Value: 2, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
 			},
 		},
 		"f:2|c|#t": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1, Tags: gostatsd.Tags{"t"}},
+				{Name: "f", Value: 2, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1, Tags: gostatsd.Tags{"t"}},
 			},
 		},
 		"f:2|c|#host:h": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1, Tags: gostatsd.Tags{"host:h"}},
+				{Name: "f", Value: 2, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1, Tags: gostatsd.Tags{"host:h"}},
 			},
 		},
 		"f:2|c\nx:3|c": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
-				{Name: "x", Value: 3, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "f", Value: 2, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "x", Value: 3, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
 			},
 		},
 		"f:2|c\nx:3|c\n": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
-				{Name: "x", Value: 3, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "f", Value: 2, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "x", Value: 3, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
 			},
 		},
 		"_e{1,1}:a|b\nf:6|c": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 6, SourceIP: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "f", Value: 6, Source: "127.0.0.1", Type: gostatsd.COUNTER, Rate: 1},
 			},
 			events: gostatsd.Events{
-				gostatsd.Event{Title: "a", Text: "b", SourceIP: "127.0.0.1"},
+				gostatsd.Event{Title: "a", Text: "b", Source: "127.0.0.1"},
 			},
 		},
 	}
@@ -127,12 +127,12 @@ func TestParseDatagramIgnoreHost(t *testing.T) {
 		},
 		"f:2|c|#host:h": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, Hostname: "h", Type: gostatsd.COUNTER, Rate: 1},
+				{Name: "f", Value: 2, Source: "h", Type: gostatsd.COUNTER, Rate: 1},
 			},
 		},
 		"f:2|c|#host:h1,host:h2": {
 			metrics: []gostatsd.Metric{
-				{Name: "f", Value: 2, Hostname: "h1", Type: gostatsd.COUNTER, Rate: 1, Tags: gostatsd.Tags{"host:h2"}},
+				{Name: "f", Value: 2, Source: "h1", Type: gostatsd.COUNTER, Rate: 1, Tags: gostatsd.Tags{"host:h2"}},
 			},
 		},
 		"f:2|c\nx:3|c": {
@@ -152,7 +152,7 @@ func TestParseDatagramIgnoreHost(t *testing.T) {
 				{Name: "f", Value: 6, Type: gostatsd.COUNTER, Rate: 1},
 			},
 			events: gostatsd.Events{
-				gostatsd.Event{Title: "a", Text: "b", SourceIP: "127.0.0.1"},
+				gostatsd.Event{Title: "a", Text: "b", Source: "127.0.0.1"},
 			},
 		},
 	}
diff --git a/pkg/statsd/statsd_test.go b/pkg/statsd/statsd_test.go
index 222a8b9..2d8822a 100644
--- a/pkg/statsd/statsd_test.go
+++ b/pkg/statsd/statsd_test.go
@@ -149,14 +149,10 @@ func (fp *fakeProvider) MaxInstancesBatch() int {
 	return 16
 }
 
-func (fp *fakeProvider) Instance(ctx context.Context, ips ...gostatsd.IP) (map[gostatsd.IP]*gostatsd.Instance, error) {
-	instances := make(map[gostatsd.IP]*gostatsd.Instance, len(ips))
+func (fp *fakeProvider) Instance(ctx context.Context, ips ...gostatsd.Source) (map[gostatsd.Source]*gostatsd.Instance, error) {
+	instances := make(map[gostatsd.Source]*gostatsd.Instance, len(ips))
 	for _, ip := range ips {
 		instances[ip] = fp.instance
 	}
 	return instances, nil
 }
-
-func (fp *fakeProvider) SelfIP() (gostatsd.IP, error) {
-	return gostatsd.UnknownIP, nil
-}