Skip to content

Commit

Permalink
logEvent Error Logging (#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
kat-statsig authored May 15, 2024
1 parent eb645d9 commit 654e8f1
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 35 deletions.
8 changes: 2 additions & 6 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func NewClientWithOptions(sdkKey string, options *Options) *Client {
panic(err)
}
transport := newTransport(sdkKey, options)
logger := newLogger(transport, options, diagnostics)
logger := newLogger(transport, options, diagnostics, errorBoundary)
evaluator := newEvaluator(transport, errorBoundary, options, diagnostics, sdkKey)
diagnostics.initialize().overall().end().success(true).mark()
return &Client{
Expand Down Expand Up @@ -233,11 +233,7 @@ func (c *Client) LogImmediate(events []Event) (*http.Response, error) {
event.User = normalizeUser(event.User, *c.options)
events_processed = append(events_processed, event)
}
input := logEventInput{
Events: events_processed,
StatsigMetadata: c.transport.metadata,
}
return c.transport.post("/log_event", input, nil, RequestOptions{})
return c.transport.log_event(events_processed, nil, RequestOptions{})
}

func (c *Client) GetClientInitializeResponse(user User, clientKey string, includeLocalOverrides bool) ClientInitializeResponse {
Expand Down
29 changes: 24 additions & 5 deletions error_boundary.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,18 @@ type errorBoundary struct {
}

type logExceptionRequestBody struct {
Exception string `json:"exception"`
Info string `json:"info"`
StatsigMetadata statsigMetadata `json:"statsigMetadata"`
Exception string `json:"exception"`
Info string `json:"info"`
StatsigMetadata statsigMetadata `json:"statsigMetadata"`
Extra *map[string]interface{} `json:"extra"`
Tag string `json:"tag"`
}

type logExceptionOptions struct {
Tag string
Extra *map[string]interface{}
BypassDedupe bool
logToOutput bool
}

type logExceptionResponse struct {
Expand Down Expand Up @@ -125,7 +134,7 @@ func (e *errorBoundary) ebRecover(recoverCallback func()) {
}
}

func (e *errorBoundary) logException(exception error) {
func (e *errorBoundary) logExceptionWithOptions(exception error, options logExceptionOptions) {
if e.options.StatsigLoggerOptions.DisableAllLogging || e.options.LocalMode {
return
}
Expand All @@ -135,7 +144,11 @@ func (e *errorBoundary) logException(exception error) {
} else {
exceptionString = exception.Error()
}
if e.checkSeen(exceptionString) {

if options.logToOutput {
Logger().LogError(exception)
}
if !options.BypassDedupe && e.checkSeen(exceptionString) {
return
}
stack := make([]byte, 1024)
Expand All @@ -145,6 +158,8 @@ func (e *errorBoundary) logException(exception error) {
Exception: exceptionString,
Info: string(stack),
StatsigMetadata: metadata,
Extra: options.Extra,
Tag: options.Tag,
}
bodyString, err := json.Marshal(body)
if err != nil {
Expand All @@ -164,3 +179,7 @@ func (e *errorBoundary) logException(exception error) {

_, _ = e.client.Do(req)
}

func (e *errorBoundary) logException(exception error) {
e.logExceptionWithOptions(exception, logExceptionOptions{})
}
52 changes: 31 additions & 21 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@ type logContext struct {
}

type logger struct {
events []interface{}
transport *transport
tick *time.Ticker
mu sync.Mutex
maxEvents int
disabled bool
diagnostics *diagnostics
options *Options
events []interface{}
transport *transport
tick *time.Ticker
mu sync.Mutex
maxEvents int
disabled bool
diagnostics *diagnostics
options *Options
errorBoundary *errorBoundary
}

func newLogger(transport *transport, options *Options, diagnostics *diagnostics) *logger {
func newLogger(transport *transport, options *Options, diagnostics *diagnostics, errorBoundary *errorBoundary) *logger {
loggingInterval := time.Minute
maxEvents := 1000
if options.LoggingInterval > 0 {
Expand All @@ -65,13 +66,14 @@ func newLogger(transport *transport, options *Options, diagnostics *diagnostics)
}
disabled := options.StatsigLoggerOptions.DisableAllLogging
log := &logger{
events: make([]interface{}, 0),
transport: transport,
tick: time.NewTicker(loggingInterval),
maxEvents: maxEvents,
disabled: disabled,
diagnostics: diagnostics,
options: options,
events: make([]interface{}, 0),
transport: transport,
tick: time.NewTicker(loggingInterval),
maxEvents: maxEvents,
disabled: disabled,
diagnostics: diagnostics,
options: options,
errorBoundary: errorBoundary,
}

go log.backgroundFlush()
Expand Down Expand Up @@ -244,12 +246,20 @@ func (l *logger) flushInternal(closing bool) {
}

func (l *logger) sendEvents(events []interface{}) {
input := &logEventInput{
Events: events,
StatsigMetadata: l.transport.metadata,
}
var res logEventResponse
_, _ = l.transport.post("/log_event", input, &res, RequestOptions{retries: maxRetries})
_, err := l.transport.log_event(events, &res, RequestOptions{retries: maxRetries})
if err != nil {
message := fmt.Sprintf("Failed to log %d events afrer %d retries, dropping the request", len(events), maxRetries)
extra := map[string]interface{}{
"eventCount": len(events),
}
options := logExceptionOptions{
Tag: "statsig::log_event_failed",
Extra: &extra,
BypassDedupe: true,
}
l.errorBoundary.logExceptionWithOptions(toError(message), options)
}
}

func (l *logger) logDiagnosticsEvents(d *diagnostics) {
Expand Down
3 changes: 2 additions & 1 deletion logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ func TestLog(t *testing.T) {
API: testServer.URL,
}
transport := newTransport("secret", opt)
logger := newLogger(transport, opt, nil)
errorBoundary := newErrorBoundary("secret", opt, nil)
logger := newLogger(transport, opt, nil, errorBoundary)

user := User{
UserID: "123",
Expand Down
22 changes: 20 additions & 2 deletions transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func newTransport(secret string, options *Options) *transport {
type RequestOptions struct {
retries int
backoff time.Duration
header map[string]string
}

func (opts *RequestOptions) fill_defaults() {
Expand Down Expand Up @@ -89,6 +90,19 @@ func (transport *transport) get_id_list(url string, headers map[string]string) (
return transport.client.Do(req)
}

func (transport *transport) log_event(event []interface{}, responseBody interface{}, options RequestOptions) (*http.Response, error) {
input := logEventInput{
Events: event,
StatsigMetadata: transport.metadata,
}
if options.header == nil {
options.header = make(map[string]string)
}
options.header["statsig-event-count"] = strconv.Itoa(len(event))
return transport.post("/log_event", input, responseBody, options)

}

func (transport *transport) post(endpoint string, body interface{}, responseBody interface{}, options RequestOptions) (*http.Response, error) {
return transport.doRequest("POST", endpoint, body, responseBody, options)
}
Expand All @@ -97,7 +111,7 @@ func (transport *transport) get(endpoint string, responseBody interface{}, optio
return transport.doRequest("GET", endpoint, nil, responseBody, options)
}

func (transport *transport) buildRequest(method, endpoint string, body interface{}) (*http.Request, error) {
func (transport *transport) buildRequest(method, endpoint string, body interface{}, header map[string]string) (*http.Request, error) {
if transport.options.LocalMode {
return nil, nil
}
Expand Down Expand Up @@ -126,6 +140,10 @@ func (transport *transport) buildRequest(method, endpoint string, body interface
req.Header.Add("STATSIG-SDK-TYPE", transport.metadata.SDKType)
req.Header.Add("STATSIG-SDK-VERSION", transport.metadata.SDKVersion)
req.Header.Add("STATSIG-SDK-LANGUAGE-VERSION", transport.metadata.LanguageVersion)
for k, v := range header {
req.Header.Add(k, v)

}
return req, nil
}

Expand All @@ -144,7 +162,7 @@ func (transport *transport) doRequest(
out interface{},
options RequestOptions,
) (*http.Response, error) {
request, err := transport.buildRequest(method, endpoint, in)
request, err := transport.buildRequest(method, endpoint, in, options.header)
if request == nil || err != nil {
return nil, err
}
Expand Down

0 comments on commit 654e8f1

Please sign in to comment.