Skip to content

Commit

Permalink
πŸ” implement telemetry
Browse files Browse the repository at this point in the history
πŸ” implement telemetry
  • Loading branch information
petar-cvit authored Mar 23, 2024
2 parents 259f725 + 6c4b523 commit 8db48a8
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 14 deletions.
2 changes: 2 additions & 0 deletions cyclops-ctrl/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DISABLE_TELEMETRY=true
PORT=8888
27 changes: 23 additions & 4 deletions cyclops-ctrl/cmd/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package main
import (
"flag"
"fmt"
"github.com/cyclops-ui/cycops-ctrl/internal/auth"
"github.com/cyclops-ui/cycops-ctrl/internal/template"
"github.com/cyclops-ui/cycops-ctrl/internal/template/cache"
"os"
"strconv"

_ "github.com/joho/godotenv/autoload"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
Expand All @@ -17,10 +16,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"

cyclopsv1alpha1 "github.com/cyclops-ui/cycops-ctrl/api/v1alpha1"
"github.com/cyclops-ui/cycops-ctrl/internal/auth"
"github.com/cyclops-ui/cycops-ctrl/internal/cluster/k8sclient"
"github.com/cyclops-ui/cycops-ctrl/internal/handler"
"github.com/cyclops-ui/cycops-ctrl/internal/modulecontroller"
"github.com/cyclops-ui/cycops-ctrl/internal/storage/templates"
"github.com/cyclops-ui/cycops-ctrl/internal/telemetry"
"github.com/cyclops-ui/cycops-ctrl/internal/template"
"github.com/cyclops-ui/cycops-ctrl/internal/template/cache"
)

