mirror of
https://github.com/SigNoz/signoz.git
synced 2026-06-20 15:20:31 +01:00
Some checks failed
build-staging / js-build (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* feat: extend error responses with new error struct
* fix: enriched error for dashboard api
* fix: merge issues
* fix: reverted dashboards changes and add for cloud integrations
* fix: delete file
* fix: add back file
* fix: added a helper
* fix: removed invlaid referencess
* fix: generate openapi
* fix: keeping additional along with suggestion
* Revert "fix: keeping additional along with suggestion"
This reverts commit be30e2ffd2.
* fix: added suggestions per additonal error
* fix: generate openapi
* fix: remove valid references
* fix: removeg valid references for select and group by and only did you mean is kept
* fix: unit test
* fix: use binding for deconding for both ee and community
* fix: trim down suggestions methods
* fix: added renamed methods and moved stuff around
* fix: typo
* fix: removed json decoder
* fix: added empty check
* fix: retain addtional
* fix: reverted re-structing of file
158 lines
4.5 KiB
Go
158 lines
4.5 KiB
Go
package querier
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
|
|
anomalyV2 "github.com/SigNoz/signoz/ee/anomaly"
|
|
"github.com/SigNoz/signoz/pkg/errors"
|
|
"github.com/SigNoz/signoz/pkg/factory"
|
|
"github.com/SigNoz/signoz/pkg/http/binding"
|
|
"github.com/SigNoz/signoz/pkg/http/render"
|
|
"github.com/SigNoz/signoz/pkg/querier"
|
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
|
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
|
|
"github.com/SigNoz/signoz/pkg/valuer"
|
|
)
|
|
|
|
type handler struct {
|
|
set factory.ProviderSettings
|
|
querier querier.Querier
|
|
community querier.Handler
|
|
}
|
|
|
|
func NewHandler(set factory.ProviderSettings, querier querier.Querier, community querier.Handler) querier.Handler {
|
|
return &handler{
|
|
set: set,
|
|
querier: querier,
|
|
community: community,
|
|
}
|
|
}
|
|
|
|
func (h *handler) QueryRange(rw http.ResponseWriter, req *http.Request) {
|
|
bodyBytes, err := io.ReadAll(req.Body)
|
|
if err != nil {
|
|
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "failed to read request body: %v", err))
|
|
return
|
|
}
|
|
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
|
|
ctx := req.Context()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
var queryRangeRequest qbtypes.QueryRangeRequest
|
|
if err := binding.JSON.BindBody(req.Body, &queryRangeRequest); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
if err := queryRangeRequest.Validate(); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
orgID, err := valuer.NewUUID(claims.OrgID)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
if anomalyQuery, ok := queryRangeRequest.IsAnomalyRequest(); ok {
|
|
anomalies, err := h.handleAnomalyQuery(ctx, orgID, anomalyQuery, &queryRangeRequest)
|
|
if err != nil {
|
|
render.Error(rw, errors.NewInternalf(errors.CodeInternal, "failed to get anomalies: %v", err))
|
|
return
|
|
}
|
|
|
|
results := []any{}
|
|
for _, item := range anomalies.Results {
|
|
results = append(results, item)
|
|
}
|
|
|
|
// Build step intervals from the anomaly query
|
|
stepIntervals := make(map[string]uint64)
|
|
if anomalyQuery.StepInterval.Duration > 0 {
|
|
stepIntervals[anomalyQuery.Name] = uint64(anomalyQuery.StepInterval.Seconds())
|
|
}
|
|
|
|
finalResp := &qbtypes.QueryRangeResponse{
|
|
Type: queryRangeRequest.RequestType,
|
|
Data: qbtypes.QueryData{
|
|
Results: results,
|
|
},
|
|
Meta: qbtypes.ExecStats{
|
|
StepIntervals: stepIntervals,
|
|
},
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, finalResp)
|
|
return
|
|
}
|
|
|
|
// regular query range request, delegate to community handler
|
|
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
h.community.QueryRange(rw, req)
|
|
}
|
|
|
|
func (h *handler) QueryRawStream(rw http.ResponseWriter, req *http.Request) {
|
|
h.community.QueryRawStream(rw, req)
|
|
}
|
|
|
|
func (h *handler) ReplaceVariables(rw http.ResponseWriter, req *http.Request) {
|
|
h.community.ReplaceVariables(rw, req)
|
|
}
|
|
|
|
func extractSeasonality(anomalyQuery *qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]) anomalyV2.Seasonality {
|
|
for _, fn := range anomalyQuery.Functions {
|
|
if fn.Name == qbtypes.FunctionNameAnomaly {
|
|
for _, arg := range fn.Args {
|
|
if arg.Name == "seasonality" {
|
|
if seasonalityStr, ok := arg.Value.(string); ok {
|
|
switch seasonalityStr {
|
|
case "weekly":
|
|
return anomalyV2.SeasonalityWeekly
|
|
case "hourly":
|
|
return anomalyV2.SeasonalityHourly
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return anomalyV2.SeasonalityDaily // default
|
|
}
|
|
|
|
func (h *handler) createAnomalyProvider(seasonality anomalyV2.Seasonality) anomalyV2.Provider {
|
|
switch seasonality {
|
|
case anomalyV2.SeasonalityWeekly:
|
|
return anomalyV2.NewWeeklyProvider(
|
|
anomalyV2.WithQuerier[*anomalyV2.WeeklyProvider](h.querier),
|
|
anomalyV2.WithLogger[*anomalyV2.WeeklyProvider](h.set.Logger),
|
|
)
|
|
case anomalyV2.SeasonalityHourly:
|
|
return anomalyV2.NewHourlyProvider(
|
|
anomalyV2.WithQuerier[*anomalyV2.HourlyProvider](h.querier),
|
|
anomalyV2.WithLogger[*anomalyV2.HourlyProvider](h.set.Logger),
|
|
)
|
|
default:
|
|
return anomalyV2.NewDailyProvider(
|
|
anomalyV2.WithQuerier[*anomalyV2.DailyProvider](h.querier),
|
|
anomalyV2.WithLogger[*anomalyV2.DailyProvider](h.set.Logger),
|
|
)
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleAnomalyQuery(ctx context.Context, orgID valuer.UUID, anomalyQuery *qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation], queryRangeRequest *qbtypes.QueryRangeRequest) (*anomalyV2.AnomaliesResponse, error) {
|
|
seasonality := extractSeasonality(anomalyQuery)
|
|
provider := h.createAnomalyProvider(seasonality)
|
|
|
|
return provider.GetAnomalies(ctx, orgID, &anomalyV2.AnomaliesRequest{Params: queryRangeRequest})
|
|
}
|