satellite/metainfo: collect versions of user tools
We want to know usage statistics for our main tools like uplink-cli or rclone. Initially we will collect only usage stats without relation to specific process e.g. download or upload. Change-Id: I203b1a6c07ae014e710368f77163f13fdf10763c
This commit is contained in:
parent
e0b3c7152b
commit
eb0d08d59b
2
go.mod
2
go.mod
@ -5,6 +5,7 @@ go 1.17
|
||||
require (
|
||||
github.com/alessio/shellescape v1.2.2
|
||||
github.com/alicebob/miniredis/v2 v2.13.3
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
|
||||
github.com/calebcase/tmpfile v1.0.3
|
||||
github.com/cheggaaa/pb/v3 v3.0.5
|
||||
@ -60,7 +61,6 @@ require (
|
||||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/apache/thrift v0.12.0 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
|
@ -138,7 +138,7 @@ func NewEndpoint(log *zap.Logger, buckets *buckets.Service, metabaseDB *metabase
|
||||
revocations: revocations,
|
||||
defaultRS: defaultRSScheme,
|
||||
config: config,
|
||||
versionCollector: newVersionCollector(),
|
||||
versionCollector: newVersionCollector(log),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,13 @@
|
||||
package metainfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/spacemonkeygo/monkit/v3"
|
||||
"github.com/zeebo/errs"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"storj.io/common/useragent"
|
||||
)
|
||||
@ -16,53 +18,66 @@ import (
|
||||
const uplinkProduct = "uplink"
|
||||
|
||||
type versionOccurrence struct {
|
||||
Product string
|
||||
Version string
|
||||
Method string
|
||||
}
|
||||
|
||||
type versionCollector struct {
|
||||
mu sync.Mutex
|
||||
versions map[versionOccurrence]*monkit.Meter
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
func newVersionCollector() *versionCollector {
|
||||
func newVersionCollector(log *zap.Logger) *versionCollector {
|
||||
return &versionCollector{
|
||||
versions: make(map[versionOccurrence]*monkit.Meter),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (vc *versionCollector) collect(useragentRaw []byte, method string) error {
|
||||
var meter *monkit.Meter
|
||||
if len(useragentRaw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
version := "unknown"
|
||||
if len(useragentRaw) != 0 {
|
||||
entries, err := useragent.ParseEntries(useragentRaw)
|
||||
if err != nil {
|
||||
return errs.New("invalid user agent %q: %v", string(useragentRaw), err)
|
||||
}
|
||||
entries, err := useragent.ParseEntries(useragentRaw)
|
||||
if err != nil {
|
||||
return errs.New("invalid user agent %q: %v", string(useragentRaw), err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if strings.EqualFold(entry.Product, uplinkProduct) {
|
||||
version = entry.Version
|
||||
break
|
||||
for _, entry := range entries {
|
||||
if strings.EqualFold(entry.Product, uplinkProduct) {
|
||||
vo := versionOccurrence{
|
||||
Product: entry.Product,
|
||||
Version: entry.Version,
|
||||
Method: method,
|
||||
}
|
||||
|
||||
vc.sendUplinkMetric(vo)
|
||||
} else {
|
||||
// for other user agents monitor only product
|
||||
product := entry.Product
|
||||
if product == "" {
|
||||
product = "unknown"
|
||||
}
|
||||
mon.Meter("user_agents", monkit.NewSeriesTag("user_agent", product)).Mark(1)
|
||||
}
|
||||
}
|
||||
|
||||
vo := versionOccurrence{
|
||||
Version: version,
|
||||
Method: method,
|
||||
}
|
||||
|
||||
vc.mu.Lock()
|
||||
meter, ok := vc.versions[vo]
|
||||
if !ok {
|
||||
meter = monkit.NewMeter(monkit.NewSeriesKey("uplink_versions").WithTag("version", version).WithTag("method", method))
|
||||
mon.Chain(meter)
|
||||
vc.versions[vo] = meter
|
||||
}
|
||||
vc.mu.Unlock()
|
||||
|
||||
meter.Mark(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vc *versionCollector) sendUplinkMetric(vo versionOccurrence) {
|
||||
if vo.Version == "" {
|
||||
vo.Version = "unknown"
|
||||
} else {
|
||||
// use only major and minor to avoid using too many resources and
|
||||
// minimize risk of abusing by sending lots of different versions
|
||||
semVer, err := semver.ParseTolerant(vo.Version)
|
||||
if err != nil {
|
||||
vc.log.Warn("invalid uplink library user agent version", zap.String("version", vo.Version), zap.Error(err))
|
||||
return
|
||||
}
|
||||
vo.Version = fmt.Sprintf("v%d.%d", semVer.Major, semVer.Minor)
|
||||
}
|
||||
|
||||
mon.Meter("uplink_versions", monkit.NewSeriesTag("version", vo.Version), monkit.NewSeriesTag("method", vo.Method)).Mark(1)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user