var (
Expand Down Expand Up @@ -54,6 +57,9 @@ func main() {

setupLog.Info("starting handler")

telemetryClient, _ := telemetry.NewClient(getEnvBool("DISABLE_TELEMETRY"))
telemetryClient.InstanceStart()

k8sClient, err := k8sclient.New()
if err != nil {
fmt.Println("error bootstrapping Kubernetes client", err)
Expand All @@ -71,7 +77,7 @@ func main() {
cache.NewInMemoryTemplatesCache(),
)

handler, err := handler.New(templatesStorage, templatesRepo, k8sClient)
handler, err := handler.New(templatesStorage, templatesRepo, k8sClient, telemetryClient)
if err != nil {
panic(err)
}
Expand All @@ -97,6 +103,7 @@ func main() {
templatesRepo,
templatesStorage,
k8sClient,
telemetryClient,
)).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Module")
os.Exit(1)
Expand All @@ -118,3 +125,15 @@ func main() {
os.Exit(1)
}
}

func getEnvBool(key string) bool {
value := os.Getenv(key)
if value == "" {
return false
}
b, err := strconv.ParseBool(value)
if err != nil {
return false
}
return b
}
4 changes: 3 additions & 1 deletion cyclops-ctrl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ require (
github.com/go-git/go-git/v5 v5.11.0
github.com/go-logr/logr v1.3.0
github.com/go-redis/redis/v8 v8.11.5
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/json-iterator/go v1.1.12
github.com/onsi/ginkgo/v2 v2.13.0
github.com/onsi/gomega v1.29.0
github.com/pkg/errors v0.9.1
github.com/posthog/posthog-go v0.0.0-20240315130956-036dfa9f3555
golang.org/x/net v0.19.0
gopkg.in/yaml.v2 v2.4.0
helm.sh/helm/v3 v3.14.2
Expand Down Expand Up @@ -79,7 +82,6 @@ require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
Expand Down
8 changes: 6 additions & 2 deletions cyclops-ctrl/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
Expand All @@ -220,6 +220,8 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
Expand Down Expand Up @@ -305,6 +307,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posthog/posthog-go v0.0.0-20240315130956-036dfa9f3555 h1:RqJZxk2VAaZYCCk4ZVo7iLqp4a03LWitjE0tNIMyvMU=
github.com/posthog/posthog-go v0.0.0-20240315130956-036dfa9f3555/go.mod h1:QjlpryJtfYLrZF2GUkAhejH4E7WlDbdKkvOi5hLmkdg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
Expand Down
6 changes: 6 additions & 0 deletions cyclops-ctrl/internal/controller/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,28 @@ import (
"github.com/cyclops-ui/cycops-ctrl/internal/mapper"
"github.com/cyclops-ui/cycops-ctrl/internal/models/dto"
"github.com/cyclops-ui/cycops-ctrl/internal/storage/templates"
"github.com/cyclops-ui/cycops-ctrl/internal/telemetry"
"github.com/cyclops-ui/cycops-ctrl/internal/template"
)

type Modules struct {
kubernetesClient *k8sclient.KubernetesClient
templatesRepo *template.Repo
templates *templates.Storage
telemetryClient telemetry.Client
}

func NewModulesController(
templates *templates.Storage,
templatesRepo *template.Repo,
kubernetes *k8sclient.KubernetesClient,
telemetryClient telemetry.Client,
) *Modules {
return &Modules{
kubernetesClient: kubernetes,
templatesRepo: templatesRepo,
templates: templates,
telemetryClient: telemetryClient,
}
}

Expand Down Expand Up @@ -211,6 +215,8 @@ func (m *Modules) CreateModule(ctx *gin.Context) {
return
}

m.telemetryClient.ModuleCreation()

err = m.kubernetesClient.CreateModule(module)
if err != nil {
fmt.Println(err)
Expand Down
7 changes: 6 additions & 1 deletion cyclops-ctrl/internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/cyclops-ui/cycops-ctrl/internal/cluster/k8sclient"
"github.com/cyclops-ui/cycops-ctrl/internal/controller"
"github.com/cyclops-ui/cycops-ctrl/internal/storage/templates"
"github.com/cyclops-ui/cycops-ctrl/internal/telemetry"
templaterepo "github.com/cyclops-ui/cycops-ctrl/internal/template"
)

Expand All @@ -17,17 +18,21 @@ type Handler struct {
templatesRepo *templaterepo.Repo
templatesStorage *templates.Storage
k8sClient *k8sclient.KubernetesClient

telemetryClient telemetry.Client
}

func New(
templates *templates.Storage,
templatesRepo *templaterepo.Repo,
kubernetesClient *k8sclient.KubernetesClient,
telemetryClient telemetry.Client,
) (*Handler, error) {
return &Handler{
templatesRepo: templatesRepo,
templatesStorage: templates,
k8sClient: kubernetesClient,
telemetryClient: telemetryClient,
router: gin.New(),
}, nil
}
Expand All @@ -36,7 +41,7 @@ func (h *Handler) Start() error {
gin.SetMode(gin.DebugMode)

templatesController := controller.NewTemplatesController(h.templatesStorage, h.templatesRepo, h.k8sClient)
modulesController := controller.NewModulesController(h.templatesStorage, h.templatesRepo, h.k8sClient)
modulesController := controller.NewModulesController(h.templatesStorage, h.templatesRepo, h.k8sClient, h.telemetryClient)
clusterController := controller.NewClusterController(h.k8sClient)

h.router = gin.New()
Expand Down
7 changes: 6 additions & 1 deletion cyclops-ctrl/internal/modulecontroller/module_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/cyclops-ui/cycops-ctrl/internal/cluster/k8sclient"
"github.com/cyclops-ui/cycops-ctrl/internal/models"
"github.com/cyclops-ui/cycops-ctrl/internal/storage/templates"
"github.com/cyclops-ui/cycops-ctrl/internal/telemetry"
templaterepo "github.com/cyclops-ui/cycops-ctrl/internal/template"
)

Expand All @@ -46,7 +47,8 @@ type ModuleReconciler struct {
templates *templates.Storage
kubernetesClient *k8sclient.KubernetesClient

logger logr.Logger
telemetryClient telemetry.Client
logger logr.Logger
}

func NewModuleReconciler(
Expand All @@ -55,13 +57,15 @@ func NewModuleReconciler(
templatesRepo *templaterepo.Repo,
templates *templates.Storage,
kubernetesClient *k8sclient.KubernetesClient,
telemetryClient telemetry.Client,
) *ModuleReconciler {
return &ModuleReconciler{
Client: client,
Scheme: scheme,
templatesRepo: templatesRepo,
templates: templates,
kubernetesClient: kubernetesClient,
telemetryClient: telemetryClient,
logger: ctrl.Log.WithName("reconciler"),
}
}
Expand All @@ -81,6 +85,7 @@ func NewModuleReconciler(
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *ModuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
r.telemetryClient.ModuleReconciliation()

var module cyclopsv1alpha1.Module
err := r.Get(ctx, req.NamespacedName, &module)
Expand Down
75 changes: 75 additions & 0 deletions cyclops-ctrl/internal/telemetry/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package telemetry

import (
"github.com/google/uuid"
"github.com/posthog/posthog-go"
)

type Client interface {
ModuleCreation()
ModuleReconciliation()
InstanceStart()
}

type EnqueueClient struct {
client posthog.Client
distinctID string
}

type MockClient struct{}

func NewClient(disable bool) (Client, error) {
if disable {
return MockClient{}, nil
}

client, err := posthog.NewWithConfig(
"phc_1GSZ1j83eWbXITdpYO3u2Epo6ZZ7IimmRsLue7oDx3p",
posthog.Config{
Endpoint: "https://eu.posthog.com",
},
)
if err != nil {
return nil, err
}

id, err := uuid.NewUUID()
if err != nil {
return nil, err
}

return EnqueueClient{
client: client,
distinctID: id.String(),
}, nil
}

func (c EnqueueClient) InstanceStart() {
_ = c.client.Enqueue(posthog.Capture{
Event: "cyclops-instance-start",
DistinctId: c.distinctID,
})
}

func (c EnqueueClient) ModuleReconciliation() {
_ = c.client.Enqueue(posthog.Capture{
Event: "module-reconciliation",
DistinctId: c.distinctID,
})
}

func (c EnqueueClient) ModuleCreation() {
_ = c.client.Enqueue(posthog.Capture{
Event: "module-creation",
DistinctId: c.distinctID,
})
}

func (c MockClient) InstanceStart() {
}

func (c MockClient) ModuleReconciliation() {
}

func (c MockClient) ModuleCreation() {
}
4 changes: 2 additions & 2 deletions install/cyclops-install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ spec:
spec:
containers:
- name: cyclops-ui
image: cyclopsui/cyclops-ui:v0.2.0-rc.2
image: cyclopsui/cyclops-ui:v0.2.0-metrics
ports:
- containerPort: 80
env:
Expand Down Expand Up @@ -379,7 +379,7 @@ spec:
serviceAccountName: cyclops-ctrl
containers:
- name: cyclops-ctrl
image: cyclopsui/cyclops-ctrl:v0.2.0-rc.2
image: cyclopsui/cyclops-ctrl:v0.2.0-metrics
ports:
- containerPort: 8080
env:
Expand Down
3 changes: 0 additions & 3 deletions web/docs/roadmap/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,3 @@ We intend to finish developing a stable version by the start of the next year.

### Contact us
If you have the knowledge or resources to help in contributing to Cyclops, contact us at [email protected]



43 changes: 43 additions & 0 deletions web/docs/usage_metrics/usage_metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Usage metrics

Cyclops tracks usage metrics so that the maintainers can gain better insights into Cyclops usage. No sensitive or user data is sent; only triggered events, like a Cyclops instance start, are sent.

These events include:

**- `cyclops-instance-start`** - triggered once at the start of cyclops-ctrl pod
**- `module-creation`** - called by the UI each time you create a new module
**- `module-reconciliation`** - each time a Module CRD in the cluster is changed

The metric collection is implemented using [posthog](https://posthog.com).

Each time one of the events above is triggered, Cyclops sends an HTTP request to the posthog API with the following information:
```json
{
"type": "capture",
"timestamp": "2024-03-23T19:05:38.808279+01:00",
"distinct_id": "f46d57f0-e93f-11ee-924c-8281c5d92ae4",
"event": "cyclops-instance-start"
}
```
`distinct_id` - generated for each Cyclops instance using [NewUUID](https://pkg.go.dev/github.com/google/uuid#NewUUID) from google/uuid package
`event` - which event was triggered; see events above

## Turn off

If you wish to turn off tracking metrics, add an environment variable to cyclops-ctrl:
`DISABLE_TELEMETRY: true`

You can turn it off by adding the env variable to your `cyclops-ctrl` Deployment definition. Navigate to the `env` part of the deployment definition and add the following:

```
env:
- name: PORT
value: "8080"
+ - name: DISABLE_TELEMETRY
+ value: "true"
```

The metric collection is enabled by default but is [disabled in development](https://github.com/cyclops-ui/cyclops/blob/main/cyclops-ctrl/.env).

## Other
If you have any additional questions about Cyclops and tracking usage metrics, reach out to us at `[email protected]`
Loading

0 comments on commit 8db48a8

Please sign in to comment.