diff --git a/frontend/src/types/reducer/trace.ts b/frontend/src/types/reducer/trace.ts
index fda615160c..701f27efa6 100644
--- a/frontend/src/types/reducer/trace.ts
+++ b/frontend/src/types/reducer/trace.ts
@@ -47,7 +47,7 @@ interface SpansAggregateData {
}
export interface Tags {
- Key: string[];
+ Key: string;
Operator: OperatorValues;
StringValues: string[];
NumberValues: number[];
diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go
index b0fbef4d0f..a1b2ceabab 100644
--- a/pkg/query-service/app/clickhouseReader/reader.go
+++ b/pkg/query-service/app/clickhouseReader/reader.go
@@ -3640,3 +3640,13 @@ func (r *ClickHouseReader) QueryDashboardVars(ctx context.Context, query string)
}
return &result, nil
}
+
+func (r *ClickHouseReader) CheckClickHouse(ctx context.Context) error {
+ rows, err := r.db.Query(ctx, "SELECT 1")
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ return nil
+}
diff --git a/pkg/query-service/app/http_handler.go b/pkg/query-service/app/http_handler.go
index 58a060649a..8d49dbb0ad 100644
--- a/pkg/query-service/app/http_handler.go
+++ b/pkg/query-service/app/http_handler.go
@@ -351,7 +351,7 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/feedback", OpenAccess(aH.submitFeedback)).Methods(http.MethodPost)
// router.HandleFunc("/api/v1/get_percentiles", aH.getApplicationPercentiles).Methods(http.MethodGet)
router.HandleFunc("/api/v1/services", ViewAccess(aH.getServices)).Methods(http.MethodPost)
- router.HandleFunc("/api/v1/services/list", aH.getServicesList).Methods(http.MethodGet)
+ router.HandleFunc("/api/v1/services/list", ViewAccess(aH.getServicesList)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/overview", ViewAccess(aH.getServiceOverview)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/service/top_operations", ViewAccess(aH.getTopOperations)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/service/top_level_operations", ViewAccess(aH.getServicesTopLevelOps)).Methods(http.MethodPost)
@@ -364,6 +364,7 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/version", OpenAccess(aH.getVersion)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/featureFlags", OpenAccess(aH.getFeatureFlags)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/configs", OpenAccess(aH.getConfigs)).Methods(http.MethodGet)
+ router.HandleFunc("/api/v1/health", OpenAccess(aH.getHealth)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/getSpanFilters", ViewAccess(aH.getSpanFilters)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/getTagFilters", ViewAccess(aH.getTagFilters)).Methods(http.MethodPost)
@@ -1671,6 +1672,22 @@ func (aH *APIHandler) getConfigs(w http.ResponseWriter, r *http.Request) {
aH.Respond(w, configs)
}
+// getHealth is used to check the health of the service.
+// 'live' query param can be used to check liveliness of
+// the service by checking the database connection.
+func (aH *APIHandler) getHealth(w http.ResponseWriter, r *http.Request) {
+ _, ok := r.URL.Query()["live"]
+ if ok {
+ err := aH.reader.CheckClickHouse(r.Context())
+ if err != nil {
+ aH.HandleError(w, err, http.StatusServiceUnavailable)
+ return
+ }
+ }
+
+ aH.WriteJSON(w, r, map[string]string{"status": "ok"})
+}
+
// inviteUser is used to invite a user. It is used by an admin api.
func (aH *APIHandler) inviteUser(w http.ResponseWriter, r *http.Request) {
req, err := parseInviteRequest(r)
diff --git a/pkg/query-service/interfaces/interface.go b/pkg/query-service/interfaces/interface.go
index a551e4b7f8..1a98e5d1d7 100644
--- a/pkg/query-service/interfaces/interface.go
+++ b/pkg/query-service/interfaces/interface.go
@@ -77,4 +77,5 @@ type Reader interface {
GetFanoutStorage() *storage.Storage
QueryDashboardVars(ctx context.Context, query string) (*model.DashboardVar, error)
+ CheckClickHouse(ctx context.Context) error
}