faas/gateway/handlers/notifiers.go
Alex Ellis (OpenFaaS Ltd) 88eea5f62e Feature for probing functions
Introduces a single-flight call to a function's health
endpoint to verify that it is registered with an Istio
sidecar (Envoy) before letting the invocation through.

Results are cached for 5 seconds, before a probe is
required again.

Tested without Istio, with probe_functions environment
variable set to true, I saw a probe execute in the logs.

Fixes: #1721 for Istio users.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alex@openfaas.com>
2022-07-07 10:35:07 +01:00

88 lines
2.5 KiB
Go

package handlers
import (
"fmt"
"log"
"strconv"
"strings"
"time"
"github.com/openfaas/faas/gateway/metrics"
"github.com/openfaas/faas/gateway/pkg/middleware"
"github.com/prometheus/client_golang/prometheus"
)
// HTTPNotifier notify about HTTP request/response
type HTTPNotifier interface {
Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration)
}
// PrometheusServiceNotifier notifier for core service endpoints
type PrometheusServiceNotifier struct {
ServiceMetrics *metrics.ServiceMetricOptions
}
// Notify about service metrics
func (psn PrometheusServiceNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
code := fmt.Sprintf("%d", statusCode)
path := urlToLabel(URL)
psn.ServiceMetrics.Counter.WithLabelValues(method, path, code).Inc()
psn.ServiceMetrics.Histogram.WithLabelValues(method, path, code).Observe(duration.Seconds())
}
func urlToLabel(path string) string {
if len(path) > 0 {
path = strings.TrimRight(path, "/")
}
if path == "" {
path = "/"
}
return path
}
// PrometheusFunctionNotifier records metrics to Prometheus
type PrometheusFunctionNotifier struct {
Metrics *metrics.MetricOptions
//FunctionNamespace default namespace of the function
FunctionNamespace string
}
// Notify records metrics in Prometheus
func (p PrometheusFunctionNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
serviceName := middleware.GetServiceName(originalURL)
if len(p.FunctionNamespace) > 0 {
if !strings.Contains(serviceName, ".") {
serviceName = fmt.Sprintf("%s.%s", serviceName, p.FunctionNamespace)
}
}
code := strconv.Itoa(statusCode)
labels := prometheus.Labels{"function_name": serviceName, "code": code}
if event == "completed" {
seconds := duration.Seconds()
p.Metrics.GatewayFunctionsHistogram.
With(labels).
Observe(seconds)
p.Metrics.GatewayFunctionInvocation.
With(labels).
Inc()
} else if event == "started" {
p.Metrics.GatewayFunctionInvocationStarted.WithLabelValues(serviceName).Inc()
}
}
// LoggingNotifier notifies a log about a request
type LoggingNotifier struct {
}
// Notify the LoggingNotifier about a request
func (LoggingNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
if event == "completed" {
log.Printf("Forwarded [%s] to %s - [%d] - %fs seconds", method, originalURL, statusCode, duration.Seconds())
}
}