diff --git a/ee/query-service/app/server.go b/ee/query-service/app/server.go index dfdff14939..dcb5568c04 100644 --- a/ee/query-service/app/server.go +++ b/ee/query-service/app/server.go @@ -10,6 +10,7 @@ import ( "net/http" _ "net/http/pprof" // http profiler "os" + "regexp" "time" "github.com/gorilla/handlers" @@ -393,13 +394,14 @@ func (lrw *loggingResponseWriter) Flush() { lrw.ResponseWriter.(http.Flusher).Flush() } -func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface{}, bool) { - pathToExtractBodyFrom := "/api/v3/query_range" +func extractQueryRangeData(path string, r *http.Request) (map[string]interface{}, bool) { + pathToExtractBodyFromV3 := "/api/v3/query_range" + pathToExtractBodyFromV4 := "/api/v4/query_range" data := map[string]interface{}{} var postData *v3.QueryRangeParamsV3 - if path == pathToExtractBodyFrom && (r.Method == "POST") { + if (r.Method == "POST") && ((path == pathToExtractBodyFromV3) || (path == pathToExtractBodyFromV4)) { if r.Body != nil { bodyBytes, err := io.ReadAll(r.Body) if err != nil { @@ -417,6 +419,25 @@ func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface return nil, false } + referrer := r.Header.Get("Referer") + + dashboardMatched, err := regexp.MatchString(`/dashboard/[a-zA-Z0-9\-]+/(new|edit)(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the referrer", zap.Error(err)) + } + alertMatched, err := regexp.MatchString(`/alerts/(new|edit)(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the alert: ", zap.Error(err)) + } + logsExplorerMatched, err := regexp.MatchString(`/logs/logs-explorer(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the logs explorer: ", zap.Error(err)) + } + traceExplorerMatched, err := regexp.MatchString(`/traces-explorer(?:\?.*)?$`, referrer) + if err != nil { + zap.L().Error("error while matching the trace explorer: ", zap.Error(err)) + } + signozMetricsUsed := false signozLogsUsed := false signozTracesUsed := false @@ -445,6 +466,20 @@ func extractQueryRangeV3Data(path string, r *http.Request) (map[string]interface data["tracesUsed"] = signozTracesUsed userEmail, err := baseauth.GetEmailFromJwt(r.Context()) if err == nil { + // switch case to set data["screen"] based on the referrer + switch { + case dashboardMatched: + data["screen"] = "panel" + case alertMatched: + data["screen"] = "alert" + case logsExplorerMatched: + data["screen"] = "logs-explorer" + case traceExplorerMatched: + data["screen"] = "traces-explorer" + default: + data["screen"] = "unknown" + return data, true + } telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail, true, false) } } @@ -472,7 +507,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler { route := mux.CurrentRoute(r) path, _ := route.GetPathTemplate() - queryRangeV3data, metadataExists := extractQueryRangeV3Data(path, r) + queryRangeData, metadataExists := extractQueryRangeData(path, r) getActiveLogs(path, r) lrw := NewLoggingResponseWriter(w) @@ -480,7 +515,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler { data := map[string]interface{}{"path": path, "statusCode": lrw.statusCode} if metadataExists { - for key, value := range queryRangeV3data { + for key, value := range queryRangeData { data[key] = value } } diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go index d795599845..781db7fbae 100644 --- a/pkg/query-service/app/clickhouseReader/reader.go +++ b/pkg/query-service/app/clickhouseReader/reader.go @@ -50,6 +50,7 @@ import ( "go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/common" "go.signoz.io/signoz/pkg/query-service/constants" + "go.signoz.io/signoz/pkg/query-service/dao" am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager" "go.signoz.io/signoz/pkg/query-service/interfaces" "go.signoz.io/signoz/pkg/query-service/model" @@ -3618,6 +3619,15 @@ func (r *ClickHouseReader) GetSavedViewsInfo(ctx context.Context) (*model.SavedV return &savedViewsInfo, nil } +func (r *ClickHouseReader) GetUsers(ctx context.Context) ([]model.UserPayload, error) { + + users, apiErr := dao.DB().GetUsers(ctx) + if apiErr != nil { + return nil, apiErr.Err + } + return users, nil +} + func (r *ClickHouseReader) GetLogFields(ctx context.Context) (*model.GetFieldsResponse, *model.ApiError) { // response will contain top level fields from the otel log model response := model.GetFieldsResponse{ diff --git a/pkg/query-service/interfaces/interface.go b/pkg/query-service/interfaces/interface.go index dfe24c9064..d132ad3c9c 100644 --- a/pkg/query-service/interfaces/interface.go +++ b/pkg/query-service/interfaces/interface.go @@ -96,6 +96,7 @@ type Reader interface { GetLogAttributeKeys(ctx context.Context, req *v3.FilterAttributeKeyRequest) (*v3.FilterAttributeKeyResponse, error) GetLogAttributeValues(ctx context.Context, req *v3.FilterAttributeValueRequest) (*v3.FilterAttributeValueResponse, error) GetLogAggregateAttributes(ctx context.Context, req *v3.AggregateAttributeRequest) (*v3.AggregateAttributeResponse, error) + GetUsers(ctx context.Context) ([]model.UserPayload, error) // Connection needed for rules, not ideal but required GetConn() clickhouse.Conn diff --git a/pkg/query-service/telemetry/telemetry.go b/pkg/query-service/telemetry/telemetry.go index a9150ebcbf..b67a136d8c 100644 --- a/pkg/query-service/telemetry/telemetry.go +++ b/pkg/query-service/telemetry/telemetry.go @@ -51,7 +51,6 @@ const ( var SAAS_EVENTS_LIST = map[string]struct{}{ TELEMETRY_EVENT_NUMBER_OF_SERVICES: {}, - TELEMETRY_EVENT_ACTIVE_USER: {}, TELEMETRY_EVENT_HEART_BEAT: {}, TELEMETRY_EVENT_LANGUAGE: {}, TELEMETRY_EVENT_SERVICE: {}, @@ -61,7 +60,7 @@ var SAAS_EVENTS_LIST = map[string]struct{}{ TELEMETRY_EVENT_DASHBOARDS_ALERTS: {}, TELEMETRY_EVENT_SUCCESSFUL_DASHBOARD_PANEL_QUERY: {}, TELEMETRY_EVENT_SUCCESSFUL_ALERT_QUERY: {}, - // TELEMETRY_EVENT_QUERY_RANGE_API: {}, // this event is not part of SAAS_EVENTS_LIST as it may cause too many events to be sent + TELEMETRY_EVENT_QUERY_RANGE_API: {}, } const api_key = "4Gmoa4ixJAUHx2BpJxsjwA1bEfnwEeRz" @@ -194,10 +193,7 @@ func createTelemetry() { rand.Seed(time.Now().UnixNano()) - data := map[string]interface{}{} - telemetry.SetTelemetryEnabled(constants.IsTelemetryEnabled()) - telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, "", true, false) ticker := time.NewTicker(HEART_BEAT_DURATION) activeUserTicker := time.NewTicker(ACTIVE_USER_DURATION) @@ -291,8 +287,16 @@ func createTelemetry() { for key, value := range tsInfo { data[key] = value } - telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, "", true, false) + users, apiErr := telemetry.reader.GetUsers(context.Background()) + if apiErr == nil { + for _, user := range users { + if user.Email == DEFAULT_CLOUD_EMAIL { + continue + } + telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data, user.Email, true, false) + } + } alertsInfo, err := telemetry.reader.GetAlertsInfo(context.Background()) if err == nil { dashboardsInfo, err := telemetry.reader.GetDashboardsInfo(context.Background()) @@ -317,14 +321,19 @@ func createTelemetry() { "tracesSavedViews": savedViewsInfo.TracesSavedViews, } // 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, "", true, false) + if (dashboardsInfo.TotalDashboards > 0 || alertsInfo.TotalAlerts > 0 || len(*channels) > 0 || savedViewsInfo.TotalSavedViews > 0) && apiErr == nil { + for _, user := range users { + if user.Email == DEFAULT_CLOUD_EMAIL { + continue + } + telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, dashboardsAlertsData, user.Email, true, false) + } } } } } } - if err != nil { + if err != nil || apiErr != nil { telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, map[string]interface{}{"error": err.Error()}, "", true, false) }