From bc0769736f11f06ffd78042636e667cc7288b949 Mon Sep 17 00:00:00 2001 From: dikkini Date: Mon, 5 Feb 2024 22:13:41 +0300 Subject: [PATCH 1/6] feat(config): disable geo ip and it is true by default, because on nodejs client such behaviour --- alias.go | 39 +++++++++++++++++++++++++++++---------- capture.go | 8 ++++++++ config.go | 16 ++++++++++++++++ config_test.go | 35 +++++++++++++++++++++++++++++++++++ group_identify.go | 8 ++++++++ identify.go | 8 ++++++++ message.go | 1 + posthog.go | 12 ++++++++++++ posthog_test.go | 4 ++++ properties.go | 7 +++++++ 10 files changed, 128 insertions(+), 10 deletions(-) diff --git a/alias.go b/alias.go index 7e1c20f..7f61e52 100644 --- a/alias.go +++ b/alias.go @@ -13,6 +13,15 @@ type Alias struct { Alias string DistinctId string Timestamp time.Time + properties Properties +} + +func (msg Alias) SetProperty(name string, value interface{}) { + if msg.properties == nil { + msg.properties = Properties{} + } + + msg.properties.Set(name, value) } func (msg Alias) internal() { @@ -40,10 +49,11 @@ func (msg Alias) Validate() error { } type AliasInApiProperties struct { - DistinctId string `json:"distinct_id"` - Alias string `json:"alias"` - Lib string `json:"$lib"` - LibVersion string `json:"$lib_version"` + DistinctId string `json:"distinct_id"` + Alias string `json:"alias"` + Lib string `json:"$lib"` + LibVersion string `json:"$lib_version"` + GeoIPDisable bool `json:"$geoip_disable"` } type AliasInApi struct { @@ -61,18 +71,27 @@ func (msg Alias) APIfy() APIMessage { library := "posthog-go" libraryVersion := getVersion() + properties := AliasInApiProperties{ + DistinctId: msg.DistinctId, + Alias: msg.Alias, + Lib: library, + LibVersion: libraryVersion, + } + + if msg.properties != nil { + geoIPDisable, exist := msg.properties.Get(GeoIPDisableKey) + if exist { + properties.GeoIPDisable = geoIPDisable.(bool) + } + } + apified := AliasInApi{ Type: msg.Type, Event: "$create_alias", Library: library, LibraryVersion: libraryVersion, Timestamp: msg.Timestamp, - Properties: AliasInApiProperties{ - DistinctId: msg.DistinctId, - Alias: msg.Alias, - Lib: library, - LibVersion: libraryVersion, - }, + Properties: properties, } return apified diff --git a/capture.go b/capture.go index b54acde..fb6acdc 100644 --- a/capture.go +++ b/capture.go @@ -18,6 +18,14 @@ type Capture struct { SendFeatureFlags bool } +func (msg Capture) SetProperty(name string, value interface{}) { + if msg.Properties == nil { + msg.Properties = Properties{} + } + + msg.Properties.Set(name, value) +} + func (msg Capture) internal() { panic(unimplementedError) } diff --git a/config.go b/config.go index 280f81a..9dc49eb 100644 --- a/config.go +++ b/config.go @@ -53,6 +53,10 @@ type Config struct { // which is independent from the number of embedded messages. BatchSize int + // This parameter allow you stop using the GeoIP plugin or feature, + // which enriches your event data with geo information based on IP addresses. + DisableGeoIP *bool + // When set to true the client will send more frequent and detailed messages // to its logger. Verbose bool @@ -98,6 +102,14 @@ const DefaultFeatureFlagsPollingInterval = 5 * time.Minute // was explicitly set. const DefaultBatchSize = 250 +// This constant sets the default value for DisableGeoIP and it is true, because same behaviour in nodejs client. +const DefaultDisableGeoIP = true + +func defaultGeoIPDisable() *bool { + val := DefaultDisableGeoIP + return &val +} + // Verifies that fields that don't have zero-values are set to valid values, // returns an error describing the problem if a field was invalid. func (c *Config) validate() error { @@ -151,6 +163,10 @@ func makeConfig(c Config) Config { c.RetryAfter = DefaultBacko().Duration } + if c.DisableGeoIP == nil { + c.DisableGeoIP = defaultGeoIPDisable() + } + if c.uid == nil { c.uid = uid } diff --git a/config_test.go b/config_test.go index 7775431..363c3af 100644 --- a/config_test.go +++ b/config_test.go @@ -44,3 +44,38 @@ func TestConfigInvalidBatchSize(t *testing.T) { t.Error("invalid field error reported:", e) } } + +func TestConfigDisableGeoIP(t *testing.T) { + positiveVal := true + negativeVal := false + + c := Config{} + + if c.DisableGeoIP != nil { + t.Error("invalid value for DisableGeoIP:", c.DisableGeoIP) + } + + c = makeConfig(c) + + if *c.DisableGeoIP != positiveVal { + t.Error("invalid value for DisableGeoIP:", *c.DisableGeoIP) + } + + c = Config{ + DisableGeoIP: &positiveVal, + } + + c = makeConfig(c) + + if *c.DisableGeoIP != positiveVal { + t.Error("invalid value for DisableGeoIP:", *c.DisableGeoIP) + } + + c.DisableGeoIP = &negativeVal + + c = makeConfig(c) + + if *c.DisableGeoIP != negativeVal { + t.Error("invalid value for DisableGeoIP:", *c.DisableGeoIP) + } +} diff --git a/group_identify.go b/group_identify.go index 52cc210..6708f72 100644 --- a/group_identify.go +++ b/group_identify.go @@ -14,6 +14,14 @@ type GroupIdentify struct { Properties Properties } +func (msg GroupIdentify) SetProperty(name string, value interface{}) { + if msg.Properties == nil { + msg.Properties = Properties{} + } + + msg.Properties.Set(name, value) +} + func (msg GroupIdentify) internal() { panic(unimplementedError) } diff --git a/identify.go b/identify.go index 2a6399f..e6a44f2 100644 --- a/identify.go +++ b/identify.go @@ -15,6 +15,14 @@ type Identify struct { Properties Properties } +func (msg Identify) SetProperty(name string, value interface{}) { + if msg.Properties == nil { + msg.Properties = Properties{} + } + + msg.Properties.Set(name, value) +} + func (msg Identify) internal() { panic(unimplementedError) } diff --git a/message.go b/message.go index 2edd4ed..9358d41 100644 --- a/message.go +++ b/message.go @@ -37,6 +37,7 @@ type Message interface { // nil if the message is valid, or an error describing what went wrong. Validate() error APIfy() APIMessage + SetProperty(name string, value interface{}) // internal is an unexposed interface function to ensure only types defined within this package can satisfy the Message interface. Invoking this method will panic. internal() diff --git a/posthog.go b/posthog.go index 4c2aa0d..d17e566 100644 --- a/posthog.go +++ b/posthog.go @@ -169,15 +169,24 @@ func (c *client) Enqueue(msg Message) (err error) { case Alias: m.Type = "alias" m.Timestamp = makeTimestamp(m.Timestamp, ts) + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } msg = m case Identify: m.Type = "identify" m.Timestamp = makeTimestamp(m.Timestamp, ts) + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } msg = m case GroupIdentify: m.Timestamp = makeTimestamp(m.Timestamp, ts) + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } msg = m case Capture: @@ -202,6 +211,9 @@ func (c *client) Enqueue(msg Message) (err error) { } m.Properties["$active_feature_flags"] = featureKeys } + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } msg = m default: diff --git a/posthog_test.go b/posthog_test.go index 3b7c77a..a4cec10 100644 --- a/posthog_test.go +++ b/posthog_test.go @@ -73,6 +73,8 @@ var _ Message = (*testErrorMessage)(nil) type testErrorMessage struct{} type testAPIErrorMessage struct{} +func (m testErrorMessage) SetProperty(name string, value interface{}) {} + func (m testErrorMessage) internal() { } @@ -342,6 +344,8 @@ type customMessage struct { type customAPIMessage struct { } +func (c *customMessage) SetProperty(name string, value interface{}) {} + func (c *customMessage) internal() { } diff --git a/properties.go b/properties.go index 49d7fbe..99387bc 100644 --- a/properties.go +++ b/properties.go @@ -1,5 +1,7 @@ package posthog +const GeoIPDisableKey = "$geoip_disable" + // This type is used to represent properties in messages that support it. // It is a free-form object so the application can set any value it sees fit but // a few helper method are defined to make it easier to instantiate properties with @@ -22,3 +24,8 @@ func (p Properties) Set(name string, value interface{}) Properties { p[name] = value return p } + +func (p Properties) Get(name string) (interface{}, bool) { + value, ok := p[name] + return value, ok +} From 09ef0ed435a47b59988111967228394b7637d661 Mon Sep 17 00:00:00 2001 From: dikkini Date: Tue, 6 Feb 2024 15:50:19 +0300 Subject: [PATCH 2/6] fix(enqueue): don not override geo ip disable if it is setup directly in Message --- posthog.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/posthog.go b/posthog.go index d17e566..f4e6d07 100644 --- a/posthog.go +++ b/posthog.go @@ -169,23 +169,29 @@ func (c *client) Enqueue(msg Message) (err error) { case Alias: m.Type = "alias" m.Timestamp = makeTimestamp(m.Timestamp, ts) - if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + if _, ok := m.properties[GeoIPDisableKey]; !ok { + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } } msg = m case Identify: m.Type = "identify" m.Timestamp = makeTimestamp(m.Timestamp, ts) - if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + if _, ok := m.Properties[GeoIPDisableKey]; !ok { + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } } msg = m case GroupIdentify: m.Timestamp = makeTimestamp(m.Timestamp, ts) - if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + if _, ok := m.Properties[GeoIPDisableKey]; !ok { + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } } msg = m @@ -211,8 +217,10 @@ func (c *client) Enqueue(msg Message) (err error) { } m.Properties["$active_feature_flags"] = featureKeys } - if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + if _, ok := m.Properties[GeoIPDisableKey]; !ok { + if c.Config.DisableGeoIP != nil { + m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + } } msg = m From 5c07db1789f45687756bd27188a3980e965037d3 Mon Sep 17 00:00:00 2001 From: dikkini Date: Thu, 8 Feb 2024 22:06:56 +0300 Subject: [PATCH 3/6] fix: do not overwrite Properties in identify --- identify.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/identify.go b/identify.go index e6a44f2..5bee828 100644 --- a/identify.go +++ b/identify.go @@ -54,7 +54,11 @@ type IdentifyInApi struct { func (msg Identify) APIfy() APIMessage { library := "posthog-go" - myProperties := Properties{}.Set("$lib", library).Set("$lib_version", getVersion()) + if msg.Properties == nil { + msg.Properties = Properties{} + } + + myProperties := msg.Properties.Set("$lib", library).Set("$lib_version", getVersion()) apified := IdentifyInApi{ Type: msg.Type, From 8343c384aadbedc12f489f33aaa19f788286d07d Mon Sep 17 00:00:00 2001 From: dikkini Date: Thu, 8 Feb 2024 22:09:28 +0300 Subject: [PATCH 4/6] fix: do not overwrite Properties in GorupIdentify --- group_identify.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/group_identify.go b/group_identify.go index 6708f72..d15e724 100644 --- a/group_identify.go +++ b/group_identify.go @@ -59,7 +59,11 @@ type GroupIdentifyInApi struct { func (msg GroupIdentify) APIfy() APIMessage { library := "posthog-go" - myProperties := Properties{}.Set("$lib", library).Set("$lib_version", getVersion()) + if msg.Properties == nil { + msg.Properties = Properties{} + } + + myProperties := msg.Properties.Set("$lib", library).Set("$lib_version", getVersion()) myProperties.Set("$group_type", msg.Type).Set("$group_key", msg.Key).Set("$group_set", msg.Properties) distinctId := fmt.Sprintf("$%s_%s", msg.Type, msg.Key) From b0e8d3b049d42119f394b3ad9501b99b762edeb8 Mon Sep 17 00:00:00 2001 From: dikkini Date: Thu, 8 Feb 2024 22:40:34 +0300 Subject: [PATCH 5/6] fix: receiver was not as pointer so properties were nor override --- alias.go | 6 ++++-- capture.go | 4 +++- group_identify.go | 4 +++- identify.go | 4 +++- message.go | 2 +- posthog.go | 8 ++++---- posthog_test.go | 50 +++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 66 insertions(+), 12 deletions(-) diff --git a/alias.go b/alias.go index 7f61e52..db1200f 100644 --- a/alias.go +++ b/alias.go @@ -16,12 +16,14 @@ type Alias struct { properties Properties } -func (msg Alias) SetProperty(name string, value interface{}) { +func (msg Alias) SetProperty(name string, value interface{}) Properties { if msg.properties == nil { msg.properties = Properties{} } msg.properties.Set(name, value) + + return msg.properties } func (msg Alias) internal() { @@ -53,7 +55,7 @@ type AliasInApiProperties struct { Alias string `json:"alias"` Lib string `json:"$lib"` LibVersion string `json:"$lib_version"` - GeoIPDisable bool `json:"$geoip_disable"` + GeoIPDisable bool `json:"$geoip_disable,omitempty"` } type AliasInApi struct { diff --git a/capture.go b/capture.go index fb6acdc..10ee4a1 100644 --- a/capture.go +++ b/capture.go @@ -18,12 +18,14 @@ type Capture struct { SendFeatureFlags bool } -func (msg Capture) SetProperty(name string, value interface{}) { +func (msg Capture) SetProperty(name string, value interface{}) Properties { if msg.Properties == nil { msg.Properties = Properties{} } msg.Properties.Set(name, value) + + return msg.Properties } func (msg Capture) internal() { diff --git a/group_identify.go b/group_identify.go index d15e724..0d8d61d 100644 --- a/group_identify.go +++ b/group_identify.go @@ -14,12 +14,14 @@ type GroupIdentify struct { Properties Properties } -func (msg GroupIdentify) SetProperty(name string, value interface{}) { +func (msg GroupIdentify) SetProperty(name string, value interface{}) Properties { if msg.Properties == nil { msg.Properties = Properties{} } msg.Properties.Set(name, value) + + return msg.Properties } func (msg GroupIdentify) internal() { diff --git a/identify.go b/identify.go index 5bee828..08fd9d3 100644 --- a/identify.go +++ b/identify.go @@ -15,12 +15,14 @@ type Identify struct { Properties Properties } -func (msg Identify) SetProperty(name string, value interface{}) { +func (msg Identify) SetProperty(name string, value interface{}) Properties { if msg.Properties == nil { msg.Properties = Properties{} } msg.Properties.Set(name, value) + + return msg.Properties } func (msg Identify) internal() { diff --git a/message.go b/message.go index 9358d41..b3115e6 100644 --- a/message.go +++ b/message.go @@ -37,7 +37,7 @@ type Message interface { // nil if the message is valid, or an error describing what went wrong. Validate() error APIfy() APIMessage - SetProperty(name string, value interface{}) + SetProperty(name string, value interface{}) Properties // internal is an unexposed interface function to ensure only types defined within this package can satisfy the Message interface. Invoking this method will panic. internal() diff --git a/posthog.go b/posthog.go index f4e6d07..f25caca 100644 --- a/posthog.go +++ b/posthog.go @@ -171,7 +171,7 @@ func (c *client) Enqueue(msg Message) (err error) { m.Timestamp = makeTimestamp(m.Timestamp, ts) if _, ok := m.properties[GeoIPDisableKey]; !ok { if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + m.properties = m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) } } msg = m @@ -181,7 +181,7 @@ func (c *client) Enqueue(msg Message) (err error) { m.Timestamp = makeTimestamp(m.Timestamp, ts) if _, ok := m.Properties[GeoIPDisableKey]; !ok { if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + m.Properties = m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) } } msg = m @@ -190,7 +190,7 @@ func (c *client) Enqueue(msg Message) (err error) { m.Timestamp = makeTimestamp(m.Timestamp, ts) if _, ok := m.Properties[GeoIPDisableKey]; !ok { if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + m.Properties = m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) } } msg = m @@ -219,7 +219,7 @@ func (c *client) Enqueue(msg Message) (err error) { } if _, ok := m.Properties[GeoIPDisableKey]; !ok { if c.Config.DisableGeoIP != nil { - m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) + m.Properties = m.SetProperty(GeoIPDisableKey, *c.Config.DisableGeoIP) } } msg = m diff --git a/posthog_test.go b/posthog_test.go index a4cec10..fbc0fac 100644 --- a/posthog_test.go +++ b/posthog_test.go @@ -17,6 +17,52 @@ import ( "time" ) +func TestClient_Enqueue(t *testing.T) { + c := New("") + + err := c.Enqueue(GroupIdentify{ + DistinctId: "1", + Type: "abc", + Key: "def", + }) + if err != nil { + t.Error("enqueue failed:", err) + } + + err = c.Enqueue(Identify{ + DistinctId: "1", + Type: "abc", + }) + if err != nil { + t.Error("enqueue failed:", err) + } + + err = c.Enqueue(Capture{ + DistinctId: "1", + Event: "abc", + }) + if err != nil { + t.Error("enqueue failed:", err) + } + + err = c.Enqueue(Capture{ + DistinctId: "1", + Event: "abc", + Properties: NewProperties().Set(GeoIPDisableKey, false), + }) + if err != nil { + t.Error("enqueue failed:", err) + } + + err = c.Enqueue(Alias{ + DistinctId: "1", + Alias: "abc", + }) + if err != nil { + t.Error("enqueue failed:", err) + } +} + // Helper type used to implement the io.Reader interface on function values. type readFunc func([]byte) (int, error) @@ -73,7 +119,7 @@ var _ Message = (*testErrorMessage)(nil) type testErrorMessage struct{} type testAPIErrorMessage struct{} -func (m testErrorMessage) SetProperty(name string, value interface{}) {} +func (m testErrorMessage) SetProperty(name string, value interface{}) Properties { return Properties{} } func (m testErrorMessage) internal() { } @@ -344,7 +390,7 @@ type customMessage struct { type customAPIMessage struct { } -func (c *customMessage) SetProperty(name string, value interface{}) {} +func (c *customMessage) SetProperty(name string, value interface{}) Properties { return Properties{} } func (c *customMessage) internal() { } From a30c1ea63a653c5a11ec180daad2cdc5caa765d8 Mon Sep 17 00:00:00 2001 From: dikkini Date: Sun, 5 May 2024 01:14:47 +0300 Subject: [PATCH 6/6] fix: add uuid --- capture.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/capture.go b/capture.go index 10ee4a1..6b2ef1f 100644 --- a/capture.go +++ b/capture.go @@ -10,6 +10,7 @@ type Capture struct { // the application, its value is always overwritten by the library. Type string + Uuid string DistinctId string Event string Timestamp time.Time @@ -58,6 +59,7 @@ type CaptureInApi struct { LibraryVersion string `json:"library_version"` Timestamp time.Time `json:"timestamp"` + Uuid string `json:"uuid"` DistinctId string `json:"distinct_id"` Event string `json:"event"` Properties Properties `json:"properties"` @@ -81,6 +83,7 @@ func (msg Capture) APIfy() APIMessage { } apified := CaptureInApi{ + Uuid: msg.Uuid, Type: msg.Type, Library: library, LibraryVersion: libraryVersion,