feat: add events API (#4761)

This commit is contained in:
Vishal Sharma 2024-03-28 21:43:41 +05:30 committed by GitHub
parent 990fc83269
commit da4a6266c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 68 additions and 32 deletions

View File

@ -445,7 +445,7 @@ func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface
data["tracesUsed"] = signozTracesUsed
userEmail, err := baseauth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail, true, false)
}
}
return data, true
@ -488,7 +488,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
if _, ok := telemetry.EnabledPaths()[path]; ok {
userEmail, err := baseauth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail, true, false)
}
}

View File

@ -204,7 +204,7 @@ func (lm *Manager) Validate(ctx context.Context) (reterr error) {
zap.L().Error("License validation completed with error", zap.Error(reterr))
atomic.AddUint64(&lm.failedAttempts, 1)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_CHECK_FAILED,
map[string]interface{}{"err": reterr.Error()}, "")
map[string]interface{}{"err": reterr.Error()}, "", true, false)
} else {
zap.L().Info("License validation completed with no errors")
}
@ -263,7 +263,7 @@ func (lm *Manager) Activate(ctx context.Context, key string) (licenseResponse *m
userEmail, err := auth.GetEmailFromJwt(ctx)
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_ACT_FAILED,
map[string]interface{}{"err": errResponse.Err.Error()}, userEmail)
map[string]interface{}{"err": errResponse.Err.Error()}, userEmail, true, false)
}
}
}()

View File

@ -3802,7 +3802,7 @@ func (r *ClickHouseReader) GetLogs(ctx context.Context, params *model.LogsFilter
if lenFilters != 0 {
userEmail, err := auth.GetEmailFromJwt(ctx)
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail, true, false)
}
}
@ -3844,7 +3844,7 @@ func (r *ClickHouseReader) TailLogs(ctx context.Context, client *model.LogsTailC
if lenFilters != 0 {
userEmail, err := auth.GetEmailFromJwt(ctx)
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail, true, false)
}
}
@ -3936,7 +3936,7 @@ func (r *ClickHouseReader) AggregateLogs(ctx context.Context, params *model.Logs
if lenFilters != 0 {
userEmail, err := auth.GetEmailFromJwt(ctx)
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail, true, false)
}
}

View File

@ -401,6 +401,8 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *AuthMiddleware) {
router.HandleFunc("/api/v1/explorer/views/{viewId}", am.EditAccess(aH.deleteSavedView)).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/feedback", am.OpenAccess(aH.submitFeedback)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/events", am.ViewAccess(aH.registerEvent)).Methods(http.MethodPost)
// router.HandleFunc("/api/v1/get_percentiles", aH.getApplicationPercentiles).Methods(http.MethodGet)
router.HandleFunc("/api/v1/services", am.ViewAccess(aH.getServices)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/services/list", am.ViewAccess(aH.getServicesList)).Methods(http.MethodGet)
@ -1502,7 +1504,22 @@ func (aH *APIHandler) submitFeedback(w http.ResponseWriter, r *http.Request) {
}
userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_INPRODUCT_FEEDBACK, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_INPRODUCT_FEEDBACK, data, userEmail, true, false)
}
}
func (aH *APIHandler) registerEvent(w http.ResponseWriter, r *http.Request) {
request, err := parseRegisterEventRequest(r)
if aH.HandleError(w, err, http.StatusBadRequest) {
return
}
userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(request.EventName, request.Attributes, userEmail, true, true)
aH.WriteJSON(w, r, map[string]string{"data": "Event Processed Successfully"})
} else {
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
}
}
@ -1585,7 +1602,7 @@ func (aH *APIHandler) getServices(w http.ResponseWriter, r *http.Request) {
}
userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_NUMBER_OF_SERVICES, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_NUMBER_OF_SERVICES, data, userEmail, true, false)
}
if (data["number"] != 0) && (data["number"] != telemetry.DEFAULT_NUMBER_OF_SERVICES) {
@ -2310,7 +2327,7 @@ func (aH *APIHandler) editOrg(w http.ResponseWriter, r *http.Request) {
"organizationName": req.Name,
}
userEmail, err := auth.GetEmailFromJwt(r.Context())
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_ORG_SETTINGS, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_ORG_SETTINGS, data, userEmail, true, false)
aH.WriteJSON(w, r, map[string]string{"data": "org updated successfully"})
}
@ -3525,7 +3542,7 @@ func sendQueryResultEvents(r *http.Request, result []*v3.Result, queryRangeParam
"metricsUsed": signozMetricsUsed,
"dashboardId": dashboardID,
"widgetId": widgetID,
}, userEmail)
}, userEmail, true, false)
}
if alertMatched {
var alertID string
@ -3547,7 +3564,7 @@ func sendQueryResultEvents(r *http.Request, result []*v3.Result, queryRangeParam
"logsUsed": signozLogsUsed,
"metricsUsed": signozMetricsUsed,
"alertId": alertID,
}, userEmail)
}, userEmail, true, false)
}
}
}

