TP-44002 | Created metric middleware, publishing API metrics. Added support for Custom metrics. (#233)
This commit is contained in:
@@ -9,10 +9,10 @@ import (
|
||||
"houston/cmd/app/handler"
|
||||
"houston/internal/clients"
|
||||
"houston/internal/metrics"
|
||||
"houston/model/ingester"
|
||||
"houston/pkg/slackbot"
|
||||
"houston/service"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -35,6 +35,7 @@ func NewServer(gin *gin.Engine, logger *zap.Logger, db *gorm.DB, mjolnirClient *
|
||||
|
||||
func (s *Server) Handler(houstonGroup *gin.RouterGroup) {
|
||||
s.readinessHandler(houstonGroup)
|
||||
s.gin.Use(s.metricMiddleware())
|
||||
s.incidentClientHandler(houstonGroup)
|
||||
s.incidentClientHandlerV2(houstonGroup)
|
||||
s.filtersHandlerV2(houstonGroup)
|
||||
@@ -184,6 +185,27 @@ func (s *Server) Start() {
|
||||
s.gin.Run(fmt.Sprintf(":%v", "8080"))
|
||||
}
|
||||
|
||||
func (s *Server) metricMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
c.Next()
|
||||
endTime := time.Now()
|
||||
duration := endTime.Sub(startTime)
|
||||
|
||||
metricsPublisher := metrics.NewMetricPublisher()
|
||||
apiMetrics := ingester.ApiMetric{
|
||||
Url: c.Request.URL.Path,
|
||||
Method: c.Request.Method,
|
||||
ResponseCode: c.Writer.Status(),
|
||||
StartTime: startTime.Unix(),
|
||||
EndTime: endTime.Unix(),
|
||||
DurationInMs: duration.Milliseconds(),
|
||||
BytesSent: c.Writer.Size(),
|
||||
}
|
||||
metricsPublisher.PublishMetrics(ingester.MetricAttributes{ApiMetric: apiMetrics}, ingester.API_METRICS)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) createMiddleware() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
@@ -213,17 +235,6 @@ func (s *Server) createMiddleware() gin.HandlerFunc {
|
||||
c.AbortWithStatus(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
c.Next()
|
||||
endTime := float64(time.Since(startTime))
|
||||
|
||||
//metrics publishing
|
||||
status := strconv.Itoa(c.Writer.Status())
|
||||
metrics.HoustonApiRequestCounter.WithLabelValues(c.Request.URL.Path, c.Request.Method, status).Inc()
|
||||
metrics.HoustonApiRequestLatencySum.WithLabelValues(c.Request.URL.Path, c.Request.Method, status).Add(endTime)
|
||||
metrics.HoustonApiRequestLatencyHistogram.WithLabelValues(c.Request.URL.Path, c.Request.Method, status).Observe(endTime)
|
||||
metrics.HoustonApiRequestLatencySummary.WithLabelValues(c.Request.URL.Path, c.Request.Method, status).Observe(endTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"houston/cmd/app"
|
||||
"houston/config"
|
||||
"houston/internal/clients"
|
||||
"houston/log"
|
||||
"houston/pkg/postgres"
|
||||
"os"
|
||||
"time"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.InitLogger()
|
||||
logger, _ := zap.NewProduction()
|
||||
config.LoadHoustonConfig(logger)
|
||||
godotenv.Load()
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func JsonToStruct[JsonObject any, Struct any](obj JsonObject, result *Struct) error {
|
||||
func Convert[T any, V any](obj T, result *V) error {
|
||||
messageBytes, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
2
go.mod
2
go.mod
@@ -11,6 +11,7 @@ require (
|
||||
github.com/gin-contrib/zap v0.1.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/jackc/pgx/v5 v5.3.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/slack-go/slack v0.12.1
|
||||
@@ -80,7 +81,6 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.3.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
||||
51
internal/metrics/metric_publisher.go
Normal file
51
internal/metrics/metric_publisher.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"houston/log"
|
||||
"houston/model/ingester"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Publisher interface {
|
||||
PublishMetrics(metricAttributes map[string]interface{}, metricType ingester.MetricType)
|
||||
}
|
||||
|
||||
type PublisherImpl struct {
|
||||
}
|
||||
|
||||
func NewMetricPublisher() *PublisherImpl {
|
||||
return &PublisherImpl{}
|
||||
}
|
||||
|
||||
func (amp *PublisherImpl) PublishMetrics(metricAttributes ingester.MetricAttributes, metricType ingester.MetricType) {
|
||||
switch metricType {
|
||||
case ingester.API_METRICS:
|
||||
{
|
||||
if err := publishApiMetric(metricAttributes.ApiMetric); err != nil {
|
||||
log.Error("error while publishing api metricAttributes", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
default:
|
||||
{
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func publishApiMetric(apiMetrics ingester.ApiMetric) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
status := strconv.Itoa(apiMetrics.ResponseCode)
|
||||
duration := float64(apiMetrics.DurationInMs)
|
||||
ApiRequestCounter.WithLabelValues(apiMetrics.Url, apiMetrics.Method, status)
|
||||
ApiRequestCounter.WithLabelValues(apiMetrics.Url, apiMetrics.Method, status).Inc()
|
||||
ApiRequestLatencySum.WithLabelValues(apiMetrics.Url, apiMetrics.Method, status).Add(duration)
|
||||
ApiRequestLatencyHistogram.WithLabelValues(apiMetrics.Url, apiMetrics.Method, status).Observe(duration)
|
||||
ApiRequestLatencySummary.WithLabelValues(apiMetrics.Url, apiMetrics.Method, status).Observe(duration)
|
||||
return
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var HoustonApiRequestCounter = promauto.NewCounterVec(
|
||||
var ApiRequestCounter = promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "houston_api_request_total",
|
||||
Help: "api request counter",
|
||||
@@ -13,7 +13,7 @@ var HoustonApiRequestCounter = promauto.NewCounterVec(
|
||||
[]string{"url", "method", "response_code"},
|
||||
)
|
||||
|
||||
var HoustonApiRequestLatencySum = promauto.NewCounterVec(
|
||||
var ApiRequestLatencySum = promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "houston_api_request_latency_sum",
|
||||
Help: "api request latency sum",
|
||||
@@ -21,7 +21,7 @@ var HoustonApiRequestLatencySum = promauto.NewCounterVec(
|
||||
[]string{"url", "method", "response_code"},
|
||||
)
|
||||
|
||||
var HoustonApiRequestLatencyHistogram = promauto.NewHistogramVec(
|
||||
var ApiRequestLatencyHistogram = promauto.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "houston_api_request_latency_histogram",
|
||||
Help: "api latency histogram",
|
||||
@@ -29,7 +29,7 @@ var HoustonApiRequestLatencyHistogram = promauto.NewHistogramVec(
|
||||
[]string{"url", "method", "response_code"},
|
||||
)
|
||||
|
||||
var HoustonApiRequestLatencySummary = promauto.NewSummaryVec(
|
||||
var ApiRequestLatencySummary = promauto.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: "houston_api_request_latency_summary",
|
||||
Help: "api latency summary",
|
||||
|
||||
46
log/log.go
Normal file
46
log/log.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
var Log *Logger
|
||||
|
||||
func InitLogger() {
|
||||
log, err := zap.NewProduction()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Log = &Logger{
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func GetLogger() *zap.Logger {
|
||||
return Log.log
|
||||
}
|
||||
|
||||
func Error(message string, fields ...zap.Field) {
|
||||
GetLogger().Error(message, fields...)
|
||||
}
|
||||
|
||||
func Warn(message string, fields ...zap.Field) {
|
||||
GetLogger().Warn(message, fields...)
|
||||
}
|
||||
|
||||
func Info(message string, fields ...zap.Field) {
|
||||
GetLogger().Info(message, fields...)
|
||||
}
|
||||
|
||||
func Fatal(message string, fields ...zap.Field) {
|
||||
GetLogger().Fatal(message, fields...)
|
||||
}
|
||||
|
||||
func Panic(message string, fields ...zap.Field) {
|
||||
GetLogger().Panic(message, fields...)
|
||||
}
|
||||
24
model/ingester/performance_metrics.go
Normal file
24
model/ingester/performance_metrics.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package ingester
|
||||
|
||||
type MetricType string
|
||||
|
||||
const (
|
||||
API_METRICS MetricType = "API_METRICS"
|
||||
)
|
||||
|
||||
type ApiMetric struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Method string `json:"method,omitempty"`
|
||||
ResponseCode int `json:"response_code,omitempty"`
|
||||
BytesSent int `json:"bytes_sent,omitempty"`
|
||||
BytesReceived int64 `json:"bytes_received,omitempty"`
|
||||
StartTime int64 `json:"start_time,omitempty"`
|
||||
EndTime int64 `json:"end_time,omitempty"`
|
||||
DurationInMs int64 `json:"duration_in_ms,omitempty"`
|
||||
ErrorType string `json:"error_type,omitempty"`
|
||||
ErrorMessage string `json:"error_message,omitempty"`
|
||||
}
|
||||
|
||||
type MetricAttributes struct {
|
||||
ApiMetric
|
||||
}
|
||||
@@ -6,16 +6,16 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type readinessService struct {
|
||||
gin *gin.Engine
|
||||
type ReadinessService struct {
|
||||
gin *gin.Engine
|
||||
}
|
||||
|
||||
func NewReadinessService(gin *gin.Engine) *readinessService {
|
||||
return &readinessService{
|
||||
gin: gin,
|
||||
}
|
||||
func NewReadinessService(gin *gin.Engine) *ReadinessService {
|
||||
return &ReadinessService{
|
||||
gin: gin,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *readinessService) Ping(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, "pong")
|
||||
}
|
||||
func (i *ReadinessService) Ping(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, "pong")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user