-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: generic api to run promql query for metrics #2073
Conversation
Signed-off-by: adarsh0728 <[email protected]>
Signed-off-by: adarsh0728 <[email protected]>
server/apis/v1/handler.go
Outdated
|
||
func buildTimeSeriesData(ctx context.Context, v1api v1.API, data MetricSpecData, query string, format PrometheusResponseFormat) []any { | ||
var timeSeriesData = make([]any, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add code comments
Signed-off-by: adarsh0728 <[email protected]>
Signed-off-by: adarsh0728 <[email protected]>
server/apis/v1/handler.go
Outdated
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||
defer cancel() | ||
|
||
var timeSeriesData = make([][]float64, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please fix lint errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
server/routes/routes.go
Outdated
// Get the time series data for a specific metric. | ||
r.POST("/namespaces/:namespace/pipelines/:pipeline/getMetricData", handler.GetMetricData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we planning to cover monovertex with the same endpoint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as of now, planning to have a separate endpoint for monovertex (for same endpoint we may have to add another field in the body and that could make API more cluttered). Any suggestions are welcome
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets update the comment to include for pipeline for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we provide a query generic query service which works for any metrics?
Signed-off-by: adarsh0728 <[email protected]>
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2073 +/- ##
==========================================
- Coverage 64.25% 63.39% -0.87%
==========================================
Files 324 327 +3
Lines 30650 31354 +704
==========================================
+ Hits 19695 19877 +182
- Misses 9913 10435 +522
Partials 1042 1042 ☔ View full report in Codecov by Sentry. |
server/apis/v1/response_metrics.go
Outdated
|
||
type MetricMetaData struct { | ||
NumaMetricName string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type MetricMetaData struct { | |
NumaMetricName string | |
type MetricMetadata struct { | |
NumaMetricName string |
server/apis/v1/handler.go
Outdated
client, err := api.NewClient(api.Config{ | ||
Address: h.prometheusServerUrl, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will end up creating a new client for every api invocation. Can we store it inside the handler struct and reuse it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, will resolve this.
server/apis/v1/handler.go
Outdated
v1api := v1.NewAPI(client) | ||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||
defer cancel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. Lets not create a new one for every invocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also make sure they are safe to be used across go routines.
Lets add a flag in config map for |
cmd/commands/server.go
Outdated
@@ -80,5 +82,7 @@ func NewServerCommand() *cobra.Command { | |||
command.Flags().StringVar(&serverAddr, "server-addr", sharedutil.LookupEnvStringOr("NUMAFLOW_SERVER_ADDRESS", "https://localhost:8443"), "The external address of the Numaflow server.") | |||
command.Flags().StringVar(&corsAllowedOrigins, "cors-allowed-origins", sharedutil.LookupEnvStringOr("NUMAFLOW_SERVER_CORS_ALLOWED_ORIGINS", ""), "The values for allowed cors AllowOrigins header field, separated by comma.") | |||
command.Flags().StringVar(&daemonClientProtocol, "daemon-client-protocol", sharedutil.LookupEnvStringOr("NUMAFLOW_SERVER_DAEMON_CLIENT_PROTOCOL", "grpc"), "The protocol used to connect to the Pipeline daemon service from Numaflow UX server, defaults to 'grpc'.") | |||
command.Flags().StringVar(&prometheusServerUrl, "prometheus-server-url", sharedutil.LookupEnvStringOr("NUMAFLOW_SERVER_PROMETHEUS_URL", ""), "The prometheus server url for querying metrics data.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using args, please mount the configmap as a volume.
@@ -129,6 +129,12 @@ metadata: | |||
name: numaflow-cmd-params-config | |||
--- | |||
apiVersion: v1 | |||
data: null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null?
server/routes/routes.go
Outdated
// Get the time series data for a specific metric. | ||
r.POST("/namespaces/:namespace/pipelines/:pipeline/getMetricData", handler.GetMetricData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we provide a query generic query service which works for any metrics?
Signed-off-by: adarsh0728 <[email protected]>
Signed-off-by: adarsh0728 <[email protected]>
server/apis/v1/response_metrics.go
Outdated
|
||
type PrometheusClient struct { | ||
// prometheus metric config from yaml | ||
ConfigData []map[string]any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Abstract to structs.
server/apis/v1/response_metrics.go
Outdated
// prometheus server url in the config | ||
ServerUrl string `yaml:"url"` | ||
// patterns in the config | ||
Patterns []map[string]any `yaml:"patterns"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Abstract to structs.
server/routes/routes.go
Outdated
@@ -165,6 +165,8 @@ func v1Routes(ctx context.Context, r gin.IRouter, dexObj *v1.DexObject, localUse | |||
r.GET("/namespaces/:namespace/mono-vertices/:mono-vertex/metrics", handler.GetMonoVertexMetrics) | |||
// Get the health information of a mono vertex. | |||
r.GET("/namespaces/:namespace/mono-vertices/:mono-vertex/health", handler.GetMonoVertexHealth) | |||
// Get the time series data for a specific metric. | |||
r.POST("/metricData", handler.GetMetricData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/metrics-proxy
server/cmd/server/start.go
Outdated
@@ -206,5 +206,6 @@ func CreateAuthRouteMap(baseHref string) authz.RouteMap { | |||
"GET:" + baseHref + "api/v1/namespaces/:namespace/mono-vertices/:mono-vertex/metrics": authz.NewRouteInfo(authz.ObjectMonoVertex, true), | |||
"POST:" + baseHref + "api/v1/namespaces/:namespace/mono-vertices": authz.NewRouteInfo(authz.ObjectMonoVertex, true), | |||
"GET:" + baseHref + "api/v1/namespaces/:namespace/mono-vertices/:mono-vertex/health": authz.NewRouteInfo(authz.ObjectMonoVertex, true), | |||
"POST:" + baseHref + "api/v1/metricData": authz.NewRouteInfo(authz.ObjectAll, true), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kohlisid - please review
name: numaflow-metric-server-config | ||
data: | ||
config.yaml: | | ||
url: http://my-release-kube-prometheus-prometheus.default.svc.cluster.local:9090 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Give commented out examples.
… clarity Signed-off-by: adarsh0728 <[email protected]>
Signed-off-by: adarsh0728 <[email protected]>
server/apis/v1/handler.go
Outdated
var fieldsMap = make(map[string]any) | ||
|
||
var ( | ||
requestBody map[string]any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall me abstract the input data into a struct? map[string]any
means no restriction.
server/apis/v1/response_metrics.go
Outdated
"gopkg.in/yaml.v2" | ||
) | ||
|
||
type PrometheusClient struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This struct has no method, maybe there's a better way abstract it?
server/apis/v1/response_metrics.go
Outdated
) | ||
|
||
// read prometheus metric config yaml from volume mount path | ||
data, err = os.ReadFile("/etc/numaflow/metrics/config.yaml") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can make this file path into a constant/config instead of hardcoding.
server/apis/v1/handler.go
Outdated
} | ||
|
||
// get expression for the pattern | ||
expr := pattern.Expression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe don't need this, we are checkingpattern.Expression
directly above as well, can be passed to subMatch directly.
server/apis/v1/handler.go
Outdated
|
||
// find index and pattern from config based on req pattern name | ||
for i, p := range h.prometheusClient.ConfigData { | ||
if p.Name == requestBody["name"] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a case where requestBody["name"]
does not exist?
server/apis/v1/handler.go
Outdated
} | ||
|
||
// throw error if pattern name not found in the config | ||
if index == -1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can directly compare with pattern != nil
right for the case it is not found.
Index might not be required here, I don't see it getting further in the code. Is that correct?
server/apis/v1/handler.go
Outdated
return fmt.Sprintf("%f", v) | ||
case int64: | ||
return fmt.Sprintf("%d", v) | ||
case map[string]any: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is any
allowed? Do we have any specific types that we support?
Signed-off-by: adarsh0728 <[email protected]>
rangeVector: 5m | ||
aggregator: sum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this overridable?
Signed-off-by: adarsh0728 <[email protected]>
I created a feature branch |
Signed-off-by: adarsh0728 <[email protected]>
Signed-off-by: adarsh0728 <[email protected]>
Signed-off-by: adarsh0728 <[email protected]>
Merging this into feature branch. Will create separate PRs for other issues. Once e2e is done, will create a PR into main. |
The PR aims to provide a generic API to run PromQL to fetch metrics for the UI.
The overall goal is to improve debuggability experience for platform and application engineers.