2021-03-23 15:52:34 +00:00
|
|
|
// Copyright (C) 2021 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package analytics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"go.uber.org/zap"
|
|
|
|
segment "gopkg.in/segmentio/analytics-go.v3"
|
|
|
|
|
|
|
|
"storj.io/common/uuid"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-03-31 19:34:44 +01:00
|
|
|
eventAccountCreated = "Account Created"
|
|
|
|
gatewayCredentialsCreated = "Credentials Created"
|
2021-03-23 15:52:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Config is a configuration struct for analytics Service.
|
|
|
|
type Config struct {
|
|
|
|
SegmentWriteKey string `help:"segment write key" default:""`
|
2021-03-27 22:43:22 +00:00
|
|
|
Enabled bool `help:"enable analytics reporting" default:"false"`
|
2021-03-23 15:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Service for sending analytics.
|
|
|
|
//
|
|
|
|
// architecture: Service
|
|
|
|
type Service struct {
|
|
|
|
log *zap.Logger
|
|
|
|
config Config
|
|
|
|
satelliteName string
|
2021-03-31 19:34:44 +01:00
|
|
|
clientEvents map[string]bool
|
2021-03-23 15:52:34 +00:00
|
|
|
|
|
|
|
segment segment.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewService creates new service for creating sending analytics.
|
|
|
|
func NewService(log *zap.Logger, config Config, satelliteName string) *Service {
|
2021-03-27 22:43:22 +00:00
|
|
|
service := &Service{
|
2021-03-23 15:52:34 +00:00
|
|
|
log: log,
|
|
|
|
config: config,
|
|
|
|
satelliteName: satelliteName,
|
2021-03-31 19:34:44 +01:00
|
|
|
clientEvents: make(map[string]bool),
|
2021-03-23 15:52:34 +00:00
|
|
|
}
|
2021-03-27 22:43:22 +00:00
|
|
|
if config.Enabled {
|
|
|
|
service.segment = segment.New(config.SegmentWriteKey)
|
|
|
|
}
|
2021-03-31 19:34:44 +01:00
|
|
|
for _, name := range []string{gatewayCredentialsCreated} {
|
|
|
|
service.clientEvents[name] = true
|
|
|
|
}
|
2021-03-27 22:43:22 +00:00
|
|
|
return service
|
2021-03-23 15:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes the Segment client.
|
|
|
|
func (service *Service) Close() error {
|
2021-03-27 22:43:22 +00:00
|
|
|
if !service.config.Enabled {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-23 15:52:34 +00:00
|
|
|
return service.segment.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
// UserType is a type for distinguishing personal vs. professional users.
|
|
|
|
type UserType string
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Professional defines a "professional" user type.
|
|
|
|
Professional UserType = "Professional"
|
|
|
|
// Personal defines a "personal" user type.
|
|
|
|
Personal UserType = "Personal"
|
|
|
|
)
|
|
|
|
|
|
|
|
// TrackCreateUserFields contains input data for tracking a create user event.
|
|
|
|
type TrackCreateUserFields struct {
|
|
|
|
ID uuid.UUID
|
|
|
|
FullName string
|
|
|
|
Email string
|
|
|
|
Type UserType
|
|
|
|
EmployeeCount string
|
|
|
|
CompanyName string
|
|
|
|
JobTitle string
|
|
|
|
}
|
|
|
|
|
2021-03-27 22:43:22 +00:00
|
|
|
func (service *Service) enqueueMessage(message segment.Message) {
|
|
|
|
if !service.config.Enabled {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err := service.segment.Enqueue(message)
|
|
|
|
if err != nil {
|
|
|
|
service.log.Error("Error enqueueing message", zap.Error(err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-23 15:52:34 +00:00
|
|
|
// TrackCreateUser sends an "Account Created" event to Segment.
|
|
|
|
func (service *Service) TrackCreateUser(fields TrackCreateUserFields) {
|
|
|
|
traits := segment.NewTraits()
|
|
|
|
traits.SetName(fields.FullName)
|
|
|
|
traits.SetEmail(fields.Email)
|
|
|
|
|
2021-03-27 22:43:22 +00:00
|
|
|
service.enqueueMessage(segment.Identify{
|
2021-03-23 15:52:34 +00:00
|
|
|
UserId: fields.ID.String(),
|
|
|
|
Traits: traits,
|
|
|
|
})
|
|
|
|
|
|
|
|
props := segment.NewProperties()
|
|
|
|
props.Set("email", fields.Email)
|
|
|
|
props.Set("name", fields.FullName)
|
|
|
|
props.Set("satellite_selected", service.satelliteName)
|
|
|
|
props.Set("account_type", fields.Type)
|
|
|
|
|
|
|
|
if fields.Type == Professional {
|
|
|
|
props.Set("company_size", fields.EmployeeCount)
|
|
|
|
props.Set("company_name", fields.CompanyName)
|
|
|
|
props.Set("job_title", fields.JobTitle)
|
|
|
|
}
|
|
|
|
|
2021-03-27 22:43:22 +00:00
|
|
|
service.enqueueMessage(segment.Track{
|
2021-03-23 15:52:34 +00:00
|
|
|
UserId: fields.ID.String(),
|
|
|
|
Event: eventAccountCreated,
|
|
|
|
Properties: props,
|
|
|
|
})
|
|
|
|
}
|
2021-03-31 19:34:44 +01:00
|
|
|
|
|
|
|
// TrackEvent sends an arbitrary event associated with user ID to Segment.
|
|
|
|
// It is used for tracking occurrences of client-side events.
|
|
|
|
func (service *Service) TrackEvent(eventName string, userID uuid.UUID) {
|
|
|
|
// do not track if the event name is an invalid client-side event
|
|
|
|
if !service.clientEvents[eventName] {
|
|
|
|
service.log.Error("Invalid client-triggered event", zap.String("eventName", eventName))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
service.enqueueMessage(segment.Track{
|
|
|
|
UserId: userID.String(),
|
|
|
|
Event: eventName,
|
|
|
|
})
|
|
|
|
}
|