feat(coderd): add enabled experiments to telemetry (#12656)

This commit is contained in:
Danny Kopping 2024-03-19 11:05:29 +02:00 committed by GitHub
parent f0f9569d51
commit ab95ae827d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 7 deletions

View File

@ -11,9 +11,10 @@ import (
"testing"
"time"
"github.com/coder/coder/v2/testutil"
"github.com/stretchr/testify/assert"
"github.com/coder/coder/v2/testutil"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/codersdk"

View File

@ -819,6 +819,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
Prometheus: vals.Prometheus.Enable.Value(),
STUN: len(vals.DERP.Server.STUNAddresses) != 0,
Tunnel: tunnel != nil,
Experiments: vals.Experiments.Value(),
ParseLicenseJWT: func(lic *telemetry.License) error {
// This will be nil when running in AGPL-only mode.
if options.ParseLicenseClaims == nil {

View File

@ -54,6 +54,7 @@ type Options struct {
SnapshotFrequency time.Duration
Tunnel bool
ParseLicenseJWT func(lic *License) error
Experiments []string
}
// New constructs a reporter for telemetry data.
@ -480,6 +481,10 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
}
return nil
})
eg.Go(func() error {
snapshot.Experiments = ConvertExperiments(r.options.Experiments)
return nil
})
err := eg.Wait()
if err != nil {
@ -741,6 +746,16 @@ func ConvertExternalProvisioner(id uuid.UUID, tags map[string]string, provisione
}
}
func ConvertExperiments(experiments []string) []Experiment {
var out []Experiment
for _, exp := range experiments {
out = append(out, Experiment{Name: exp})
}
return out
}
// Snapshot represents a point-in-time anonymized database dump.
// Data is aggregated by latest on the server-side, so partial data
// can be sent without issue.
@ -763,6 +778,7 @@ type Snapshot struct {
WorkspaceResourceMetadata []WorkspaceResourceMetadata `json:"workspace_resource_metadata"`
WorkspaceResources []WorkspaceResource `json:"workspace_resources"`
Workspaces []Workspace `json:"workspaces"`
Experiments []Experiment `json:"experiments"`
}
// Deployment contains information about the host running Coder.
@ -971,6 +987,10 @@ type ExternalProvisioner struct {
ShutdownAt *time.Time `json:"shutdown_at"`
}
type Experiment struct {
Name string `json:"name"`
}
type noopReporter struct{}
func (*noopReporter) Report(_ *Snapshot) {}

View File

@ -85,7 +85,7 @@ func TestTelemetry(t *testing.T) {
assert.NoError(t, err)
_, _ = dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{})
_, snapshot := collectSnapshot(t, db)
_, snapshot := collectSnapshot(t, db, nil)
require.Len(t, snapshot.ProvisionerJobs, 1)
require.Len(t, snapshot.Licenses, 1)
require.Len(t, snapshot.Templates, 1)
@ -110,21 +110,32 @@ func TestTelemetry(t *testing.T) {
_ = dbgen.User(t, db, database.User{
Email: "kyle@coder.com",
})
_, snapshot := collectSnapshot(t, db)
_, snapshot := collectSnapshot(t, db, nil)
require.Len(t, snapshot.Users, 1)
require.Equal(t, snapshot.Users[0].EmailHashed, "bb44bf07cf9a2db0554bba63a03d822c927deae77df101874496df5a6a3e896d@coder.com")
})
t.Run("Experiments", func(t *testing.T) {
t.Parallel()
const expName = "my-experiment"
exps := []string{expName}
_, snapshot := collectSnapshot(t, dbmem.New(), func(opts telemetry.Options) telemetry.Options {
opts.Experiments = exps
return opts
})
require.Equal(t, []telemetry.Experiment{{Name: expName}}, snapshot.Experiments)
})
}
// nolint:paralleltest
func TestTelemetryInstallSource(t *testing.T) {
t.Setenv("CODER_TELEMETRY_INSTALL_SOURCE", "aws_marketplace")
db := dbmem.New()
deployment, _ := collectSnapshot(t, db)
deployment, _ := collectSnapshot(t, db, nil)
require.Equal(t, "aws_marketplace", deployment.InstallSource)
}
func collectSnapshot(t *testing.T, db database.Store) (*telemetry.Deployment, *telemetry.Snapshot) {
func collectSnapshot(t *testing.T, db database.Store, addOptionsFn func(opts telemetry.Options) telemetry.Options) (*telemetry.Deployment, *telemetry.Snapshot) {
t.Helper()
deployment := make(chan *telemetry.Deployment, 64)
snapshot := make(chan *telemetry.Snapshot, 64)
@ -149,12 +160,17 @@ func collectSnapshot(t *testing.T, db database.Store) (*telemetry.Deployment, *t
t.Cleanup(server.Close)
serverURL, err := url.Parse(server.URL)
require.NoError(t, err)
reporter, err := telemetry.New(telemetry.Options{
options := telemetry.Options{
Database: db,
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
URL: serverURL,
DeploymentID: uuid.NewString(),
})
}
if addOptionsFn != nil {
options = addOptionsFn(options)
}
reporter, err := telemetry.New(options)
require.NoError(t, err)
t.Cleanup(reporter.Close)
return <-deployment, <-snapshot