Init commit repo setup
This commit is contained in:
50
pkg/db/postgres.go
Normal file
50
pkg/db/postgres.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"cybertron/configs"
|
||||
"cybertron/pkg/log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var logger = log.Log.GetLog()
|
||||
|
||||
func NewDBClient() *gorm.DB {
|
||||
postgresConfig := configs.GetPostgresConfig()
|
||||
db, err := gorm.Open(postgres.Open(postgresConfig.GetPostgresDsn()), &gorm.Config{})
|
||||
if err != nil {
|
||||
logger.Error("database connection failed", zap.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
connMaxIdleDuration, err := time.ParseDuration(postgresConfig.GetMaxIdleConnectionTimeout())
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
connMaxLifetimeDuration, err := time.ParseDuration(postgresConfig.GetMaxConnectionLifetime())
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
sqlDB.SetConnMaxIdleTime(time.Duration(connMaxIdleDuration.Seconds()))
|
||||
sqlDB.SetConnMaxLifetime(time.Duration(connMaxLifetimeDuration.Seconds()))
|
||||
sqlDB.SetMaxIdleConns(postgresConfig.GetMaxIdleConnections())
|
||||
sqlDB.SetMaxOpenConns(postgresConfig.GetMaxOpenConnections())
|
||||
|
||||
err = sqlDB.Ping()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
logger.Info("database connection established")
|
||||
return db
|
||||
}
|
||||
76
pkg/log/log.go
Normal file
76
pkg/log/log.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.elastic.co/ecszap"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
var Log *Logger
|
||||
|
||||
func initiateLogger() *zap.Logger {
|
||||
config := zap.NewProductionConfig()
|
||||
config.EncoderConfig = ecszap.ECSCompatibleEncoderConfig(config.EncoderConfig)
|
||||
log, err := config.Build(ecszap.WrapCoreOption(), zap.AddCaller())
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return log
|
||||
}
|
||||
|
||||
func Error(message string, fields ...zap.Field) {
|
||||
Log.log.Error(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func Warn(message string, fields ...zap.Field) {
|
||||
Log.log.Warn(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func Info(message string, fields ...zap.Field) {
|
||||
Log.log.Info(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func Fatal(message string, fields ...zap.Field) {
|
||||
Log.log.Fatal(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func Panic(message string, fields ...zap.Field) {
|
||||
Log.log.Panic(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func ErrorWithContext(c *gin.Context, message string, fields ...zap.Field) {
|
||||
requestLogEntryWithCorrelationId(c).Error(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func WarnWithContext(c *gin.Context, message string, fields ...zap.Field) {
|
||||
requestLogEntryWithCorrelationId(c).Warn(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func InfoWithContext(c *gin.Context, message string, fields ...zap.Field) {
|
||||
requestLogEntryWithCorrelationId(c).Info(appendBaseMessage(message), fields...)
|
||||
}
|
||||
|
||||
func requestLogEntryWithCorrelationId(c *gin.Context) *zap.Logger {
|
||||
return Log.log.With(
|
||||
zap.String("CorrelationId", c.Value("X-Correlation-Id").(string)),
|
||||
)
|
||||
}
|
||||
|
||||
func appendBaseMessage(message string) string {
|
||||
return "cybertron" + message
|
||||
}
|
||||
|
||||
func (l *Logger) GetLog() *zap.Logger {
|
||||
return Log.log
|
||||
}
|
||||
|
||||
func init() {
|
||||
Log = &Logger{
|
||||
log: initiateLogger(),
|
||||
}
|
||||
}
|
||||
36
pkg/metrics/http_client_metrics_recorder.go
Normal file
36
pkg/metrics/http_client_metrics_recorder.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"cybertron/models/instrumentation"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ClientHttpCall func(req *http.Request) (*http.Response, error)
|
||||
|
||||
func RecordClientHttpCallMetrics(req *http.Request, method ClientHttpCall) (*http.Response, error) {
|
||||
startTime := time.Now()
|
||||
|
||||
resp, err := method(req)
|
||||
|
||||
endTime := time.Now()
|
||||
duration := endTime.Sub(startTime)
|
||||
|
||||
metricsPublisher := NewMetricPublisher()
|
||||
|
||||
clientHttpCallMetrics := instrumentation.ClientHttpCallMetric{
|
||||
Url: req.URL.Path,
|
||||
StartTime: startTime.Unix(),
|
||||
EndTime: endTime.Unix(),
|
||||
DurationInMs: duration.Milliseconds(),
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
clientHttpCallMetrics.ResponseCode = resp.StatusCode
|
||||
}
|
||||
|
||||
metricsPublisher.PublishMetrics(instrumentation.MetricAttributes{ClientHttpCallMetric: clientHttpCallMetrics},
|
||||
instrumentation.CLIENT_HTTP_CALL_METRICS)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
44
pkg/metrics/metric_publisher.go
Normal file
44
pkg/metrics/metric_publisher.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"cybertron/models/instrumentation"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Publisher interface {
|
||||
PublishMetrics(metricAttributes map[string]interface{}, metricType instrumentation.MetricType)
|
||||
}
|
||||
|
||||
type PublisherImpl struct {
|
||||
}
|
||||
|
||||
func NewMetricPublisher() *PublisherImpl {
|
||||
return &PublisherImpl{}
|
||||
}
|
||||
|
||||
func (amp *PublisherImpl) PublishMetrics(metricAttributes instrumentation.MetricAttributes, metricType instrumentation.MetricType) {
|
||||
switch metricType {
|
||||
case instrumentation.API_METRICS:
|
||||
publishApiMetric(metricAttributes.ApiMetric)
|
||||
return
|
||||
case instrumentation.CLIENT_HTTP_CALL_METRICS:
|
||||
publishClientHttpCallMetric(metricAttributes.ClientHttpCallMetric)
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func publishApiMetric(apiMetrics instrumentation.ApiMetric) {
|
||||
status := strconv.Itoa(apiMetrics.ResponseCode)
|
||||
duration := float64(apiMetrics.DurationInMs)
|
||||
ApiRequestCounter.WithLabelValues(apiMetrics.Url, status).Inc()
|
||||
ApiRequestLatencyHistogram.WithLabelValues(apiMetrics.Url, status).Observe(duration)
|
||||
}
|
||||
|
||||
func publishClientHttpCallMetric(clientHttpCallMetric instrumentation.ClientHttpCallMetric) {
|
||||
status := strconv.Itoa(clientHttpCallMetric.ResponseCode)
|
||||
duration := float64(clientHttpCallMetric.DurationInMs)
|
||||
HttpCallRequestCounter.WithLabelValues(clientHttpCallMetric.Url, status).Inc()
|
||||
HttpCallRequestLatencyHistogram.WithLabelValues(clientHttpCallMetric.Url, status).Observe(duration)
|
||||
}
|
||||
42
pkg/metrics/metrics.go
Normal file
42
pkg/metrics/metrics.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var metricsBuckets = []float64{5, 10, 20, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 20000, 30000, 60000}
|
||||
|
||||
var ApiRequestCounter = promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "cybertron_api_request_total",
|
||||
Help: "api request counter",
|
||||
},
|
||||
[]string{"url", "response_code"},
|
||||
)
|
||||
|
||||
var ApiRequestLatencyHistogram = promauto.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "cybertron_api_request_latency_histogram",
|
||||
Help: "api latency histogram",
|
||||
Buckets: metricsBuckets,
|
||||
},
|
||||
[]string{"url", "response_code"},
|
||||
)
|
||||
|
||||
var HttpCallRequestCounter = promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "cybertron_http_call_request_total",
|
||||
Help: "http call request counter",
|
||||
},
|
||||
[]string{"url", "response_code"},
|
||||
)
|
||||
|
||||
var HttpCallRequestLatencyHistogram = promauto.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "cybertron_http_call_request_latency_histogram",
|
||||
Help: "http call latency histogram",
|
||||
Buckets: metricsBuckets,
|
||||
},
|
||||
[]string{"url", "response_code"},
|
||||
)
|
||||
24
pkg/metrics/server.go
Normal file
24
pkg/metrics/server.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"cybertron/configs"
|
||||
"cybertron/pkg/log"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func AdminHandler() {
|
||||
ginServer := gin.New()
|
||||
port := configs.GetMetricsPort()
|
||||
log.Log.GetLog().Info("Starting metrics on port", zap.Int("port", port))
|
||||
ginServer.GET("/metrics", gin.WrapH(promhttp.Handler()))
|
||||
go func() {
|
||||
err := ginServer.Run(fmt.Sprintf(":%v", port))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user