Skip to content

Commit

Permalink
Merge pull request #54 from statsig-io/log-immediate
Browse files Browse the repository at this point in the history
add logImmediate api
  • Loading branch information
jkw-statsig authored Dec 17, 2021
2 parents f5706cf + e2cb7db commit e21d231
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 12 deletions.
23 changes: 23 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package statsig

import (
"encoding/json"
"fmt"
"net/http"
"strings"
)

Expand Down Expand Up @@ -93,6 +95,27 @@ func (c *Client) LogEvent(event Event) {
c.logger.logCustom(event)
}

func (c *Client) LogImmediate(events []Event) (*http.Response, error) {
if len(events) > 500 {
return nil, fmt.Errorf("The max number of events supported in one batch is 500. Please reduce the slice size and try again.")
}
events_processed := make([]interface{}, 0)
for _, event := range events {
event.User = normalizeUser(event.User, *c.options)
events_processed = append(events_processed, event)
}
input := &logEventInput{
Events: events_processed,
StatsigMetadata: c.transport.metadata,
}
body, err := json.Marshal(input)

if err != nil {
return nil, err
}
return c.transport.doRequest("/log_event", body)
}

// Cleans up Statsig, persisting any Event Logs and cleanup processes
// Using any method is undefined after Shutdown() has been called
func (c *Client) Shutdown() {
Expand Down
9 changes: 9 additions & 0 deletions statsig.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package statsig

import (
"fmt"
"net/http"
"sync"
)

Expand Down Expand Up @@ -70,6 +71,14 @@ func LogEvent(event Event) {
instance.LogEvent(event)
}

// Logs a slice of events to Statsig server immediately
func LogImmediate(events []Event) (*http.Response, error) {
if instance == nil {
panic(fmt.Errorf("must Initialize() statsig before calling LogImmediate"))
}
return instance.LogImmediate(events)
}

// Cleans up Statsig, persisting any Event Logs and cleanup processes
// Using any method is undefined after Shutdown() has been called
func Shutdown() {
Expand Down
51 changes: 51 additions & 0 deletions statsig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package statsig

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
)

func TestLogImmediate(t *testing.T) {
env := ""
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
t.Errorf("Expected ‘POST’ request, got '%s'", req.Method)
}
if strings.Contains(req.URL.Path, "log_event") {
type requestInput struct {
Events []Event `json:"events"`
StatsigMetadata statsigMetadata `json:"statsigMetadata"`
}
input := &requestInput{}
defer req.Body.Close()
buf := new(bytes.Buffer)
buf.ReadFrom(req.Body)

json.Unmarshal(buf.Bytes(), &input)
env = input.Events[0].User.StatsigEnvironment["tier"]
}

res.WriteHeader(http.StatusOK)
}))
defer testServer.Close()
opt := &Options{
API: testServer.URL,
Environment: Environment{Tier: "test"},
}
InitializeWithOptions("secret-key", opt)
event := Event{EventName: "test_event", User: User{UserID: "123"}}
response, err := LogImmediate([]Event{event})
if response.StatusCode != http.StatusOK {
t.Errorf("Status should be OK")
}
if err != nil {
t.Errorf("Error should be nil")
}
if env != "test" {
t.Errorf("Environment not set on user")
}
}
28 changes: 16 additions & 12 deletions transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func newTransport(secret string, options *Options) *transport {

return &transport{
api: api,
metadata: statsigMetadata{SDKType: "go-sdk", SDKVersion: "1.1.0"},
metadata: statsigMetadata{SDKType: "go-sdk", SDKVersion: "1.2.0"},
sdkKey: secret,
client: &http.Client{},
options: options,
Expand Down Expand Up @@ -74,18 +74,9 @@ func (transport *transport) postRequestInternal(
}

return retry(retries, time.Duration(backoff), func() (bool, error) {
req, err := http.NewRequest("POST", transport.api+endpoint, bytes.NewBuffer(body))
response, err := transport.doRequest(endpoint, body)
if err != nil {
return false, err
}

req.Header.Add("STATSIG-API-KEY", transport.sdkKey)
req.Header.Set("Content-Type", "application/json")
req.Header.Add("STATSIG-CLIENT-TIME", strconv.FormatInt(time.Now().Unix()*1000, 10))

response, err := transport.client.Do(req)
if err != nil {
return true, err
return response != nil, err
}
defer response.Body.Close()

Expand All @@ -97,6 +88,19 @@ func (transport *transport) postRequestInternal(
})
}

func (transport *transport) doRequest(endpoint string, body []byte) (*http.Response, error) {
req, err := http.NewRequest("POST", transport.api+endpoint, bytes.NewBuffer(body))
if err != nil {
return nil, err
}

req.Header.Add("STATSIG-API-KEY", transport.sdkKey)
req.Header.Set("Content-Type", "application/json")
req.Header.Add("STATSIG-CLIENT-TIME", strconv.FormatInt(time.Now().Unix()*1000, 10))

return transport.client.Do(req)
}

func retry(retries int, backoff time.Duration, fn func() (bool, error)) error {
for {
if retry, err := fn(); retry {
Expand Down

0 comments on commit e21d231

Please sign in to comment.