View File

@ -66,6 +66,19 @@ func parseGetTopOperationsRequest(r *http.Request) (*model.GetTopOperationsParam
return postData, nil
}
func parseRegisterEventRequest(r *http.Request) (*model.RegisterEventParams, error) {
var postData *model.RegisterEventParams
err := json.NewDecoder(r.Body).Decode(&postData)
if err != nil {
return nil, err
}
if postData.EventName == "" {
return nil, errors.New("eventName param missing in query")
}
return postData, nil
}
func parseMetricsTime(s string) (time.Time, error) {
if t, err := strconv.ParseFloat(s, 64); err == nil {
s, ns := math.Modf(t)

View File

@ -452,7 +452,7 @@ func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface
data["tracesUsed"] = signozTracesUsed
userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail, true, false)
}
}
return data, true
@ -496,7 +496,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
if _, ok := telemetry.EnabledPaths()[path]; ok {
userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail, true, false)
}
}
// }

View File

@ -89,7 +89,7 @@ func Invite(ctx context.Context, req *model.InviteRequest) (*model.InviteRespons
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_USER_INVITATION_SENT, map[string]interface{}{
"invited user email": req.Email,
}, au.Email)
}, au.Email, true, false)
// send email if SMTP is enabled
if os.Getenv("SMTP_ENABLED") == "true" && req.FrontendBaseUrl != "" {
@ -404,7 +404,7 @@ func RegisterInvitedUser(ctx context.Context, req *RegisterRequest, nopassword b
}
telemetry.GetInstance().IdentifyUser(user)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_USER_INVITATION_ACCEPTED, nil, req.Email)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_USER_INVITATION_ACCEPTED, nil, req.Email, true, false)
return user, nil
}

View File

@ -203,7 +203,7 @@ func (mds *ModelDaoSqlite) CreateUser(ctx context.Context,
}
telemetry.GetInstance().IdentifyUser(user)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_USER, data, user.Email)
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_USER, data, user.Email, true, false)
return user, nil
}

View File

