feat: Add anonymized telemetry to report product usage (#2273)

* feat: Add anonymized telemetry to report product usage

This adds a background service to report telemetry to a Coder
server for usage data. There will be realtime event data sent
in the future, but for now usage will report on a CRON.

* Fix flake and requested changes

* Add reporting options for setup

* Add reporting for workspaces

* Add resources as they are reported

* Track API key usage

* Ensure telemetry is tracked prior to exit
This commit is contained in:
Kyle Carberry
2022-06-17 00:26:40 -05:00
committed by GitHub
parent af8a1e3fea
commit 4cce969018
33 changed files with 1674 additions and 95 deletions
+48
View File
@@ -29,6 +29,7 @@ import (
"github.com/coreos/go-systemd/daemon"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
"github.com/google/go-github/v43/github"
"github.com/google/uuid"
"github.com/pion/turn/v2"
"github.com/pion/webrtc/v3"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -53,6 +54,7 @@ import (
"github.com/coder/coder/coderd/database/databasefake"
"github.com/coder/coder/coderd/devtunnel"
"github.com/coder/coder/coderd/gitsshkey"
"github.com/coder/coder/coderd/telemetry"
"github.com/coder/coder/coderd/tracing"
"github.com/coder/coder/coderd/turnconn"
"github.com/coder/coder/codersdk"
@@ -81,6 +83,7 @@ func server() *cobra.Command {
oauth2GithubClientSecret string
oauth2GithubAllowedOrganizations []string
oauth2GithubAllowSignups bool
telemetryURL string
tlsCertFile string
tlsClientCAFile string
tlsClientAuth string
@@ -134,6 +137,7 @@ func server() *cobra.Command {
}
config := createConfig(cmd)
builtinPostgres := false
// Only use built-in if PostgreSQL URL isn't specified!
if !inMemoryDatabase && postgresURL == "" {
var closeFunc func() error
@@ -142,6 +146,7 @@ func server() *cobra.Command {
if err != nil {
return err
}
builtinPostgres = true
defer func() {
// Gracefully shut PostgreSQL down!
_ = closeFunc()
@@ -253,6 +258,7 @@ func server() *cobra.Command {
SSHKeygenAlgorithm: sshKeygenAlgorithm,
TURNServer: turnServer,
TracerProvider: tracerProvider,
Telemetry: telemetry.NewNoop(),
}
if oauth2GithubClientSecret != "" {
@@ -285,6 +291,44 @@ func server() *cobra.Command {
}
}
deploymentID, err := options.Database.GetDeploymentID(cmd.Context())
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
return xerrors.Errorf("get deployment id: %w", err)
}
if deploymentID == "" {
deploymentID = uuid.NewString()
err = options.Database.InsertDeploymentID(cmd.Context(), deploymentID)
if err != nil {
return xerrors.Errorf("set deployment id: %w", err)
}
}
// Parse the raw telemetry URL!
telemetryURL, err := url.Parse(telemetryURL)
if err != nil {
return xerrors.Errorf("parse telemetry url: %w", err)
}
if !inMemoryDatabase || cmd.Flags().Changed("telemetry-url") {
options.Telemetry, err = telemetry.New(telemetry.Options{
BuiltinPostgres: builtinPostgres,
DeploymentID: deploymentID,
Database: options.Database,
Logger: logger.Named("telemetry"),
URL: telemetryURL,
GitHubOAuth: oauth2GithubClientID != "",
Prometheus: promEnabled,
STUN: len(stunServers) != 0,
Tunnel: tunnel,
})
if err != nil {
return xerrors.Errorf("create telemetry reporter: %w", err)
}
defer options.Telemetry.Close()
}
coderAPI := coderd.New(options)
client := codersdk.New(localURL)
if tlsEnable {
@@ -438,6 +482,8 @@ func server() *cobra.Command {
<-devTunnelErrChan
}
// Ensures a last report can be sent before exit!
options.Telemetry.Close()
cmd.Println("Waiting for WebSocket connections to close...")
shutdownConns()
coderAPI.Close()
@@ -485,6 +531,8 @@ func server() *cobra.Command {
"Specifies organizations the user must be a member of to authenticate with GitHub.")
cliflag.BoolVarP(root.Flags(), &oauth2GithubAllowSignups, "oauth2-github-allow-signups", "", "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS", false,
"Specifies whether new users can sign up with GitHub.")
cliflag.StringVarP(root.Flags(), &telemetryURL, "telemetry-url", "", "CODER_TELEMETRY_URL", "https://telemetry.coder.com", "Specifies a URL to send telemetry to.")
_ = root.Flags().MarkHidden("telemetry-url")
cliflag.BoolVarP(root.Flags(), &tlsEnable, "tls-enable", "", "CODER_TLS_ENABLE", false, "Specifies if TLS will be enabled")
cliflag.StringVarP(root.Flags(), &tlsCertFile, "tls-cert-file", "", "CODER_TLS_CERT_FILE", "",
"Specifies the path to the certificate for TLS. It requires a PEM-encoded file. "+