Add UI telemetry (#6981)

* Load Segment module

* First events

* Add GET /telemetry epoint to API

* Init telemetry with data from API

* Add more tracking

* Update ui static files

* Send telemetry for tab changes

* Update UI static files

* Set IP to 0.0.0.0

* Update UI static files
This commit is contained in:
Philippe Martin
2023-07-19 18:20:18 +02:00
committed by GitHub
parent 1624e4a490
commit 159ca02b89
37 changed files with 3627 additions and 42 deletions

View File

@@ -37,4 +37,5 @@ go/model_image_command.go
go/model_metadata.go
go/model_metadata_request.go
go/model_resource.go
go/model_telemetry_response.go
go/routers.go

View File

@@ -44,6 +44,7 @@ type DefaultApiRouter interface {
DevstateResourceResourceNameDelete(http.ResponseWriter, *http.Request)
InstanceDelete(http.ResponseWriter, *http.Request)
InstanceGet(http.ResponseWriter, *http.Request)
TelemetryGet(http.ResponseWriter, *http.Request)
}
// DefaultApiServicer defines the api actions for the DefaultApi service
@@ -77,4 +78,5 @@ type DefaultApiServicer interface {
DevstateResourceResourceNameDelete(context.Context, string) (ImplResponse, error)
InstanceDelete(context.Context) (ImplResponse, error)
InstanceGet(context.Context) (ImplResponse, error)
TelemetryGet(context.Context) (ImplResponse, error)
}

View File

@@ -206,6 +206,12 @@ func (c *DefaultApiController) Routes() Routes {
"/api/v1/instance",
c.InstanceGet,
},
{
"TelemetryGet",
strings.ToUpper("Get"),
"/api/v1/telemetry",
c.TelemetryGet,
},
}
}
@@ -714,3 +720,16 @@ func (c *DefaultApiController) InstanceGet(w http.ResponseWriter, r *http.Reques
EncodeJSONResponse(result.Body, &result.Code, w)
}
// TelemetryGet -
func (c *DefaultApiController) TelemetryGet(w http.ResponseWriter, r *http.Request) {
result, err := c.service.TelemetryGet(r.Context())
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}

View File

