-
Notifications
You must be signed in to change notification settings - Fork 453
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
Prom read instant handler refactoring #2928
Changes from all commits
7f94c66
6adad32
c6f43b2
c70d0f5
1031323
4dc973a
362a55d
ae5110d
b12752a
fbec087
a50265a
2314219
7db2913
12e7353
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,7 +53,8 @@ const ( | |
|
||
type errorType string | ||
|
||
type queryData struct { | ||
// QueryData struct to be used when responding from HTTP handler. | ||
type QueryData struct { | ||
ResultType promql.ValueType `json:"resultType"` | ||
Result promql.Value `json:"result"` | ||
} | ||
|
@@ -66,7 +67,8 @@ type response struct { | |
Warnings []string `json:"warnings,omitempty"` | ||
} | ||
|
||
func respond(w http.ResponseWriter, data interface{}, warnings promstorage.Warnings) { | ||
// Responds with HTTP OK status code and writes response JSON to response body. | ||
func Respond(w http.ResponseWriter, data interface{}, warnings promstorage.Warnings) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Need to add comment to exported types |
||
statusMessage := statusSuccess | ||
var warningStrings []string | ||
for _, warning := range warnings { | ||
|
@@ -88,7 +90,8 @@ func respond(w http.ResponseWriter, data interface{}, warnings promstorage.Warni | |
w.Write(b) | ||
} | ||
|
||
func respondError(w http.ResponseWriter, err error) { | ||
// Responds with error status code and writes error JSON to response body. | ||
func RespondError(w http.ResponseWriter, err error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Need to add comment to exported types |
||
json := jsoniter.ConfigCompatibleWithStandardLibrary | ||
b, marshalErr := json.Marshal(&response{ | ||
Status: statusError, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,8 +24,11 @@ import ( | |
"net/http" | ||
"time" | ||
|
||
promstorage "github.com/prometheus/prometheus/storage" | ||
|
||
"github.com/m3db/m3/src/query/api/v1/options" | ||
"github.com/m3db/m3/src/query/block" | ||
"github.com/m3db/m3/src/query/graphite/errors" | ||
"github.com/m3db/m3/src/query/storage/prometheus" | ||
|
||
"github.com/prometheus/prometheus/promql" | ||
|
@@ -38,29 +41,65 @@ func init() { | |
promql.SetDefaultEvaluationInterval(time.Minute) | ||
} | ||
|
||
// Options defines options for PromQL handler. | ||
type Options struct { | ||
PromQLEngine *promql.Engine | ||
// opts defines options for PromQL handler. | ||
type opts struct { | ||
promQLEngine *promql.Engine | ||
instant bool | ||
queryable promstorage.Queryable | ||
newQueryFn NewQueryFn | ||
} | ||
|
||
// NewReadHandler creates a handler to handle PromQL requests. | ||
func NewReadHandler(opts Options, hOpts options.HandlerOptions) http.Handler { | ||
queryable := prometheus.NewPrometheusQueryable( | ||
prometheus.PrometheusOptions{ | ||
Storage: hOpts.Storage(), | ||
InstrumentOptions: hOpts.InstrumentOpts(), | ||
}) | ||
return newReadHandler(opts, hOpts, queryable) | ||
// Option is a Prometheus handler option. | ||
type Option func(*opts) error | ||
|
||
// WithEngine sets the PromQL engine. | ||
func WithEngine(promQLEngine *promql.Engine) Option { | ||
return withEngine(promQLEngine, false) | ||
} | ||
|
||
// WithInstantEngine sets the PromQL instant engine. | ||
func WithInstantEngine(promQLEngine *promql.Engine) Option { | ||
return withEngine(promQLEngine, true) | ||
} | ||
|
||
func withEngine(promQLEngine *promql.Engine, instant bool) Option { | ||
return func(o *opts) error { | ||
if promQLEngine == nil { | ||
return errors.New("invalid engine") | ||
} | ||
o.instant = instant | ||
o.promQLEngine = promQLEngine | ||
o.newQueryFn = newRangeQueryFn(promQLEngine, o.queryable) | ||
if instant { | ||
o.newQueryFn = newInstantQueryFn(promQLEngine, o.queryable) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
// NewReadInstantHandler creates a handler to handle PromQL requests. | ||
func NewReadInstantHandler(opts Options, hOpts options.HandlerOptions) http.Handler { | ||
func newDefaultOptions(hOpts options.HandlerOptions) opts { | ||
queryable := prometheus.NewPrometheusQueryable( | ||
prometheus.PrometheusOptions{ | ||
Storage: hOpts.Storage(), | ||
InstrumentOptions: hOpts.InstrumentOpts(), | ||
}) | ||
return newReadInstantHandler(opts, hOpts, queryable) | ||
return opts{ | ||
promQLEngine: hOpts.PrometheusEngine(), | ||
queryable: queryable, | ||
instant: false, | ||
newQueryFn: newRangeQueryFn(hOpts.PrometheusEngine(), queryable), | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're going to do parameterized options for this change, we can simplify this a bit (also note the type opts struct {
promQLEngine *promql.Engine
instant bool
newQueryFn NewQueryFn
}
func newDefaultOptions(hOpts options.HandlerOptions) opts {
return opts{
promQLEngine: hOpts.PrometheusEngine(),
instant: false,
newQueryFn: newRangeQueryFn,
}
}
// Option is a Prometheus handler option.
type Option func(*opts)
// WithEngine sets the PromQL engine.
func WithEngine(promQLEngine *promql.Engine) Option {
return withEngine(promQLEngine, false)
}
// WithInstantEngine sets the PromQL instant engine.
func WithInstantEngine(promQLEngine *promql.Engine) Option {
return withEngine(promQLEngine, true)
}
func withEngine(promQLEngine *promql.Engine, instant bool) Option {
return func(o *opts) error {
if promQLEngine == nil {
return errors.New("invalid engine")
}
o.instant = instant
o.promQLEngine = promQLEngine
o.newQueryFn = newRangeQueryFn
if instant {
o.newQueryFn = newInstantQueryFn
}
return nil
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks much simpler to me 👍🏻 |
||
} | ||
|
||
// NewReadHandler creates a handler to handle PromQL requests. | ||
func NewReadHandler(hOpts options.HandlerOptions, options ...Option) (http.Handler, error) { | ||
opts := newDefaultOptions(hOpts) | ||
for _, optionFn := range options { | ||
if err := optionFn(&opts); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return newReadHandler(hOpts, opts) | ||
} | ||
|
||
// ApplyRangeWarnings applies warnings encountered during execution. | ||
|
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.
To me, it doesn't look like
queryData
needs to be public, at least in the scope of this PR (ditto forRespond
andRespondError
). Am I missing something?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.
Since we can now override default handlers, we might need these for such use-cases.
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.
I think we should take a bit more care when exposing things. For example, there seems to be a duplicate of this struct in
prometheus/response.go
, which doesn't surface types from prometheus repository. Maybe we should pick one of those to be public, and not both?m3/src/query/api/v1/handler/prometheus/response.go
Lines 40 to 69 in 2bcd6fd
Similar question with
Respond
andRespondError
– are these the methods we want to have exposed? Aren't there better candidates?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.
response
is not made public in this PR so no changes there.As for
Respond
andRespondError
, I don't think exposing them would make any harm. They do not belong to any class and could be reused by custom handlers without a need to copy the same code (as we are currently doing in our private codebase).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.
nit: Need to add comment to exported types
// QueryData is ...
.