mirror of
https://github.com/3ybactuk/marketplace-go-service-project.git
synced 2025-10-30 14:03:45 +03:00
[hw-7] add metrics, tracing
This commit is contained in:
31
loms/internal/infra/grpc/metrics/db.go
Normal file
31
loms/internal/infra/grpc/metrics/db.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
dbQueryCounter = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: "app",
|
||||
Name: "db_queries_total",
|
||||
Help: "Total DB queries",
|
||||
}, []string{"category", "error"})
|
||||
|
||||
dbQueryDurationHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: "app",
|
||||
Name: "db_query_duration_seconds",
|
||||
Help: "Latency of DB queries, seconds",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"category", "error"})
|
||||
)
|
||||
|
||||
func IncDBQueryCount(cat, errLabel string) {
|
||||
dbQueryCounter.WithLabelValues(cat, errLabel).Inc()
|
||||
}
|
||||
|
||||
func StoreDBQueryDuration(cat, errLabel string, d time.Duration) {
|
||||
dbQueryDurationHistogram.WithLabelValues(cat, errLabel).Observe(d.Seconds())
|
||||
}
|
||||
31
loms/internal/infra/grpc/metrics/metrics.go
Normal file
31
loms/internal/infra/grpc/metrics/metrics.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
requestCounter = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: "app",
|
||||
Name: "requests_total",
|
||||
Help: "Total amount of request by handler",
|
||||
}, []string{"method", "path", "status_code"})
|
||||
|
||||
requestDurationHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: "app",
|
||||
Name: "request_duration_seconds",
|
||||
Help: "Latency of handler processing, seconds",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"method", "path", "status_code"})
|
||||
)
|
||||
|
||||
func IncRequestHandlerCount(method, path, statusCode string) {
|
||||
requestCounter.WithLabelValues(method, path, statusCode).Inc()
|
||||
}
|
||||
|
||||
func StoreHandlerRequestDuration(method, path, statusCode string, d time.Duration) {
|
||||
requestDurationHistogram.WithLabelValues(method, path, statusCode).Observe(d.Seconds())
|
||||
}
|
||||
43
loms/internal/infra/grpc/middleware/metrics.go
Normal file
43
loms/internal/infra/grpc/middleware/metrics.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package mw
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"route256/loms/internal/infra/grpc/metrics"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const UNKNOWN = "unknown"
|
||||
|
||||
func WithMetrics(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
|
||||
start := time.Now()
|
||||
|
||||
resp, err = handler(ctx, req)
|
||||
|
||||
// "/pkg.Service/Method"
|
||||
service, method := parseFullMethod(info.FullMethod)
|
||||
|
||||
code := status.Code(err).String()
|
||||
|
||||
metrics.IncRequestHandlerCount(service, method, code)
|
||||
metrics.StoreHandlerRequestDuration(service, method, code, time.Since(start))
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func parseFullMethod(full string) (service, method string) {
|
||||
if full == "" {
|
||||
return UNKNOWN, UNKNOWN
|
||||
}
|
||||
full = strings.TrimPrefix(full, "/")
|
||||
|
||||
slash := strings.Index(full, "/")
|
||||
if slash < 0 {
|
||||
return full, UNKNOWN
|
||||
}
|
||||
return full[:slash], full[slash+1:]
|
||||
}
|
||||
38
loms/internal/infra/grpc/middleware/tracing.go
Normal file
38
loms/internal/infra/grpc/middleware/tracing.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package mw
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"route256/loms/internal/infra/tracing"
|
||||
)
|
||||
|
||||
func WithTracing(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
service, method := splitFullMethod(info.FullMethod)
|
||||
ctx, span := tracing.Tracer().Start(ctx, service+"/"+method)
|
||||
defer span.End()
|
||||
|
||||
resp, err := handler(ctx, req)
|
||||
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, status.Convert(err).Message())
|
||||
} else {
|
||||
span.SetStatus(codes.Ok, "OK")
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func splitFullMethod(full string) (service, method string) {
|
||||
full = strings.TrimPrefix(full, "/")
|
||||
if i := strings.Index(full, "/"); i >= 0 {
|
||||
return full[:i], full[i+1:]
|
||||
}
|
||||
|
||||
return "unknown", full
|
||||
}
|
||||
Reference in New Issue
Block a user