@@ -0,0 +1,44 @@
/*
* odo dev
*
* API interface for 'odo dev'
*
* API version: 0.1
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type TelemetryGet200Response struct {
Enabled bool `json:"enabled"`
Apikey string `json:"apikey,omitempty"`
Userid string `json:"userid,omitempty"`
}
// AssertTelemetryGet200ResponseRequired checks if the required fields are not zero-ed
func AssertTelemetryGet200ResponseRequired(obj TelemetryGet200Response) error {
elements := map[string]interface{}{
"enabled": obj.Enabled,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertRecurseTelemetryGet200ResponseRequired recursively checks if required fields are not zero-ed in a nested slice.
// Accepts only nested slice of TelemetryGet200Response (e.g. [][]TelemetryGet200Response), otherwise ErrTypeAssertionError is thrown.
func AssertRecurseTelemetryGet200ResponseRequired(objSlice interface{}) error {
return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error {
aTelemetryGet200Response, ok := obj.(TelemetryGet200Response)
if !ok {
return ErrTypeAssertionError
}
return AssertTelemetryGet200ResponseRequired(aTelemetryGet200Response)
})
}

View File

@@ -0,0 +1,44 @@
/*
* odo dev
*
* API interface for 'odo dev'
*
* API version: 0.1
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type TelemetryResponse struct {
Enabled bool `json:"enabled"`
Apikey string `json:"apikey,omitempty"`
Userid string `json:"userid,omitempty"`
}
// AssertTelemetryResponseRequired checks if the required fields are not zero-ed
func AssertTelemetryResponseRequired(obj TelemetryResponse) error {
elements := map[string]interface{}{
"enabled": obj.Enabled,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertRecurseTelemetryResponseRequired recursively checks if required fields are not zero-ed in a nested slice.
// Accepts only nested slice of TelemetryResponse (e.g. [][]TelemetryResponse), otherwise ErrTypeAssertionError is thrown.
func AssertRecurseTelemetryResponseRequired(objSlice interface{}) error {
return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error {
aTelemetryResponse, ok := obj.(TelemetryResponse)
if !ok {
return ErrTypeAssertionError
}
return AssertTelemetryResponseRequired(aTelemetryResponse)
})
}

View File

@@ -17,6 +17,8 @@ import (
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
"github.com/redhat-developer/odo/pkg/podman"
"github.com/redhat-developer/odo/pkg/preference"
"github.com/redhat-developer/odo/pkg/segment"
scontext "github.com/redhat-developer/odo/pkg/segment/context"
"github.com/redhat-developer/odo/pkg/state"
"k8s.io/klog"
)
@@ -175,3 +177,27 @@ func (s *DefaultApiService) validateDevfile(ctx context.Context, dir string) err
}
return validate.ValidateDevfileData(devObj.Data)
}
func (s *DefaultApiService) TelemetryGet(ctx context.Context) (openapi.ImplResponse, error) {
var (
enabled = scontext.GetTelemetryStatus(ctx)
apikey string
userid string
)
if enabled {
apikey = segment.GetApikey()
var err error
userid, err = segment.GetUserIdentity(segment.GetTelemetryFilePath())
if err != nil {
return openapi.Response(http.StatusInternalServerError, openapi.GeneralError{
Message: fmt.Sprintf("error getting telemetry data: %s", err),
}), nil
}
}
return openapi.Response(http.StatusOK, openapi.TelemetryResponse{
Enabled: enabled,
Apikey: apikey,
Userid: userid,
}), nil
}

View File

@@ -1321,6 +1321,9 @@ terms above.
mermaid
MIT
ngx-segment-analytics
MIT
rxjs
Apache-2.0
Apache License

View File

@@ -11,6 +11,6 @@
<body class="mat-typography">
<div id="loading">Loading, please wait...</div>
<app-root></app-root>
<script src="runtime.1289ea0acffcdc5e.js" type="module"></script><script src="polyfills.8b3b37cedaf377c3.js" type="module"></script><script src="main.2ab96df0533a01ab.js" type="module"></script>
<script src="runtime.1289ea0acffcdc5e.js" type="module"></script><script src="polyfills.8b3b37cedaf377c3.js" type="module"></script><script src="main.64f53365507b1341.js" type="module"></script>
</body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -155,6 +155,9 @@ func GenericRun(o Runnable, testClientset clientset.Clientset, cmd *cobra.Comman
klog.V(4).Infof("WARNING: debug telemetry, if enabled, will be logged in %s", debugTelemetry)
}
isTelemetryEnabled := segment.IsTelemetryEnabled(userConfig, envcontext.GetEnvConfig(ctx))
scontext.SetTelemetryStatus(ctx, isTelemetryEnabled)
// We can dereference as there is a default value defined for this config field
err = scontext.SetCaller(ctx, envConfig.TelemetryCaller)
if err != nil {

View File

@@ -39,7 +39,7 @@ func getTelemetryForDevfileRegistry(ctx context.Context) (registryLibrary.Teleme
tag, _ := locale.Detect()
td.Locale = tag.String()
user, err := getUserIdentity(GetTelemetryFilePath())
user, err := GetUserIdentity(GetTelemetryFilePath())
if err != nil {
// default to the generic user ID if the anonymous ID cannot be found
td.User = td.Client

View File

@@ -73,6 +73,10 @@ type Client struct {
TelemetryFilePath string
}
func GetApikey() string {
return writeKey
}
// NewClient returns a Client created with the default args
func NewClient() (*Client, error) {
return newCustomClient(
@@ -131,7 +135,7 @@ func (c *Client) Upload(ctx context.Context, data TelemetryData) error {
}
// obtain the user ID
userId, uerr := getUserIdentity(c.TelemetryFilePath)
userId, uerr := GetUserIdentity(c.TelemetryFilePath)
if uerr != nil {
return uerr
}
@@ -193,8 +197,8 @@ func GetTelemetryFilePath() string {
return filepath.Join(homeDir, ".redhat", "anonymousId")
}
// getUserIdentity returns the anonymous ID if it exists, else creates a new one and sends the data to Segment
func getUserIdentity(telemetryFilePath string) (string, error) {
// GetUserIdentity returns the anonymous ID if it exists, else creates a new one and sends the data to Segment
func GetUserIdentity(telemetryFilePath string) (string, error) {
var id []byte
// Get-or-Create the '$HOME/.redhat' directory