Skip to content

Commit

Permalink
Merge pull request prometheus#774 from prometheus/fabxc/api-v1
Browse files Browse the repository at this point in the history
Initial API v1 implementation
  • Loading branch information
fabxc committed Jun 8, 2015
2 parents 8d8de7a + 5b71391 commit ae01a53
Show file tree
Hide file tree
Showing 11 changed files with 553 additions and 35 deletions.
13 changes: 10 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ import (
"github.com/prometheus/prometheus/storage/remote/influxdb"
"github.com/prometheus/prometheus/storage/remote/opentsdb"
"github.com/prometheus/prometheus/web"
"github.com/prometheus/prometheus/web/api"
"github.com/prometheus/prometheus/web/api/legacy"
"github.com/prometheus/prometheus/web/api/v1"
)

const deletionBatchSize = 100
Expand Down Expand Up @@ -184,16 +185,22 @@ func NewPrometheus() *prometheus {
PathPrefix: *pathPrefix,
}

metricsService := &api.MetricsService{
apiLegacy := &legacy.API{
Now: clientmodel.Now,
Storage: memStorage,
QueryEngine: queryEngine,
}

apiv1 := &v1.API{
Storage: memStorage,
QueryEngine: queryEngine,
}

webService := web.NewWebService(&web.WebServiceOptions{
PathPrefix: *pathPrefix,
StatusHandler: prometheusStatus,
MetricsHandler: metricsService,
APILegacy: apiLegacy,
APIv1: apiv1,
ConsolesHandler: consolesHandler,
AlertsHandler: alertsHandler,
GraphsHandler: graphsHandler,
Expand Down
12 changes: 7 additions & 5 deletions promql/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,8 @@ func lexNumberOrDuration(l *lexer) stateFn {
// not necessarily a valid number. This case is caught by the parser.
func (l *lexer) scanNumber() bool {
digits := "0123456789"
if l.accept("0") && l.accept("xX") {
// Disallow hexadecimal in series descriptions as the syntax is ambiguous.
if !l.seriesDesc && l.accept("0") && l.accept("xX") {
digits = "0123456789abcdefABCDEF"
}
l.acceptRun(digits)
Expand All @@ -677,11 +678,12 @@ func (l *lexer) scanNumber() bool {
l.accept("+-")
l.acceptRun("0123456789")
}
// Next thing must not be alphanumeric.
if isAlphaNumeric(l.peek()) && !l.seriesDesc {
return false
// Next thing must not be alphanumeric unless it's the times token
// for series repetitions.
if r := l.peek(); (l.seriesDesc && r == 'x') || !isAlphaNumeric(r) {
return true
}
return true
return false
}

// lexIdentifier scans an alphanumeric identifier. The next character
Expand Down
7 changes: 7 additions & 0 deletions promql/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,13 @@ var testSeries = []struct {
"a": "b",
},
expectedValues: newSeq(1, 2, 3, -7, -17, -27, -37),
}, {
input: `my_metric{a="b"} 1 2 3-0x4`,
expectedMetric: clientmodel.Metric{
clientmodel.MetricNameLabel: "my_metric",
"a": "b",
},
expectedValues: newSeq(1, 2, 3, 3, 3, 3, 3),
}, {
input: `my_metric{a="b"} 1 3 _ 5 _x4`,
expectedMetric: clientmodel.Metric{
Expand Down
10 changes: 10 additions & 0 deletions promql/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ func NewTestFromFile(t testutil.T, filename string) (*Test, error) {
return NewTest(t, string(content))
}

// QueryEngine returns the test's query engine.
func (t *Test) QueryEngine() *Engine {
return t.queryEngine
}

// Storage returns the test's storage.
func (t *Test) Storage() local.Storage {
return t.storage
}

func raise(line int, format string, v ...interface{}) error {
return &ParseErr{
Line: line + 1,
Expand Down
14 changes: 7 additions & 7 deletions web/api/api.go → web/api/legacy/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package api
package legacy

import (
"net/http"
Expand All @@ -26,18 +26,18 @@ import (
"github.com/prometheus/prometheus/util/route"
)

// MetricsService manages the /api HTTP endpoint.
type MetricsService struct {
// API manages the /api HTTP endpoint.
type API struct {
Now func() clientmodel.Timestamp
Storage local.Storage
QueryEngine *promql.Engine
}

// RegisterHandler registers the handler for the various endpoints below /api.
func (msrv *MetricsService) RegisterHandler(router *route.Router) {
router.Get("/query", handle("query", msrv.Query))
router.Get("/query_range", handle("query_range", msrv.QueryRange))
router.Get("/metrics", handle("metrics", msrv.Metrics))
func (api *API) Register(router *route.Router) {
router.Get("/query", handle("query", api.Query))
router.Get("/query_range", handle("query_range", api.QueryRange))
router.Get("/metrics", handle("metrics", api.Metrics))
}

func handle(name string, f http.HandlerFunc) http.HandlerFunc {
Expand Down
6 changes: 3 additions & 3 deletions web/api/api_test.go → web/api/legacy/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package api
package legacy

import (
"io/ioutil"
Expand Down Expand Up @@ -93,13 +93,13 @@ func TestQuery(t *testing.T) {
})
storage.WaitForIndexing()

api := MetricsService{
api := &API{
Now: testNow,
Storage: storage,
QueryEngine: promql.NewEngine(storage),
}
rtr := route.New()
api.RegisterHandler(rtr.WithPrefix("/api"))
api.Register(rtr.WithPrefix("/api"))

server := httptest.NewServer(rtr)
defer server.Close()
Expand Down
20 changes: 10 additions & 10 deletions web/api/query.go → web/api/legacy/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package api
package legacy

import (
"encoding/json"
Expand Down Expand Up @@ -63,20 +63,20 @@ func parseDuration(d string) (time.Duration, error) {
}

// Query handles the /api/query endpoint.
func (serv MetricsService) Query(w http.ResponseWriter, r *http.Request) {
func (api *API) Query(w http.ResponseWriter, r *http.Request) {
setAccessControlHeaders(w)
w.Header().Set("Content-Type", "application/json")

params := httputil.GetQueryParams(r)
expr := params.Get("expr")

timestamp, err := parseTimestampOrNow(params.Get("timestamp"), serv.Now())
timestamp, err := parseTimestampOrNow(params.Get("timestamp"), api.Now())
if err != nil {
httpJSONError(w, fmt.Errorf("invalid query timestamp %s", err), http.StatusBadRequest)
return
}

query, err := serv.QueryEngine.NewInstantQuery(expr, timestamp)
query, err := api.QueryEngine.NewInstantQuery(expr, timestamp)
if err != nil {
httpJSONError(w, err, http.StatusOK)
return
Expand All @@ -92,7 +92,7 @@ func (serv MetricsService) Query(w http.ResponseWriter, r *http.Request) {
}

// QueryRange handles the /api/query_range endpoint.
func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
func (api *API) QueryRange(w http.ResponseWriter, r *http.Request) {
setAccessControlHeaders(w)
w.Header().Set("Content-Type", "application/json")

Expand All @@ -111,7 +111,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
return
}

end, err := parseTimestampOrNow(params.Get("end"), serv.Now())
end, err := parseTimestampOrNow(params.Get("end"), api.Now())
if err != nil {
httpJSONError(w, fmt.Errorf("invalid query timestamp: %s", err), http.StatusBadRequest)
return
Expand All @@ -121,7 +121,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
// the current time as the end time. Instead, the "end" parameter should
// simply be omitted or set to an empty string for that case.
if end == 0 {
end = serv.Now()
end = api.Now()
}

// For safety, limit the number of returned points per timeseries.
Expand All @@ -136,7 +136,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
end = end.Add(-time.Duration(end.UnixNano() % int64(step)))
start := end.Add(-duration)

query, err := serv.QueryEngine.NewRangeQuery(expr, start, end, step)
query, err := api.QueryEngine.NewRangeQuery(expr, start, end, step)
if err != nil {
httpJSONError(w, err, http.StatusOK)
return
Expand All @@ -152,11 +152,11 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
}

// Metrics handles the /api/metrics endpoint.
func (serv MetricsService) Metrics(w http.ResponseWriter, r *http.Request) {
func (api *API) Metrics(w http.ResponseWriter, r *http.Request) {
setAccessControlHeaders(w)
w.Header().Set("Content-Type", "application/json")

metricNames := serv.Storage.LabelValuesForLabelName(clientmodel.MetricNameLabel)
metricNames := api.Storage.LabelValuesForLabelName(clientmodel.MetricNameLabel)
sort.Sort(metricNames)
resultBytes, err := json.Marshal(metricNames)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion web/api/query_test.go → web/api/legacy/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package api
package legacy

import (
"testing"
Expand Down
Loading

0 comments on commit ae01a53

Please sign in to comment.