diff --git a/go.mod b/go.mod index 676a7e4db..e6c0528d2 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/getlantern/systray v1.2.1 github.com/gliderlabs/ssh v0.3.4 github.com/google/nftables v0.0.0-20220808154552-2eca00135732 + github.com/hashicorp/go-version v1.6.0 github.com/libp2p/go-netroute v0.2.0 github.com/magiconair/properties v1.8.5 github.com/miekg/dns v1.1.41 diff --git a/go.sum b/go.sum index 43a64c2a8..3a4338ff7 100644 --- a/go.sum +++ b/go.sum @@ -347,6 +347,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= diff --git a/management/server/metrics/selfhosted.go b/management/server/metrics/selfhosted.go index 8302f099d..c658a4215 100644 --- a/management/server/metrics/selfhosted.go +++ b/management/server/metrics/selfhosted.go @@ -5,11 +5,14 @@ import ( "context" "encoding/json" "fmt" + "github.com/hashicorp/go-version" "github.com/netbirdio/netbird/client/system" "github.com/netbirdio/netbird/management/server" log "github.com/sirupsen/logrus" "io" "net/http" + "regexp" + "sort" "strings" "time" ) @@ -85,6 +88,7 @@ func (w *Worker) Run() { if err != nil { log.Error(err) } + w.lastRun = time.Now() } } } @@ -161,11 +165,15 @@ func (w *Worker) generateProperties() properties { groups int routes int nameservers int + uiClient int version string + peerActiveVersions []string + osUIClients map[string]int ) start := time.Now() metricsProperties := make(properties) osPeers = make(map[string]int) + osUIClients = make(map[string]int) uptime = time.Since(w.startupTime).Seconds() connections := w.connManager.GetAllConnectedPeers() version = system.NetbirdVersion() @@ -184,7 +192,7 @@ func (w *Worker) generateProperties() properties { for _, peer := range account.Peers { peers++ - if peer.SetupKey != "" { + if peer.SetupKey == "" { userPeers++ } @@ -192,16 +200,25 @@ func (w *Worker) generateProperties() properties { osCount := osPeers[osKey] osPeers[osKey] = osCount + 1 + if peer.Meta.UIVersion != "" { + uiClient++ + uiOSKey := strings.ToLower(fmt.Sprintf("ui_client_os_%s", peer.Meta.GoOS)) + osUICount := osUIClients[uiOSKey] + osUIClients[uiOSKey] = osUICount + 1 + } + _, connected := connections[peer.Key] if connected || peer.Status.LastSeen.After(w.lastRun) { activePeersLastDay++ osActiveKey := osKey + "_active" osActiveCount := osPeers[osActiveKey] osPeers[osActiveKey] = osActiveCount + 1 + peerActiveVersions = append(peerActiveVersions, peer.Meta.WtVersion) } } } + minActivePeerVersion, maxActivePeerVersion := getMinMaxVersion(peerActiveVersions) metricsProperties["uptime"] = uptime metricsProperties["accounts"] = accounts metricsProperties["users"] = users @@ -214,11 +231,17 @@ func (w *Worker) generateProperties() properties { metricsProperties["routes"] = routes metricsProperties["nameservers"] = nameservers metricsProperties["version"] = version - + metricsProperties["min_active_peer_version"] = minActivePeerVersion + metricsProperties["max_active_peer_version"] = maxActivePeerVersion + metricsProperties["ui_clients"] = uiClient for os, count := range osPeers { metricsProperties[os] = count } + for os, count := range osUIClients { + metricsProperties[os] = count + } + metricsProperties["metric_generation_time"] = time.Since(start).Milliseconds() return metricsProperties @@ -284,3 +307,31 @@ func createPostRequest(ctx context.Context, endpoint string, payloadStr string) return req, nil } + +func getMinMaxVersion(inputList []string) (string, string) { + reg, err := regexp.Compile(version.SemverRegexpRaw) + if err != nil { + return "", "" + } + + versions := make([]*version.Version, 0) + + for _, raw := range inputList { + if raw != "" && reg.MatchString(raw) { + v, err := version.NewVersion(raw) + if err == nil { + versions = append(versions, v) + } + } + } + switch len(versions) { + case 0: + return "", "" + case 1: + v := versions[0].String() + return v, v + default: + sort.Sort(version.Collection(versions)) + return versions[0].String(), versions[len(versions)-1].String() + } +}