github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/analytics/tilt_analytics.go (about) 1 package analytics 2 3 import ( 4 "time" 5 6 "github.com/tilt-dev/wmclient/pkg/analytics" 7 ) 8 9 const TagVersion = "version" 10 const TagOS = "os" 11 const TagGitRepoHash = "git.origin" 12 const TagSubcommand = "subcommand" 13 14 // An Analytics that allows opting in/out at runtime. 15 type TiltAnalytics struct { 16 opter AnalyticsOpter 17 a analytics.Analytics 18 tiltVersion string 19 20 // We make this a constant pointer to a struct. 21 // That way, the struct returned by WithoutGlobalTags() can 22 // point to the same opt set. 23 opt *optSet 24 } 25 26 type optSet struct { 27 env analytics.Opt 28 user analytics.Opt 29 tiltfile analytics.Opt 30 } 31 32 // An AnalyticsOpter can record a user's choice (opt-in or opt-out) 33 // in re: Tilt recording analytics. 34 type AnalyticsOpter interface { 35 SetUserOpt(opt analytics.Opt) error 36 ReadUserOpt() (analytics.Opt, error) 37 } 38 39 func NewTiltAnalytics(opter AnalyticsOpter, a analytics.Analytics, tiltVersion string) (*TiltAnalytics, error) { 40 userOpt, err := opter.ReadUserOpt() 41 if err != nil { 42 return nil, err 43 } 44 envOpt := analytics.OptDefault 45 if ok, _ := IsAnalyticsDisabledFromEnv(); ok { 46 envOpt = analytics.OptOut 47 } 48 return &TiltAnalytics{ 49 opter: opter, 50 a: a, 51 tiltVersion: tiltVersion, 52 opt: &optSet{ 53 env: envOpt, 54 user: userOpt, 55 tiltfile: analytics.OptDefault, 56 }, 57 }, nil 58 } 59 60 // NOTE: if you need a ctx as well, use testutils.CtxAndAnalyticsForTest so that you get 61 // a ctx with the correct analytics baked in. 62 func NewMemoryTiltAnalyticsForTest(opter AnalyticsOpter) (*analytics.MemoryAnalytics, *TiltAnalytics) { 63 ma := analytics.NewMemoryAnalytics() 64 ta, err := NewTiltAnalytics(opter, ma, "v0.0.0") 65 if err != nil { 66 panic(err) 67 } 68 ta.opt.env = analytics.OptDefault 69 return ma, ta 70 } 71 72 func (ta *TiltAnalytics) GlobalTag(name string) (string, bool) { 73 return ta.a.GlobalTag(name) 74 } 75 func (ta *TiltAnalytics) MachineHash() string { 76 id, _ := ta.GlobalTag(analytics.TagMachine) 77 return id 78 } 79 func (ta *TiltAnalytics) GitRepoHash() string { 80 id, _ := ta.GlobalTag(TagGitRepoHash) 81 return id 82 } 83 func (ta *TiltAnalytics) Count(name string, tags map[string]string, n int) { 84 if ta.EffectiveOpt() != analytics.OptOut { 85 ta.a.Count(name, tags, n) 86 } 87 } 88 89 func (ta *TiltAnalytics) Incr(name string, tags map[string]string) { 90 if ta.EffectiveOpt() != analytics.OptOut { 91 ta.a.Incr(name, tags) 92 } 93 } 94 95 func (ta *TiltAnalytics) Timer(name string, dur time.Duration, tags map[string]string) { 96 if ta.EffectiveOpt() != analytics.OptOut { 97 ta.a.Timer(name, dur, tags) 98 } 99 } 100 101 func (ta *TiltAnalytics) Flush(timeout time.Duration) { 102 ta.a.Flush(timeout) 103 } 104 105 func (ta *TiltAnalytics) UserOpt() analytics.Opt { 106 return ta.opt.user 107 } 108 109 func (ta *TiltAnalytics) TiltfileOpt() analytics.Opt { 110 return ta.opt.tiltfile 111 } 112 113 func (ta *TiltAnalytics) EffectiveOpt() analytics.Opt { 114 if ta.opt.env != analytics.OptDefault { 115 return ta.opt.env 116 } 117 if ta.opt.tiltfile != analytics.OptDefault { 118 return ta.opt.tiltfile 119 } 120 return ta.opt.user 121 } 122 123 func (ta *TiltAnalytics) SetUserOpt(opt analytics.Opt) error { 124 if opt == ta.opt.user { 125 return nil 126 } 127 ta.opt.user = opt 128 return ta.opter.SetUserOpt(opt) 129 } 130 131 func (ta *TiltAnalytics) SetTiltfileOpt(opt analytics.Opt) { 132 ta.opt.tiltfile = opt 133 } 134 135 func (ta *TiltAnalytics) WithoutGlobalTags() analytics.Analytics { 136 return &TiltAnalytics{ 137 opter: ta.opter, 138 a: ta.a.WithoutGlobalTags(), 139 tiltVersion: ta.tiltVersion, 140 opt: ta.opt, 141 } 142 } 143 144 var _ analytics.Analytics = &TiltAnalytics{}