@ -164,6 +164,11 @@ type GetTopOperationsParams struct {
Limit int `json:"limit"`
}
type RegisterEventParams struct {
EventName string `json:"eventName"`
Attributes map[string]interface{} `json:"attributes"`
}
type GetUsageParams struct {
StartTime string
EndTime string

View File

@ -197,7 +197,7 @@ func createTelemetry() {
data := map[string]interface{}{}
telemetry.SetTelemetryEnabled(constants.IsTelemetryEnabled())
telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, "")
telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, "", true, false)
ticker := time.NewTicker(HEART_BEAT_DURATION)
activeUserTicker := time.NewTicker(ACTIVE_USER_DURATION)
@ -231,7 +231,12 @@ func createTelemetry() {
if (telemetry.activeUser["traces"] != 0) || (telemetry.activeUser["metrics"] != 0) || (telemetry.activeUser["logs"] != 0) {
telemetry.activeUser["any"] = 1
}
telemetry.SendEvent(TELEMETRY_EVENT_ACTIVE_USER, map[string]interface{}{"traces": telemetry.activeUser["traces"], "metrics": telemetry.activeUser["metrics"], "logs": telemetry.activeUser["logs"], "any": telemetry.activeUser["any"]}, "")
telemetry.SendEvent(TELEMETRY_EVENT_ACTIVE_USER, map[string]interface{}{
"traces": telemetry.activeUser["traces"],
"metrics": telemetry.activeUser["metrics"],
"logs": telemetry.activeUser["logs"],
"any": telemetry.activeUser["any"]},
"", true, false)
telemetry.activeUser = map[string]int8{"traces": 0, "metrics": 0, "logs": 0, "any": 0}
case <-ticker.C:
@ -239,15 +244,15 @@ func createTelemetry() {
tagsInfo, _ := telemetry.reader.GetTagsInfoInLastHeartBeatInterval(context.Background(), HEART_BEAT_DURATION)
if len(tagsInfo.Env) != 0 {
telemetry.SendEvent(TELEMETRY_EVENT_ENVIRONMENT, map[string]interface{}{"value": tagsInfo.Env}, "")
telemetry.SendEvent(TELEMETRY_EVENT_ENVIRONMENT, map[string]interface{}{"value": tagsInfo.Env}, "", true, false)
}
for language, _ := range tagsInfo.Languages {
telemetry.SendEvent(TELEMETRY_EVENT_LANGUAGE, map[string]interface{}{"language": language}, "")
telemetry.SendEvent(TELEMETRY_EVENT_LANGUAGE, map[string]interface{}{"language": language}, "", true, false)
}
for service, _ := range tagsInfo.Services {
telemetry.SendEvent(TELEMETRY_EVENT_SERVICE, map[string]interface{}{"serviceName": service}, "")
telemetry.SendEvent(TELEMETRY_EVENT_SERVICE, map[string]interface{}{"serviceName": service}, "", true, false)
}
totalSpans, _ := telemetry.reader.GetTotalSpans(context.Background())
@ -280,7 +285,7 @@ func createTelemetry() {
for key, value := range tsInfo {
data[key] = value
}
telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, "")
telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, "", true, false)
alertsInfo, err := telemetry.reader.GetAlertsInfo(context.Background())
if err == nil {
@ -307,18 +312,18 @@ func createTelemetry() {
}
// send event only if there are dashboards or alerts or channels
if dashboardsInfo.TotalDashboards > 0 || alertsInfo.TotalAlerts > 0 || len(*channels) > 0 || savedViewsInfo.TotalSavedViews > 0 {
telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, dashboardsAlertsData, "")
telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, dashboardsAlertsData, "", true, false)
}
}
}
}
}
if err != nil {
telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, map[string]interface{}{"error": err.Error()}, "")
telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, map[string]interface{}{"error": err.Error()}, "", true, false)
}
getDistributedInfoInLastHeartBeatInterval, _ := telemetry.reader.GetDistributedInfoInLastHeartBeatInterval(context.Background())
telemetry.SendEvent(TELEMETRY_EVENT_DISTRIBUTED, getDistributedInfoInLastHeartBeatInterval, "")
telemetry.SendEvent(TELEMETRY_EVENT_DISTRIBUTED, getDistributedInfoInLastHeartBeatInterval, "", true, false)
}
}
}()
@ -426,7 +431,7 @@ func (a *Telemetry) checkEvents(event string) bool {
return sendEvent
}
func (a *Telemetry) SendEvent(event string, data map[string]interface{}, userEmail string, opts ...bool) {
func (a *Telemetry) SendEvent(event string, data map[string]interface{}, userEmail string, rateLimitFlag bool, viaEventsAPI bool) {
// ignore telemetry for default user
if userEmail == DEFAULT_CLOUD_EMAIL || a.GetUserEmail() == DEFAULT_CLOUD_EMAIL {
@ -436,10 +441,6 @@ func (a *Telemetry) SendEvent(event string, data map[string]interface{}, userEma
if userEmail != "" {
a.SetUserEmail(userEmail)
}
rateLimitFlag := true
if len(opts) > 0 {
rateLimitFlag = opts[0]
}
if !a.isTelemetryEnabled() {
return
@ -485,7 +486,7 @@ func (a *Telemetry) SendEvent(event string, data map[string]interface{}, userEma
// check if event is part of SAAS_EVENTS_LIST
_, isSaaSEvent := SAAS_EVENTS_LIST[event]
if a.saasOperator != nil && a.GetUserEmail() != "" && isSaaSEvent {
if a.saasOperator != nil && a.GetUserEmail() != "" && (isSaaSEvent || viaEventsAPI) {
a.saasOperator.Enqueue(analytics.Track{
Event: event,
UserId: a.GetUserEmail(),