github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libpages/stathat.go (about) 1 // Copyright 2018 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package libpages 6 7 import ( 8 "strconv" 9 "strings" 10 "time" 11 12 stathat "github.com/stathat/go" 13 "go.uber.org/zap" 14 ) 15 16 type stathatReporter struct { 17 logger *zap.Logger 18 ezKey string 19 reporter stathat.Reporter 20 21 statNameRequests string 22 statNameAuthenticated string 23 statNameCloningShown string 24 statNameInvalidConfig string 25 statPrefixProto string 26 statPrefixStatus string 27 statPrefixTlfType string 28 statPrefixRootType string 29 30 activityStats ActivityStatsEnabler 31 statPrefixActiveHosts string 32 statPrefixActiveTlfs string 33 } 34 35 func (s *stathatReporter) activityStatsReportLoop() { 36 if len(s.activityStats.Durations) == 0 || s.activityStats.Interval == 0 { 37 return 38 } 39 40 durations := make([]NameableDuration, len(s.activityStats.Durations)) 41 copy(durations, s.activityStats.Durations) 42 statNamesHosts := make([]string, 0, len(durations)) 43 statNamesTlfs := make([]string, 0, len(durations)) 44 for _, d := range durations { 45 statNamesHosts = append(statNamesHosts, 46 s.statPrefixActiveHosts+"("+d.String()+")") 47 statNamesTlfs = append(statNamesTlfs, 48 s.statPrefixActiveTlfs+"("+d.String()+")") 49 } 50 reportTicker := time.NewTicker(s.activityStats.Interval) 51 defer reportTicker.Stop() 52 53 for range reportTicker.C { 54 getter, err := s.activityStats.Storer.GetActivesGetter() 55 if err != nil { 56 s.logger.Warn("GetActivesGetter", zap.Error(err)) 57 continue 58 } 59 for i, d := range durations { 60 tlfs, hosts, err := getter.GetActives(d.Duration) 61 if err != nil { 62 s.logger.Warn("GetActives", zap.Error(err)) 63 } 64 if err = s.reporter.PostEZValue(statNamesTlfs[i], s.ezKey, 65 float64(tlfs)); err != nil { 66 s.logger.Warn("PostEZValue", zap.Error(err)) 67 } 68 if err = s.reporter.PostEZValue(statNamesHosts[i], s.ezKey, 69 float64(hosts)); err != nil { 70 s.logger.Warn("PostEZValue", zap.Error(err)) 71 } 72 } 73 } 74 } 75 76 var _ StatsReporter = (*stathatReporter)(nil) 77 78 const stathatReportInterval = time.Second * 10 79 80 // NewStathatReporter create a new StatsReporter that reports stats to stathat. 81 // If enableActivityBasedStats, if set to non-nil, causes the reporter to 82 // generate activity-based stats. Caller should not modify 83 // enableActivityBasedStats passed into this function. 84 func NewStathatReporter(logger *zap.Logger, prefix string, ezKey string, 85 enableActivityBasedStats *ActivityStatsEnabler) StatsReporter { 86 if len(ezKey) == 0 { 87 return &stathatReporter{} 88 } 89 90 enabler := enableActivityBasedStats 91 if enabler == nil { 92 enabler = &ActivityStatsEnabler{ 93 Storer: nullActivityStatsStorer{}, 94 Durations: nil, 95 } 96 } 97 98 prefix = strings.TrimSpace(prefix) + " " 99 reporter := &stathatReporter{ 100 logger: logger, 101 ezKey: ezKey, 102 reporter: stathat.NewBatchReporter( 103 stathat.DefaultReporter, stathatReportInterval), 104 105 statNameRequests: prefix + "requests", 106 statNameAuthenticated: prefix + "authenticated", 107 statNameCloningShown: prefix + "cloningShown", 108 statNameInvalidConfig: prefix + "invalidConfig", 109 statPrefixProto: prefix + "proto:", 110 statPrefixStatus: prefix + "status:", 111 statPrefixTlfType: prefix + "tlfType:", 112 statPrefixRootType: prefix + "rootType:", 113 114 activityStats: *enabler, 115 statPrefixActiveHosts: prefix + "activeHosts:", 116 statPrefixActiveTlfs: prefix + "activeTlfs:", 117 } 118 go reporter.activityStatsReportLoop() 119 return reporter 120 } 121 122 func (s *stathatReporter) postCountOneOrLog(statName string) { 123 if err := s.reporter.PostEZCountOne(statName, s.ezKey); err != nil { 124 s.logger.Warn("PostEZCountOne", zap.Error(err)) 125 } 126 } 127 128 // ReportServedRequest implementes the StatsReporter interface. 129 func (s *stathatReporter) ReportServedRequest(sri *ServedRequestInfo) { 130 s.postCountOneOrLog(s.statNameRequests) 131 s.postCountOneOrLog(s.statPrefixProto + sri.Proto) 132 s.postCountOneOrLog(s.statPrefixStatus + strconv.Itoa(sri.HTTPStatus)) 133 if sri.Authenticated { 134 s.postCountOneOrLog(s.statNameAuthenticated) 135 } 136 if sri.CloningShown { 137 s.postCountOneOrLog(s.statNameCloningShown) 138 } 139 if sri.InvalidConfig { 140 s.postCountOneOrLog(s.statNameInvalidConfig) 141 } 142 s.postCountOneOrLog(s.statPrefixTlfType + sri.TlfType.String()) 143 s.postCountOneOrLog(s.statPrefixRootType + sri.RootType.String()) 144 145 s.activityStats.Storer.RecordActives(sri.TlfID, sri.Host) 146 }