diff --git a/config.go b/config.go index ee8d2dd..51ff05d 100644 --- a/config.go +++ b/config.go @@ -52,6 +52,11 @@ type Config struct { // `os.Stderr`. Logger Logger + // Properties that will be included in every event sent by the client. + // This is useful for adding common metadata like service name or app version across all events. + // If a property conflict occurs, the value from DefaultEventProperties will overwrite any existing value. + DefaultEventProperties Properties + // The callback object that will be used by the client to notify the // application when messages sends to the backend API succeeded or failed. Callback Callback diff --git a/fixtures/test-merge-capture.json b/fixtures/test-merge-capture.json new file mode 100644 index 0000000..d754fdd --- /dev/null +++ b/fixtures/test-merge-capture.json @@ -0,0 +1,22 @@ +{ + "api_key": "Csyjlnlun3OzyNJAafdlv", + "batch": [ + { + "distinct_id": "123456", + "event": "Download", + "library": "posthog-go", + "library_version": "1.0.0", + "properties": { + "$lib": "posthog-go", + "$lib_version": "1.0.0", + "application": "PostHog Go", + "platform": "macos", + "service": "api", + "version": "1.0.0" + }, + "send_feature_flags": false, + "timestamp": "2015-07-10T23:00:00Z", + "type": "capture" + } + ] +} diff --git a/posthog.go b/posthog.go index 5d64de6..f6ed9c5 100644 --- a/posthog.go +++ b/posthog.go @@ -227,6 +227,7 @@ func (c *client) Enqueue(msg Message) (err error) { } m.Properties["$active_feature_flags"] = featureKeys } + m.Properties.Merge(c.DefaultEventProperties) c.setLastCapturedEvent(m) msg = m diff --git a/posthog_test.go b/posthog_test.go index b8bdcd0..ed56c76 100644 --- a/posthog_test.go +++ b/posthog_test.go @@ -436,6 +436,40 @@ func TestCaptureWithTimestamp(t *testing.T) { } } +func TestCaptureWithDefaultProperties(t *testing.T) { + var ref = strings.TrimSpace(fixture("test-merge-capture.json")) + + body, server := mockServer() + defer server.Close() + + client, _ := NewWithConfig("Csyjlnlun3OzyNJAafdlv", Config{ + Endpoint: server.URL, + Verbose: true, + DefaultEventProperties: NewProperties().Set("service", "api"), + Logger: t, + BatchSize: 1, + now: mockTime, + uid: mockId, + }) + defer client.Close() + + client.Enqueue(Capture{ + Event: "Download", + DistinctId: "123456", + Properties: Properties{ + "application": "PostHog Go", + "version": "1.0.0", + "platform": "macos", // :) + }, + SendFeatureFlags: false, + Timestamp: time.Date(2015, time.July, 10, 23, 0, 0, 0, time.UTC), + }) + + if res := string(<-body); ref != res { + t.Errorf("invalid response:\n- expected %s\n- received: %s", ref, res) + } +} + func TestCaptureMany(t *testing.T) { var ref = strings.TrimSpace(fixture("test-many-capture.json")) diff --git a/properties.go b/properties.go index 49d7fbe..9a5efb9 100644 --- a/properties.go +++ b/properties.go @@ -22,3 +22,13 @@ func (p Properties) Set(name string, value interface{}) Properties { p[name] = value return p } + +// Merge adds the properties from the provided `props` into the receiver `p`. +// If a property in `props` already exists in `p`, its value will be overwritten. +func (p Properties) Merge(props Properties) Properties { + for k, v := range props { + p[k] = v + } + + return p +} diff --git a/properties_test.go b/properties_test.go index 2d00d5e..4fb6a8e 100644 --- a/properties_test.go +++ b/properties_test.go @@ -34,5 +34,17 @@ func TestPropertiesMulti(t *testing.T) { if !reflect.DeepEqual(p0, p1) { t.Errorf("invalid properties produced by chained setters:\n- expected %#v\n- found: %#v", p0, p1) } +} + +func TestPropertiesMerge(t *testing.T) { + defaultProps := Properties{"currency": "USD", "service": "api"} + + props := NewProperties().Set("title", "A").Set("value", 0.5).Set("currency", "BRL") + props.Merge(defaultProps) + expected := Properties{"title": "A", "value": 0.5, "currency": "USD", "service": "api"} + + if !reflect.DeepEqual(props, Properties{"title": "A", "value": 0.5, "currency": "USD", "service": "api"}) { + t.Errorf("invalid properties produced by merge:\n- expected %#v\n- found: %#v", expected, props) + } }