// Copyright (c) 2020 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License.AGPL.txt in the project root for license information. package observer import ( "time" "github.com/gitpod-io/gitpod/loadgen/pkg/loadgen" "github.com/gitpod-io/gitpod/ws-manager/api" ) const ( defaultCapacity = 200 ) // Stats is stats across a whole session type Stats struct { Total int `json:"total"` Failed int `json:"failed"` Running int `json:"running"` Samples []StatsSample `json:"samples"` } // StatsSample is a single workspace sample type StatsSample struct { InstanceID string Start, Running time.Time Phase api.WorkspacePhase Failed bool StartDuration time.Duration } // NewStatsObserver produces a stats collecting observer func NewStatsObserver(cb func(*Stats)) chan<- *loadgen.SessionEvent { res := make(chan *loadgen.SessionEvent, defaultCapacity) publishStats := func(status map[string]*StatsSample) { var s Stats s.Samples = make([]StatsSample, 0, len(status)) for _, ws := range status { s.Total++ if ws.Failed { s.Failed++ } if ws.Phase == api.WorkspacePhase_RUNNING { s.Running++ } s.Samples = append(s.Samples, *ws) } cb(&s) } go func() { status := make(map[string]*StatsSample) for evt := range res { switch evt.Kind { case loadgen.SessionStart: status = make(map[string]*StatsSample) case loadgen.SessionWorkspaceStart: status[evt.WorkspaceStart.Spec.Id] = &StatsSample{ InstanceID: evt.WorkspaceStart.Spec.Id, Start: evt.WorkspaceStart.Time, Failed: false, Phase: api.WorkspacePhase_UNKNOWN, StartDuration: evt.WorkspaceStart.CallDuration, } case loadgen.SessionWorkspaceUpdate: up := evt.WorkspaceUpdate.Update ws, ok := status[up.InstanceID] if !ok { continue } ws.Phase = up.Phase ws.Failed = up.Failed ws.Running = evt.WorkspaceUpdate.Time publishStats(status) case loadgen.SessionDone: publishStats(status) } } }() return res }