-
Notifications
You must be signed in to change notification settings - Fork 0
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
Prometheus based metrics #1
Comments
Yes, i understood.
But, |
Following middleware, one more idea came to my mind that is, we can have a middleware library that can be plugged into the code. That library can further be extended to provide support for tracing. Additionally, It can expose metrics in various formats to be compatible with different scrapers Metrics:
Tracing:
|
Yes, you're right. I'm thinking of supporting I hope that If you has a good idea. give me? |
I would say put them in Anyone who wants to expose metrics should just add a line to his code and automatically relevant metrics should be exposed on a configurable endpoint What metrics to expose is always a challenge. Starting off with some basic metrics will be a good idea and later more can be added as more people start using it (see envoy metrics for ref) I see you already have something for prometheus, my suggestion is to put these functionalities in that first. Adding more standards should be relatively easy, can be done later. |
I'm with you on that. |
BTW, how is |
For the http router, moreover, When using |
middleware.NewMiddleware("name", priority, func(h interface{}) interface{} {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
// TODO
h.(http.Handler).ServeHTTP(w, r)
// TODO
})
}),
http.DefaultClient = &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)}
middleware.NewMiddleware("otel", 100, func(h interface{}) interface{} {
return otelhttp.NewHandler(h.(http.Handler), "HTTPServerName")
}) So what we only need to do is to install the exporter, for example var defaultResource *resource.Resource
func installPrometheusAsMetricExporter() {
factory := processor.NewFactory(
selector.NewWithHistogramDistribution(),
aggregation.CumulativeTemporalitySelector(),
)
ctrl := controller.New(factory, controller.WithResource(defaultResource))
exporter, err := prometheus.New(prometheus.Config{}, ctrl)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
ruler.DefaultRouter.Path("/metrics").GET(exporter)
global.SetMeterProvider(exporter.MeterProvider())
}
func installJaegerAsTracerExporter() {
exporter, err := jaeger.New(jaeger.WithAgentEndpoint())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
otel.SetTracerProvider(trace.NewTracerProvider(
trace.WithResource(defaultResource),
trace.WithSyncer(exporter),
))
}
func installOpenTelemetryExporter() {
var err error
defaultResource, err = resource.New(context.Background(),
resource.WithAttributes(semconv.ServiceNameKey.String("ServiceName")),
resource.WithFromEnv(),
resource.WithTelemetrySDK(),
resource.WithHost(),
)
if err != nil {
fmt.Println(err)
} else {
defaultResource = resource.Default()
}
installJaegerAsTracerExporter()
installPrometheusAsMetricExporter()
} Here is a complete example. module myapp
require (
github.com/xgfone/go-apiserver v0.18.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.33.0
go.opentelemetry.io/otel v1.8.0
go.opentelemetry.io/otel/exporters/jaeger v1.8.0
go.opentelemetry.io/otel/exporters/prometheus v0.31.0
go.opentelemetry.io/otel/metric v0.31.0
go.opentelemetry.io/otel/sdk v1.8.0
go.opentelemetry.io/otel/sdk/metric v0.31.0
)
go 1.16 package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
// go-apiserver
"github.com/xgfone/go-apiserver/entrypoint"
"github.com/xgfone/go-apiserver/http/reqresp"
"github.com/xgfone/go-apiserver/http/router"
"github.com/xgfone/go-apiserver/http/router/routes/ruler"
"github.com/xgfone/go-apiserver/middleware"
// OpenTelemetry
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/metric/global"
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
selector "go.opentelemetry.io/otel/sdk/metric/selector/simple"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
// ------------------------------------------------------------------------ //
// Install the OpenTelemetry exporter. If not, no metric or tracer data is exported.
var defaultResource *resource.Resource
func installPrometheusAsMetricExporter() {
factory := processor.NewFactory(
selector.NewWithHistogramDistribution(),
aggregation.CumulativeTemporalitySelector(),
)
ctrl := controller.New(factory, controller.WithResource(defaultResource))
exporter, err := prometheus.New(prometheus.Config{}, ctrl)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
ruler.DefaultRouter.Path("/metrics").GET(exporter)
global.SetMeterProvider(exporter.MeterProvider())
}
func installJaegerAsTracerExporter() {
exporter, err := jaeger.New(jaeger.WithAgentEndpoint())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
otel.SetTracerProvider(trace.NewTracerProvider(
trace.WithResource(defaultResource),
trace.WithSyncer(exporter),
))
}
func installOpenTelemetryExporter() {
var err error
defaultResource, err = resource.New(context.Background(),
resource.WithAttributes(semconv.ServiceNameKey.String("ServiceName")),
resource.WithFromEnv(),
resource.WithTelemetrySDK(),
resource.WithHost(),
)
if err != nil {
fmt.Println(err)
} else {
defaultResource = resource.Default()
}
installJaegerAsTracerExporter()
installPrometheusAsMetricExporter()
}
// ------------------------------------------------------------------------ //
// Initialize the HTTP client and server middleware to support OpenTelemetry.
func initHTTPClient(opts ...otelhttp.Option) {
http.DefaultClient = &http.Client{
Transport: otelhttp.NewTransport(http.DefaultTransport, opts...),
}
}
func initHTTPMiddleware() {
router.DefaultRouter.Middlewares.Use(
// Add the middleware to let OpenTelemetry wrap the request to handle metric and tracer.
middleware.NewMiddleware("otel", 100, func(h interface{}) interface{} {
return otelhttp.NewHandler(h.(http.Handler), "HTTPServerName")
}),
// TODO: Add other middlewares...
)
}
func init() {
installOpenTelemetryExporter()
initHTTPClient()
initHTTPMiddleware()
}
func main() {
// Add The routes into the router.
ruler.DefaultRouter.Path("/path1").GET(http.DefaultServeMux)
ruler.DefaultRouter.Path("/path2").GETFunc(func(w http.ResponseWriter, r *http.Request) {
// TODO
})
ruler.DefaultRouter.Path("/path3").GETContext(func(c *reqresp.Context) {
// TODO
})
startHTTPServer("127.0.0.1:80")
}
func startHTTPServer(addr string) {
ep, err := entrypoint.NewEntryPoint("", addr, router.DefaultRouter)
if err != nil {
log.Fatalf("fail to start the http server")
}
go waitSignal(ep.Stop)
ep.Start()
}
func waitSignal(stop func()) {
ch := make(chan os.Signal, 1)
signal.Notify(ch,
os.Interrupt,
syscall.SIGTERM,
syscall.SIGQUIT,
syscall.SIGABRT,
syscall.SIGINT,
)
<-ch
stop()
} |
We have no need to write too codes but installing or initializing the metric and tracer exporters. |
I packages the codes above into the repository |
Awesome man, I will give it a try and will let you know |
Can we have an option to expose prometheus metrics ? Similar to what envoy exposes
You can take a look at them by running envoy server locally. Use below code and commands to have a working envoy routing to a microservice.
Run with:
Visit: localhost:8000/stats/prometheus
envoy.yaml
main.go
The text was updated successfully, but these errors were encountered: