mirror of
https://github.com/openfaas/faas.git
synced 2025-06-09 00:36:46 +00:00
Record metrics for invocations when they start
* This experimental patch records metrics as invocations start so that the metrics can be used to make better scale to zero decisions in faas-idler. Tested with Kubernetes on a single-node cluster, metrics reported as expected. Existing metrics still report. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
This commit is contained in:
parent
1eea381dd5
commit
96812d2cd8
@ -28,7 +28,7 @@ COPY queue queue
|
|||||||
COPY plugin plugin
|
COPY plugin plugin
|
||||||
COPY version version
|
COPY version version
|
||||||
COPY scaling scaling
|
COPY scaling scaling
|
||||||
COPY server.go .
|
COPY main.go .
|
||||||
|
|
||||||
# Run a gofmt and exclude all vendored code.
|
# Run a gofmt and exclude all vendored code.
|
||||||
RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Authors" "OpenFaaS Author(s)" \
|
RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Authors" "OpenFaaS Author(s)" \
|
||||||
|
@ -25,7 +25,7 @@ COPY queue queue
|
|||||||
COPY plugin plugin
|
COPY plugin plugin
|
||||||
COPY version version
|
COPY version version
|
||||||
COPY scaling scaling
|
COPY scaling scaling
|
||||||
COPY server.go .
|
COPY main.go .
|
||||||
|
|
||||||
# Run a gofmt and exclude all vendored code.
|
# Run a gofmt and exclude all vendored code.
|
||||||
RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Project" "OpenFaaS Authors" "OpenFaaS Author(s)" \
|
RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Project" "OpenFaaS Authors" "OpenFaaS Author(s)" \
|
||||||
|
@ -25,7 +25,7 @@ COPY queue queue
|
|||||||
COPY plugin plugin
|
COPY plugin plugin
|
||||||
COPY version version
|
COPY version version
|
||||||
COPY scaling scaling
|
COPY scaling scaling
|
||||||
COPY server.go .
|
COPY main.go .
|
||||||
|
|
||||||
# Run a gofmt and exclude all vendored code.
|
# Run a gofmt and exclude all vendored code.
|
||||||
RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Project" "OpenFaaS Authors" "OpenFaaS Author(s)" \
|
RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Project" "OpenFaaS Authors" "OpenFaaS Author(s)" \
|
||||||
|
@ -53,9 +53,12 @@ func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy,
|
|||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
baseURL := baseURLResolver.Resolve(r)
|
baseURL := baseURLResolver.Resolve(r)
|
||||||
originalURL := r.URL.String()
|
originalURL := r.URL.String()
|
||||||
|
|
||||||
requestURL := urlPathTransformer.Transform(r)
|
requestURL := urlPathTransformer.Transform(r)
|
||||||
|
|
||||||
|
for _, notifier := range notifiers {
|
||||||
|
notifier.Notify(r.Method, requestURL, originalURL, http.StatusProcessing, "started", time.Second*0)
|
||||||
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
statusCode, err := forwardRequest(w, r, proxy.Client, baseURL, requestURL, proxy.Timeout, writeRequestURI, serviceAuthInjector)
|
statusCode, err := forwardRequest(w, r, proxy.Client, baseURL, requestURL, proxy.Timeout, writeRequestURI, serviceAuthInjector)
|
||||||
@ -66,7 +69,7 @@ func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.Notify(r.Method, requestURL, originalURL, statusCode, seconds)
|
notifier.Notify(r.Method, requestURL, originalURL, statusCode, "completed", seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ func MakeNotifierWrapper(next http.HandlerFunc, notifiers []HTTPNotifier) http.H
|
|||||||
|
|
||||||
url := r.URL.String()
|
url := r.URL.String()
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.Notify(r.Method, url, url, writer.Status(), time.Since(then))
|
notifier.Notify(r.Method, url, url, writer.Status(), "completed", time.Since(then))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,6 @@ type testNotifier struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify about service metrics
|
// Notify about service metrics
|
||||||
func (tf *testNotifier) Notify(method string, URL string, originalURL string, statusCode int, duration time.Duration) {
|
func (tf *testNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||||
tf.StatusReceived = statusCode
|
tf.StatusReceived = statusCode
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
// HTTPNotifier notify about HTTP request/response
|
// HTTPNotifier notify about HTTP request/response
|
||||||
type HTTPNotifier interface {
|
type HTTPNotifier interface {
|
||||||
Notify(method string, URL string, originalURL string, statusCode int, duration time.Duration)
|
Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrometheusServiceNotifier notifier for core service endpoints
|
// PrometheusServiceNotifier notifier for core service endpoints
|
||||||
@ -22,7 +22,7 @@ type PrometheusServiceNotifier struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify about service metrics
|
// Notify about service metrics
|
||||||
func (psn PrometheusServiceNotifier) Notify(method string, URL string, originalURL string, statusCode int, duration time.Duration) {
|
func (psn PrometheusServiceNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||||
code := fmt.Sprintf("%d", statusCode)
|
code := fmt.Sprintf("%d", statusCode)
|
||||||
path := urlToLabel(URL)
|
path := urlToLabel(URL)
|
||||||
|
|
||||||
@ -46,19 +46,26 @@ type PrometheusFunctionNotifier struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify records metrics in Prometheus
|
// Notify records metrics in Prometheus
|
||||||
func (p PrometheusFunctionNotifier) Notify(method string, URL string, originalURL string, statusCode int, duration time.Duration) {
|
func (p PrometheusFunctionNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||||
seconds := duration.Seconds()
|
if event == "completed" {
|
||||||
serviceName := getServiceName(originalURL)
|
|
||||||
|
|
||||||
p.Metrics.GatewayFunctionsHistogram.
|
seconds := duration.Seconds()
|
||||||
WithLabelValues(serviceName).
|
serviceName := getServiceName(originalURL)
|
||||||
Observe(seconds)
|
|
||||||
|
|
||||||
code := strconv.Itoa(statusCode)
|
p.Metrics.GatewayFunctionsHistogram.
|
||||||
|
WithLabelValues(serviceName).
|
||||||
|
Observe(seconds)
|
||||||
|
|
||||||
|
code := strconv.Itoa(statusCode)
|
||||||
|
|
||||||
|
p.Metrics.GatewayFunctionInvocation.
|
||||||
|
With(prometheus.Labels{"function_name": serviceName, "code": code}).
|
||||||
|
Inc()
|
||||||
|
} else if event == "started" {
|
||||||
|
serviceName := getServiceName(originalURL)
|
||||||
|
p.Metrics.StartedCounter.WithLabelValues(serviceName).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
p.Metrics.GatewayFunctionInvocation.
|
|
||||||
With(prometheus.Labels{"function_name": serviceName, "code": code}).
|
|
||||||
Inc()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServiceName(urlValue string) string {
|
func getServiceName(urlValue string) string {
|
||||||
@ -83,7 +90,9 @@ func getServiceName(urlValue string) string {
|
|||||||
type LoggingNotifier struct {
|
type LoggingNotifier struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify a log about a request
|
// Notify the LoggingNotifier about a request
|
||||||
func (LoggingNotifier) Notify(method string, URL string, originalURL string, statusCode int, duration time.Duration) {
|
func (LoggingNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||||
log.Printf("Forwarded [%s] to %s - [%d] - %fs", method, originalURL, statusCode, duration.Seconds())
|
if event == "completed" {
|
||||||
|
log.Printf("Forwarded [%s] to %s - [%d] - %fs seconds", method, originalURL, statusCode, duration.Seconds())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
|||||||
e.metricOptions.GatewayFunctionInvocation.Describe(ch)
|
e.metricOptions.GatewayFunctionInvocation.Describe(ch)
|
||||||
e.metricOptions.GatewayFunctionsHistogram.Describe(ch)
|
e.metricOptions.GatewayFunctionsHistogram.Describe(ch)
|
||||||
e.metricOptions.ServiceReplicasGauge.Describe(ch)
|
e.metricOptions.ServiceReplicasGauge.Describe(ch)
|
||||||
|
e.metricOptions.StartedCounter.Describe(ch)
|
||||||
|
|
||||||
e.metricOptions.ServiceMetrics.Counter.Describe(ch)
|
e.metricOptions.ServiceMetrics.Counter.Describe(ch)
|
||||||
e.metricOptions.ServiceMetrics.Histogram.Describe(ch)
|
e.metricOptions.ServiceMetrics.Histogram.Describe(ch)
|
||||||
@ -51,6 +52,8 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|||||||
e.metricOptions.GatewayFunctionInvocation.Collect(ch)
|
e.metricOptions.GatewayFunctionInvocation.Collect(ch)
|
||||||
e.metricOptions.GatewayFunctionsHistogram.Collect(ch)
|
e.metricOptions.GatewayFunctionsHistogram.Collect(ch)
|
||||||
|
|
||||||
|
e.metricOptions.StartedCounter.Collect(ch)
|
||||||
|
|
||||||
e.metricOptions.ServiceReplicasGauge.Reset()
|
e.metricOptions.ServiceReplicasGauge.Reset()
|
||||||
for _, service := range e.services {
|
for _, service := range e.services {
|
||||||
e.metricOptions.ServiceReplicasGauge.
|
e.metricOptions.ServiceReplicasGauge.
|
||||||
|
@ -17,6 +17,7 @@ type MetricOptions struct {
|
|||||||
GatewayFunctionsHistogram *prometheus.HistogramVec
|
GatewayFunctionsHistogram *prometheus.HistogramVec
|
||||||
ServiceReplicasGauge *prometheus.GaugeVec
|
ServiceReplicasGauge *prometheus.GaugeVec
|
||||||
ServiceMetrics *ServiceMetricOptions
|
ServiceMetrics *ServiceMetricOptions
|
||||||
|
StartedCounter *prometheus.CounterVec
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceMetricOptions provides RED metrics
|
// ServiceMetricOptions provides RED metrics
|
||||||
@ -81,6 +82,16 @@ func BuildMetricsOptions() MetricOptions {
|
|||||||
[]string{"method", "path", "status"},
|
[]string{"method", "path", "status"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
startedCounter := prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Namespace: "gateway",
|
||||||
|
Subsystem: "function",
|
||||||
|
Name: "invocation_started",
|
||||||
|
Help: "The total number of function HTTP requests started.",
|
||||||
|
},
|
||||||
|
[]string{"function_name"},
|
||||||
|
)
|
||||||
|
|
||||||
serviceMetricOptions := &ServiceMetricOptions{
|
serviceMetricOptions := &ServiceMetricOptions{
|
||||||
Counter: counter,
|
Counter: counter,
|
||||||
Histogram: histogram,
|
Histogram: histogram,
|
||||||
@ -91,6 +102,7 @@ func BuildMetricsOptions() MetricOptions {
|
|||||||
GatewayFunctionInvocation: gatewayFunctionInvocation,
|
GatewayFunctionInvocation: gatewayFunctionInvocation,
|
||||||
ServiceReplicasGauge: serviceReplicas,
|
ServiceReplicasGauge: serviceReplicas,
|
||||||
ServiceMetrics: serviceMetricOptions,
|
ServiceMetrics: serviceMetricOptions,
|
||||||
|
StartedCounter: startedCounter,
|
||||||
}
|
}
|
||||||
|
|
||||||
return metricsOptions
|
return metricsOptions
|
||||||
|
2
gateway/vendor/github.com/gorilla/mux/go.mod
generated
vendored
2
gateway/vendor/github.com/gorilla/mux/go.mod
generated
vendored
@ -1 +1,3 @@
|
|||||||
module github.com/gorilla/mux
|
module github.com/gorilla/mux
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
Loading…
x
Reference in New Issue
Block a user