From f490d45300f0319f025c9ea93d538d21dfd9e61d Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 23 Feb 2025 16:34:24 +0300 Subject: [PATCH 1/5] shortlinks fix --- internal/core/repos/shortlink_repo.go | 6 +++--- sql/01_user.sql | 2 -- sql/02_shortlinks.sql | 17 ++--------------- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/internal/core/repos/shortlink_repo.go b/internal/core/repos/shortlink_repo.go index 2db06ce..565e4db 100644 --- a/internal/core/repos/shortlink_repo.go +++ b/internal/core/repos/shortlink_repo.go @@ -35,8 +35,8 @@ func (u *shortlinkRepo) AddShortlink(ctx context.Context, dto ShortlinkDTO) erro _, span := u.tracer.Start(ctx, "postgres::AddShortlink") defer span.End() - query := `insert into shortlinks (url, expires_at) values ($1, $2);` - _, err := u.db.ExecContext(ctx, query, dto.Url, dto.ExpiresAt) + query := `insert into shortlinks (id, url, expires_at) values ($1, $2, $3);` + _, err := u.db.ExecContext(ctx, query, dto.Id, dto.Url, dto.ExpiresAt) return err } @@ -72,7 +72,7 @@ func (u *shortlinkRepo) DeleteExpiredShortlinks(ctx context.Context, limit int) where id in ( select id from shortlinks - where current_date > expiration + where current_date > expires_at limit $1 ) returning * diff --git a/sql/01_user.sql b/sql/01_user.sql index 1b38857..fd39f6a 100644 --- a/sql/01_user.sql +++ b/sql/01_user.sql @@ -9,8 +9,6 @@ create table if not exists users ( updated_at timestamp ); -alter table users alter column active set default true; - create index if not exists idx_users_email on users(email); create or replace trigger trg_user_created diff --git a/sql/02_shortlinks.sql b/sql/02_shortlinks.sql index bb0611a..e85199b 100644 --- a/sql/02_shortlinks.sql +++ b/sql/02_shortlinks.sql @@ -1,18 +1,5 @@ create table if not exists shortlinks ( - id int generated always as identity, + id text primary key, url text not null, - expires_at timestamp not null, - created_at timestamp, - updated_at timestamp + expires_at timestamp not null ); - -create or replace trigger trg_shortlink_created - before insert on shortlinks - for each row - execute function trg_proc_row_created(); - -create or replace trigger trg_shortlink_updated - before update on shortlinks - for each row - when (new is distinct from old) - execute function trg_proc_row_updated(); \ No newline at end of file From 16260ecedb89d4398f9b7ba64aa2802a9f471097 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 23 Feb 2025 20:09:55 +0300 Subject: [PATCH 2/5] add wrapper for prometheus --- cmd/backend/server/server.go | 12 +-- cmd/notifyer/config.go | 1 + cmd/notifyer/config.yaml | 1 + cmd/notifyer/event_handler.go | 90 +++++++++++++++++++++ cmd/notifyer/main.go | 98 +++++++++-------------- cmd/shortlinks/main.go | 9 ++- internal/http_server/metrics.go | 49 ++++++++++++ internal/http_server/recovery.go | 5 +- internal/http_server/request_log.go | 16 ++-- internal/integrations/prometheus.go | 117 +++++++++++----------------- 10 files changed, 245 insertions(+), 153 deletions(-) create mode 100644 cmd/notifyer/event_handler.go create mode 100644 internal/http_server/metrics.go diff --git a/cmd/backend/server/server.go b/cmd/backend/server/server.go index e76b7d4..028ee83 100644 --- a/cmd/backend/server/server.go +++ b/cmd/backend/server/server.go @@ -28,14 +28,14 @@ func NewServer(opts NewServerOpts) *httpserver.Server { r := gin.New() r.ContextWithFallback = true // Use it to allow getting values from c.Request.Context() - // r.Static("/webapp", "./webapp") + metrics := integrations.NewMetrics("backend") + serverMetrics := httpserver.NewServerMetrics(metrics) + r.GET("/health", handlers.New200OkHandler()) + r.Any("/metrics", gin.WrapH(metrics.HttpHandler())) - prometheus := integrations.NewPrometheus() - r.Any("/metrics", gin.WrapH(prometheus.GetRequestHandler())) - - r.Use(httpserver.NewRecoveryMiddleware(opts.Logger, prometheus, opts.DebugMode)) - r.Use(httpserver.NewRequestLogMiddleware(opts.Logger, opts.Tracer, prometheus)) + r.Use(httpserver.NewRecoveryMiddleware(opts.Logger, serverMetrics, opts.DebugMode)) + r.Use(httpserver.NewRequestLogMiddleware(opts.Logger, opts.Tracer, serverMetrics)) r.Use(httpserver.NewTracingMiddleware(opts.Tracer)) r.GET("/verify-user", handlers.NewUserVerifyEmailHandler(opts.Logger, opts.UserService)) diff --git a/cmd/notifyer/config.go b/cmd/notifyer/config.go index e40f597..f0c0437 100644 --- a/cmd/notifyer/config.go +++ b/cmd/notifyer/config.go @@ -8,6 +8,7 @@ func LoadConfig(filePath string) (Config, error) { type Config struct { App struct { + Port uint16 `yaml:"port"` LogFile string `yaml:"logFile"` ServiceUrl string `yaml:"serviceUrl"` } diff --git a/cmd/notifyer/config.yaml b/cmd/notifyer/config.yaml index 4de10a5..1762b99 100644 --- a/cmd/notifyer/config.yaml +++ b/cmd/notifyer/config.yaml @@ -1,4 +1,5 @@ app: + port: 8082 serviceUrl: "http://localhost:8080" kafka: brokers: diff --git a/cmd/notifyer/event_handler.go b/cmd/notifyer/event_handler.go new file mode 100644 index 0000000..9d2b58e --- /dev/null +++ b/cmd/notifyer/event_handler.go @@ -0,0 +1,90 @@ +package main + +import ( + "backend/internal/integrations" + "backend/pkg/logger" + "context" + "encoding/json" + "fmt" + "io" + + "github.com/segmentio/kafka-go" +) + +type SendEmailEvent struct { + Email string `json:"email"` + Token string `json:"token"` +} + +func NewEventHandler( + config Config, + logger logger.Logger, + metrics *integrations.Metrics, + emailer *Emailer, +) *EventHandler { + eventsCounter := metrics.NewCounter("events_counter", "total events handled") + return &EventHandler{ + config: config, + logger: logger, + emailer: emailer, + eventsCounter: eventsCounter, + } +} + +type EventHandler struct { + config Config + logger logger.Logger + emailer *Emailer + eventsCounter integrations.Counter +} + +func (e *EventHandler) eventLoop(ctx context.Context, kafkaReader *kafka.Reader) { + for { + msg, err := kafkaReader.FetchMessage(ctx) + if err == io.EOF { + e.logger.Fatal().Err(err) + } + if err != nil { + e.logger.Fatal().Err(err) + } + + select { + case <-ctx.Done(): + return + default: + } + + e.logger.Log().Msgf("event: %s", msg.Key) + e.eventsCounter.Inc() + + if err := kafkaReader.CommitMessages(ctx, msg); err != nil { + e.logger.Error().Err(err).Msg("failed to commit offset") + continue + } + + if err := e.handleEvent(ctx, msg); err != nil { + e.logger.Error().Err(err).Msg("failed to handle event") + continue + } + } +} + +func (e *EventHandler) handleEvent(ctx context.Context, msg kafka.Message) error { + event := SendEmailEvent{} + if err := json.Unmarshal(msg.Value, &event); err != nil { + return err + } + + // TODO: add context somehow + switch string(msg.Key) { + case "email_forgot_password": + return e.emailer.SendRestorePassword(event.Email, event.Token) + case "email_password_changed": + return e.emailer.SendPasswordChanged(event.Email) + case "email_verify_user": + link := fmt.Sprintf("%s/verify-user?token=%s", e.config.App.ServiceUrl, event.Token) + return e.emailer.SendVerifyUser(event.Email, link) + } + + return fmt.Errorf("unknown event type") +} diff --git a/cmd/notifyer/main.go b/cmd/notifyer/main.go index c328b89..71fb044 100644 --- a/cmd/notifyer/main.go +++ b/cmd/notifyer/main.go @@ -1,21 +1,16 @@ package main import ( + httpserver "backend/internal/http_server" + "backend/internal/integrations" "backend/pkg/logger" "context" - "encoding/json" - "fmt" - "io" "log" + "github.com/gin-gonic/gin" "github.com/segmentio/kafka-go" ) -type SendEmailEvent struct { - Email string `json:"email"` - Token string `json:"token"` -} - func main() { ctx := context.Background() @@ -24,67 +19,44 @@ func main() { log.Fatal(err.Error()) } - emailer, err := NewEmailer(config.SMTP) - if err != nil { - log.Fatal(err.Error()) - } - - r := kafka.NewReader(kafka.ReaderConfig{ - Brokers: config.Kafka.Brokers, - Topic: config.Kafka.Topic, - GroupID: config.Kafka.ConsumerGroupId, - }) - logger, err := logger.New(ctx, logger.NewLoggerOpts{ Debug: true, OutputFile: config.App.LogFile, }) if err != nil { - log.Fatal(err.Error()) + logger.Fatal().Err(err) } - logger.Printf("notifyer service started\n") - - for { - msg, err := r.FetchMessage(ctx) - if err == io.EOF { - log.Fatal("EOF") - return - } - if err != nil { - log.Fatal(err.Error()) - return - } - - log.Printf("offset: %d, partition: %d, key: %s, value: %s\n", msg.Offset, msg.Partition, string(msg.Key), string(msg.Value)) - - if err := r.CommitMessages(ctx, msg); err != nil { - log.Fatalf("failed to commit: %s\n", err.Error()) - continue - } - - if err := handleEvent(config, emailer, msg); err != nil { - log.Printf("failed to handle event: %s\n", err.Error()) - continue - } + emailer, err := NewEmailer(config.SMTP) + if err != nil { + logger.Fatal().Err(err) } -} - -func handleEvent(config Config, emailer *Emailer, msg kafka.Message) error { - event := SendEmailEvent{} - if err := json.Unmarshal(msg.Value, &event); err != nil { - return err - } - - switch string(msg.Key) { - case "email_forgot_password": - return emailer.SendRestorePassword(event.Email, event.Token) - case "email_password_changed": - return emailer.SendPasswordChanged(event.Email) - case "email_verify_user": - link := fmt.Sprintf("%s/verify-user?token=%s", config.App.ServiceUrl, event.Token) - return emailer.SendVerifyUser(event.Email, link) - } - - return fmt.Errorf("unknown event type") + + metrics := integrations.NewMetrics("notifyer") + + ginRouter := gin.New() + ginRouter.GET("/metrics", gin.WrapH(metrics.HttpHandler())) + ginRouter.GET("/health", func(ctx *gin.Context) { + ctx.Status(200) + }) + + kafkaReader := kafka.NewReader(kafka.ReaderConfig{ + Brokers: config.Kafka.Brokers, + Topic: config.Kafka.Topic, + GroupID: config.Kafka.ConsumerGroupId, + }) + kafkaReader.SetOffset(kafka.LastOffset) + + eventHandler := NewEventHandler(config, logger, metrics, emailer) + go eventHandler.eventLoop(ctx, kafkaReader) + + logger.Log().Msg("notifyer service started") + + srv := httpserver.New( + httpserver.NewServerOpts{ + Logger: logger, + HttpServer: ginRouter, + }, + ) + srv.Run(ctx, config.App.Port) } diff --git a/cmd/shortlinks/main.go b/cmd/shortlinks/main.go index 2adbf3d..f9765ca 100644 --- a/cmd/shortlinks/main.go +++ b/cmd/shortlinks/main.go @@ -85,16 +85,17 @@ func RunServer(ctx context.Context, log logger.Logger, tracer trace.Tracer, conf gin.SetMode(gin.ReleaseMode) } - prometheus := integrations.NewPrometheus() + metrics := integrations.NewMetrics("shortlinks") + serverMetrics := httpserver.NewServerMetrics(metrics) r := gin.New() - r.Any("/metrics", gin.WrapH(prometheus.GetRequestHandler())) + r.Any("/metrics", gin.WrapH(metrics.HttpHandler())) r.GET("/health", func(ctx *gin.Context) { ctx.Status(200) }) - r.Use(httpserver.NewRecoveryMiddleware(log, prometheus, debugMode)) - r.Use(httpserver.NewRequestLogMiddleware(log, tracer, prometheus)) + r.Use(httpserver.NewRecoveryMiddleware(log, serverMetrics, debugMode)) + r.Use(httpserver.NewRequestLogMiddleware(log, tracer, serverMetrics)) r.Use(httpserver.NewTracingMiddleware(tracer)) linkGroup := r.Group("/s") diff --git a/internal/http_server/metrics.go b/internal/http_server/metrics.go new file mode 100644 index 0000000..e024d94 --- /dev/null +++ b/internal/http_server/metrics.go @@ -0,0 +1,49 @@ +package httpserver + +import ( + "backend/internal/integrations" +) + +func NewServerMetrics(p *integrations.Metrics) *ServerMetrics { + errors5xxCounter := p.NewCounter("server_responses_5xx", "5xx responses counter") + errors4xxCounter := p.NewCounter("server_responses_4xx", "4xx responses count") + requestsCounter := p.NewCounter("server_requests_total", "requests counter") + avgReqTimeHist := p.NewHistogram("server_requests_time", "requests time histogram") + panicsHist := p.NewHistogram("server_panics", "panics histogram metric") + + return &ServerMetrics{ + rpsCounter: requestsCounter, + avgReqTimeHist: avgReqTimeHist, + panicsHist: panicsHist, + errors4xxCounter: errors4xxCounter, + errors5xxCounter: errors5xxCounter, + } +} + +type ServerMetrics struct { + rpsCounter integrations.Counter + avgReqTimeHist integrations.Histogram + panicsHist integrations.Histogram + errors4xxCounter integrations.Counter + errors5xxCounter integrations.Counter +} + +func (b *ServerMetrics) AddRequest() { + b.rpsCounter.Inc() +} + +func (b *ServerMetrics) AddRequestTime(reqTime float64) { + b.avgReqTimeHist.Observe(reqTime) +} + +func (b *ServerMetrics) AddPanic() { + b.panicsHist.Observe(1) +} + +func (b *ServerMetrics) Add4xxError() { + b.errors4xxCounter.Inc() +} + +func (b *ServerMetrics) Add5xxError() { + b.errors5xxCounter.Inc() +} diff --git a/internal/http_server/recovery.go b/internal/http_server/recovery.go index 4611dab..6c5a409 100644 --- a/internal/http_server/recovery.go +++ b/internal/http_server/recovery.go @@ -3,7 +3,6 @@ package httpserver // Modified recovery from gin, use own logger import ( - "backend/internal/integrations" "backend/pkg/logger" "bytes" "errors" @@ -30,12 +29,12 @@ var ( slash = []byte("/") ) -func NewRecoveryMiddleware(logger logger.Logger, prometheus *integrations.Prometheus, debugMode bool) gin.HandlerFunc { +func NewRecoveryMiddleware(logger logger.Logger, serverMetrics *ServerMetrics, debugMode bool) gin.HandlerFunc { handle := defaultHandleRecovery return func(c *gin.Context) { defer func() { if err := recover(); err != nil { - prometheus.AddPanic() + serverMetrics.AddPanic() // Check for a broken connection, as it is not really a // condition that warrants a panic stack trace. diff --git a/internal/http_server/request_log.go b/internal/http_server/request_log.go index f3c7e5b..24c9c7a 100644 --- a/internal/http_server/request_log.go +++ b/internal/http_server/request_log.go @@ -1,7 +1,6 @@ package httpserver import ( - "backend/internal/integrations" log "backend/pkg/logger" "fmt" "time" @@ -11,10 +10,13 @@ import ( "go.opentelemetry.io/otel/trace" ) -func NewRequestLogMiddleware(logger log.Logger, tracer trace.Tracer, prometheus *integrations.Prometheus) gin.HandlerFunc { +func NewRequestLogMiddleware( + logger log.Logger, + tracer trace.Tracer, + serverMetrics *ServerMetrics, +) gin.HandlerFunc { return func(c *gin.Context) { - prometheus.RequestInc() - defer prometheus.RequestDec() + serverMetrics.AddRequest() requestId := c.GetHeader("X-Request-Id") if requestId == "" { @@ -34,7 +36,7 @@ func NewRequestLogMiddleware(logger log.Logger, tracer trace.Tracer, prometheus c.Next() latency := time.Since(start) - prometheus.AddRequestTime(float64(latency.Microseconds())) + serverMetrics.AddRequestTime(float64(latency.Microseconds())) method := c.Request.Method statusCode := c.Writer.Status() @@ -49,12 +51,12 @@ func NewRequestLogMiddleware(logger log.Logger, tracer trace.Tracer, prometheus } if statusCode >= 400 && statusCode < 500 { - prometheus.Add4xxError() + serverMetrics.Add4xxError() ctxLogger.Warning().Msg(msg) return } - prometheus.Add5xxError() + serverMetrics.Add5xxError() ctxLogger.Error().Msg(msg) } } diff --git a/internal/integrations/prometheus.go b/internal/integrations/prometheus.go index 9fecfba..31533c6 100644 --- a/internal/integrations/prometheus.go +++ b/internal/integrations/prometheus.go @@ -8,90 +8,67 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -type Prometheus struct { - reg *prometheus.Registry - rpsCounter prometheus.Counter - avgReqTimeHist prometheus.Histogram - panicsHist prometheus.Histogram - errors4xxCounter prometheus.Counter - errors5xxCounter prometheus.Counter +type Counter interface { + Inc() } -func NewPrometheus() *Prometheus { - reg := prometheus.NewRegistry() +type Gauge interface { + Set(float64) + Inc() + Dec() +} - // Add go runtime metrics and process collectors. - reg.MustRegister( +type Histogram interface { + Observe(float64) +} + +type Metrics struct { + registry *prometheus.Registry + registerer prometheus.Registerer +} + +func NewMetrics(prefix string) *Metrics { + registry := prometheus.NewRegistry() + registerer := prometheus.WrapRegistererWithPrefix(prefix, registry) + + registerer.MustRegister( collectors.NewGoCollector(), collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), ) - errors5xxCounter := prometheus.NewCounter( - prometheus.CounterOpts{ - Name: "backend_errors_count_5xx", - Help: "5xx errors count", - }, - ) - errors4xxCounter := prometheus.NewCounter( - prometheus.CounterOpts{ - Name: "backend_errors_count_4xx", - Help: "4xx errors count", - }, - ) - rpsCounter := prometheus.NewCounter( - prometheus.CounterOpts{ - Name: "backend_requests_per_second", - Help: "Requests per second metric", - }, - ) - avgReqTimeHist := prometheus.NewHistogram( - prometheus.HistogramOpts{ - Name: "backend_requests_average_time", - Help: "Average time of requests", - }, - ) - panicsHist := prometheus.NewHistogram( - prometheus.HistogramOpts{ - Name: "backend_panics", - Help: "Panics histogram metric", - }, - ) - reg.MustRegister(rpsCounter, avgReqTimeHist, panicsHist, errors4xxCounter, errors5xxCounter) - - return &Prometheus{ - panicsHist: panicsHist, - avgReqTimeHist: avgReqTimeHist, - rpsCounter: rpsCounter, - errors4xxCounter: errors4xxCounter, - errors5xxCounter: errors5xxCounter, - reg: reg, + return &Metrics{ + registry: registry, + registerer: registerer, } } -func (p *Prometheus) GetRequestHandler() http.Handler { - return promhttp.HandlerFor(p.reg, promhttp.HandlerOpts{Registry: p.reg}) +func (m *Metrics) NewCounter(name, description string) Counter { + collector := prometheus.NewCounter(prometheus.CounterOpts{ + Name: name, + Help: description, + }) + m.registerer.MustRegister(collector) + return collector } -func (p *Prometheus) RequestInc() { - p.rpsCounter.Inc() +func (m *Metrics) NewGauge(name, description string) Gauge { + collector := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: name, + Help: description, + }) + m.registerer.MustRegister(collector) + return collector } -func (p *Prometheus) RequestDec() { - // p.rpsGauge.Dec() +func (m *Metrics) NewHistogram(name, description string) Histogram { + collector := prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: name, + Help: description, + }) + m.registerer.MustRegister(collector) + return collector } -func (p *Prometheus) AddRequestTime(reqTime float64) { - p.avgReqTimeHist.Observe(reqTime) -} - -func (p *Prometheus) AddPanic() { - p.panicsHist.Observe(1) -} - -func (p *Prometheus) Add4xxError() { - p.errors4xxCounter.Inc() -} - -func (p *Prometheus) Add5xxError() { - p.errors5xxCounter.Inc() +func (m *Metrics) HttpHandler() http.Handler { + return promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{Registry: m.registerer}) } From 2e70087f63dd24155c2e0445754bfa5330d0f6f4 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 23 Feb 2025 20:29:39 +0300 Subject: [PATCH 3/5] improvements for notifyer microservice --- cmd/notifyer/emailer.go | 13 +++++++------ cmd/notifyer/event_handler.go | 3 ++- internal/core/repos/event_repo.go | 2 +- internal/http_server/{wrapper.go => gin_wrapper.go} | 0 internal/integrations/kafka.go | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) rename internal/http_server/{wrapper.go => gin_wrapper.go} (100%) diff --git a/cmd/notifyer/emailer.go b/cmd/notifyer/emailer.go index 7c496c6..71cc508 100644 --- a/cmd/notifyer/emailer.go +++ b/cmd/notifyer/emailer.go @@ -14,7 +14,7 @@ const MSG_TEXT = `

{{.Text}}

{{if .Link}} - Clicklink

+ link {{end}} @@ -34,7 +34,7 @@ func NewEmailer(conf ConfigSMTP) (*Emailer, error) { } defer closer.Close() - htmlTemplate, err := template.New("verify-email").Parse(MSG_TEXT) + htmlTemplate, err := template.New("email").Parse(MSG_TEXT) if err != nil { return nil, err } @@ -52,22 +52,23 @@ type Emailer struct { dialer *gomail.Dialer } -func (e *Emailer) SendRestorePassword(email, token string) error { +func (e *Emailer) SendRestorePassword(email, link string) error { return e.sendEmail("Restore your password", email, MailContent{ - Text: "Token: " + token, + Text: "You received this message do request of password change. Use this link to change your password:", + Link: link, }) } func (e *Emailer) SendVerifyUser(email, link string) error { return e.sendEmail("Verify your email", email, MailContent{ - Text: "You recieved this message due to registration of account. Use this link to verify email:", + Text: "You received this message due to registration of account. Use this link to verify email:", Link: link, }) } func (e *Emailer) SendPasswordChanged(email string) error { return e.sendEmail("Password changed", email, MailContent{ - Text: "You recieved this message due to password change", + Text: "Your password was successfully changed", }) } diff --git a/cmd/notifyer/event_handler.go b/cmd/notifyer/event_handler.go index 9d2b58e..b0041dc 100644 --- a/cmd/notifyer/event_handler.go +++ b/cmd/notifyer/event_handler.go @@ -78,7 +78,8 @@ func (e *EventHandler) handleEvent(ctx context.Context, msg kafka.Message) error // TODO: add context somehow switch string(msg.Key) { case "email_forgot_password": - return e.emailer.SendRestorePassword(event.Email, event.Token) + link := fmt.Sprintf("%s/restore-password?token=%s", e.config.App.ServiceUrl, event.Token) + return e.emailer.SendRestorePassword(event.Email, link) case "email_password_changed": return e.emailer.SendPasswordChanged(event.Email) case "email_verify_user": diff --git a/internal/core/repos/event_repo.go b/internal/core/repos/event_repo.go index ac3e588..7a4cfb0 100644 --- a/internal/core/repos/event_repo.go +++ b/internal/core/repos/event_repo.go @@ -35,7 +35,7 @@ func (e *EventRepo) sendEmail(ctx context.Context, email, actionToken, eventType return err } - return e.kafka.SendMessage(ctx, eventType, valueBytes) + return e.kafka.PushMessage(ctx, eventType, valueBytes) } func (e *EventRepo) SendEmailPasswordChanged(ctx context.Context, email string) error { diff --git a/internal/http_server/wrapper.go b/internal/http_server/gin_wrapper.go similarity index 100% rename from internal/http_server/wrapper.go rename to internal/http_server/gin_wrapper.go diff --git a/internal/integrations/kafka.go b/internal/integrations/kafka.go index 69eef72..bd2180c 100644 --- a/internal/integrations/kafka.go +++ b/internal/integrations/kafka.go @@ -26,7 +26,7 @@ func NewKafka(addr, topic string) *Kafka { } } -func (k *Kafka) SendMessage(ctx context.Context, key string, value []byte) error { +func (k *Kafka) PushMessage(ctx context.Context, key string, value []byte) error { return k.writer.WriteMessages( context.Background(), kafka.Message{ From d96b5606ff79f8d33c27ef9ca3b28f7fbf3047ee Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 23 Feb 2025 20:42:45 +0300 Subject: [PATCH 4/5] add service_url field to shortlinks config --- cmd/shortlinks/conf.yml | 1 + cmd/shortlinks/config.go | 6 ++++++ cmd/shortlinks/grpc.go | 2 +- cmd/shortlinks/handlers.go | 14 +++++++++----- cmd/shortlinks/main.go | 6 ++---- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/cmd/shortlinks/conf.yml b/cmd/shortlinks/conf.yml index fb50a15..7c8980d 100644 --- a/cmd/shortlinks/conf.yml +++ b/cmd/shortlinks/conf.yml @@ -1,3 +1,4 @@ +service_url: http://localhost:8081 http_port: 8081 grpc_port: 8082 postgres_url: "postgres://postgres:postgres@localhost:5432/postgres" \ No newline at end of file diff --git a/cmd/shortlinks/config.go b/cmd/shortlinks/config.go index a2c6036..707f44b 100644 --- a/cmd/shortlinks/config.go +++ b/cmd/shortlinks/config.go @@ -3,6 +3,7 @@ package main import "backend/pkg/config" type IConfig interface { + GetServiceUrl() string GetHttpPort() uint16 GetGrpcPort() uint16 GetPostgresUrl() string @@ -13,11 +14,16 @@ func LoadConfig(filePath string) (IConfig, error) { } type Config struct { + ServiceUrl string `yaml:"service_url" validate:"required"` HttpPort uint16 `yaml:"http_port" validate:"required"` GrpcPort uint16 `yaml:"grpc_port" validate:"required"` PostgresUrl string `yaml:"postgres_url" validate:"required"` } +func (c *Config) GetServiceUrl() string { + return c.ServiceUrl +} + func (c *Config) GetHttpPort() uint16 { return c.HttpPort } diff --git a/cmd/shortlinks/grpc.go b/cmd/shortlinks/grpc.go index c35bf71..ab23a2f 100644 --- a/cmd/shortlinks/grpc.go +++ b/cmd/shortlinks/grpc.go @@ -10,7 +10,7 @@ import ( func NewShortlinksGrpc(log logger.Logger, shortlinkService services.ShortlinkService, host string) *ShortlinksGrpc { return &ShortlinksGrpc{ - handler: NewCreateHandler(log, shortlinkService, host), + handler: NewShortlinkCreateHandler(log, shortlinkService, host), } } diff --git a/cmd/shortlinks/handlers.go b/cmd/shortlinks/handlers.go index 0af19af..450824d 100644 --- a/cmd/shortlinks/handlers.go +++ b/cmd/shortlinks/handlers.go @@ -19,10 +19,10 @@ type shortlinkCreateOutput struct { Link string `json:"link"` } -func NewCreateHandler( +func NewShortlinkCreateHandler( log logger.Logger, shortlinkService services.ShortlinkService, - host string, + serviceUrl string, ) httpserver.Handler[shortlinkCreateInput, shortlinkCreateOutput] { return func(ctx context.Context, input shortlinkCreateInput) (shortlinkCreateOutput, error) { output := shortlinkCreateOutput{} @@ -39,13 +39,17 @@ func NewCreateHandler( } return shortlinkCreateOutput{ - Link: fmt.Sprintf("%s/s/%s", host, linkId), + Link: fmt.Sprintf("%s/s/%s", serviceUrl, linkId), }, nil } } -func NewShortlinkCreateHandler(log logger.Logger, shortlinkService services.ShortlinkService, host string) gin.HandlerFunc { - return httpserver.WrapGin(log, NewCreateHandler(log, shortlinkService, host)) +func NewShortlinkCreateGinHandler( + log logger.Logger, + shortlinkService services.ShortlinkService, + serviceUrl string, +) gin.HandlerFunc { + return httpserver.WrapGin(log, NewShortlinkCreateHandler(log, shortlinkService, serviceUrl)) } func NewShortlinkResolveHandler(logger logger.Logger, shortlinkService services.ShortlinkService) gin.HandlerFunc { diff --git a/cmd/shortlinks/main.go b/cmd/shortlinks/main.go index f9765ca..28dcc8b 100644 --- a/cmd/shortlinks/main.go +++ b/cmd/shortlinks/main.go @@ -10,7 +10,6 @@ import ( "backend/pkg/cache" "backend/pkg/logger" "context" - "fmt" "sync" "github.com/gin-gonic/gin" @@ -79,7 +78,6 @@ func main() { } func RunServer(ctx context.Context, log logger.Logger, tracer trace.Tracer, conf IConfig, shortlinkService services.ShortlinkService) { - host := fmt.Sprintf("http://localhost:%d", conf.GetHttpPort()) debugMode := true if !debugMode { gin.SetMode(gin.ReleaseMode) @@ -99,13 +97,13 @@ func RunServer(ctx context.Context, log logger.Logger, tracer trace.Tracer, conf r.Use(httpserver.NewTracingMiddleware(tracer)) linkGroup := r.Group("/s") - linkGroup.POST("/new", NewShortlinkCreateHandler(log, shortlinkService, host)) + linkGroup.POST("/new", NewShortlinkCreateGinHandler(log, shortlinkService, conf.GetServiceUrl())) linkGroup.GET("/:linkId", NewShortlinkResolveHandler(log, shortlinkService)) grpcUnderlying := grpc.NewServer() shortlinks.RegisterShortlinksServer( grpcUnderlying, - NewShortlinksGrpc(log, shortlinkService, host), + NewShortlinksGrpc(log, shortlinkService, conf.GetServiceUrl()), ) httpServer := httpserver.New( From 21614f75033e35f3794befb9235e29cda7b37728 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 23 Feb 2025 22:17:27 +0300 Subject: [PATCH 5/5] improve deploy with docker compose --- backend.Dockerfile | 23 +++ cmd/backend/app.go | 5 +- .../{args_parser/args.go => cmdargs.go} | 26 ++- cmd/backend/config.go | 14 +- cmd/backend/config.yaml | 5 - cmd/shortlinks/conf.yml | 4 - cmd/shortlinks/main.go | 1 - cmd/shortlinks/makefile | 2 - docker-compose.yaml => compose.yml | 161 ++++++++---------- deploy/backend-config.yaml | 5 + .../backend-jwt-privkey | 0 .../notifyer-config.yaml | 8 +- deploy/shortlinks-config.yaml | 4 + go.mod | 80 ++++----- go.sum | 97 ++++------- makefile | 6 +- monitoring-compose.yml | 47 +++++ notifyer.Dockerfile | 22 +++ Dockerfile => shortlinks.Dockerfile | 7 +- 19 files changed, 269 insertions(+), 248 deletions(-) create mode 100644 backend.Dockerfile rename cmd/backend/{args_parser/args.go => cmdargs.go} (62%) delete mode 100644 cmd/backend/config.yaml delete mode 100644 cmd/shortlinks/conf.yml delete mode 100644 cmd/shortlinks/makefile rename docker-compose.yaml => compose.yml (59%) create mode 100644 deploy/backend-config.yaml rename cmd/backend/jwt_signing_key => deploy/backend-jwt-privkey (100%) rename cmd/notifyer/config.yaml => deploy/notifyer-config.yaml (64%) create mode 100644 deploy/shortlinks-config.yaml create mode 100644 monitoring-compose.yml create mode 100644 notifyer.Dockerfile rename Dockerfile => shortlinks.Dockerfile (76%) diff --git a/backend.Dockerfile b/backend.Dockerfile new file mode 100644 index 0000000..7a2b478 --- /dev/null +++ b/backend.Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.22-alpine AS builder +WORKDIR /build + +COPY go.mod go.sum ./ +RUN go mod download && go mod verify + +COPY cmd/backend cmd/backend +COPY pkg pkg +COPY internal internal + +RUN GOEXPERIMENT=boringcrypto go build -ldflags "-s -w" -o ./app ./cmd/backend +RUN chmod +x ./app + +FROM alpine:3.21.2 AS production +WORKDIR /backend + +COPY --from=builder /build/app . +COPY deploy/backend-config.yaml ./config.yaml +COPY deploy/backend-jwt-privkey ./privkey + +EXPOSE 8080 + +CMD ["./app", "-c", "config.yaml", "-k", "privkey"] \ No newline at end of file diff --git a/cmd/backend/app.go b/cmd/backend/app.go index f36ac80..d62f7d2 100644 --- a/cmd/backend/app.go +++ b/cmd/backend/app.go @@ -1,7 +1,6 @@ package main import ( - "backend/cmd/backend/args_parser" "backend/cmd/backend/server" "backend/internal/core/models" "backend/internal/core/repos" @@ -55,7 +54,7 @@ func (a *App) Run(p RunParams) { //----------------------------------------- - args, err := args_parser.Parse(osArgs) + args, err := CmdArgsParse(osArgs) if err != nil { log.Fatalf("failed to parse os args: %v\n", err) } @@ -90,7 +89,7 @@ func (a *App) Run(p RunParams) { var key *rsa.PrivateKey { - keyRawBytes, err := os.ReadFile(conf.GetJwtSigningKey()) + keyRawBytes, err := os.ReadFile(args.GetSigningKeyPath()) if err != nil { logger.Fatal().Err(err).Msg("failed reading signing key file") } diff --git a/cmd/backend/args_parser/args.go b/cmd/backend/cmdargs.go similarity index 62% rename from cmd/backend/args_parser/args.go rename to cmd/backend/cmdargs.go index 543d0df..3726db5 100644 --- a/cmd/backend/args_parser/args.go +++ b/cmd/backend/cmdargs.go @@ -1,19 +1,21 @@ -package args_parser +package main import ( "github.com/akamensky/argparse" ) -type Args interface { +type CmdArgs interface { GetProfilePath() string GetConfigPath() string GetLogPath() string + GetSigningKeyPath() string } -func Parse(osArgs []string) (Args, error) { +func CmdArgsParse(osArgs []string) (CmdArgs, error) { parser := argparse.NewParser("backend", "runs backend") s := parser.String("c", "config", &argparse.Options{Required: true, Help: "Path to a config file"}) + k := parser.String("k", "key", &argparse.Options{Required: false, Default: "", Help: "Path to a jwt signing key"}) l := parser.String("o", "log", &argparse.Options{Required: false, Default: "", Help: "Path to a log file"}) p := parser.String("p", "profile", &argparse.Options{Required: false, Default: "", Help: "Path to a cpu profile file"}) @@ -23,16 +25,18 @@ func Parse(osArgs []string) (Args, error) { } return &args{ - ConfigPath: *s, - LogPath: *l, - ProfilePath: *p, + ConfigPath: *s, + LogPath: *l, + ProfilePath: *p, + SigningKeyPath: *k, }, nil } type args struct { - ProfilePath string - ConfigPath string - LogPath string + ProfilePath string + ConfigPath string + LogPath string + SigningKeyPath string } func (a *args) GetConfigPath() string { @@ -46,3 +50,7 @@ func (a *args) GetLogPath() string { func (a *args) GetProfilePath() string { return a.ProfilePath } + +func (a *args) GetSigningKeyPath() string { + return a.SigningKeyPath +} diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 893c0db..f24abf9 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -5,7 +5,6 @@ import "backend/pkg/config" type IConfig interface { GetPort() uint16 GetPostgresUrl() string - GetJwtSigningKey() string GetKafkaUrl() string GetKafkaTopic() string } @@ -15,11 +14,10 @@ func LoadConfig(filePath string) (IConfig, error) { } type Config struct { - Port uint16 `yaml:"port"` - PostgresUrl string `yaml:"postgres_url"` - JwtSigningKey string `yaml:"jwt_signing_key" validate:"file"` - KafkaUrl string `yaml:"kafka_url"` - KafkaTopic string `yaml:"kafka_topic"` + Port uint16 `yaml:"port"` + PostgresUrl string `yaml:"postgres_url"` + KafkaUrl string `yaml:"kafka_url"` + KafkaTopic string `yaml:"kafka_topic"` } func (c *Config) GetPort() uint16 { @@ -30,10 +28,6 @@ func (c *Config) GetPostgresUrl() string { return c.PostgresUrl } -func (c *Config) GetJwtSigningKey() string { - return c.JwtSigningKey -} - func (c *Config) GetKafkaUrl() string { return c.KafkaUrl } diff --git a/cmd/backend/config.yaml b/cmd/backend/config.yaml deleted file mode 100644 index e50060a..0000000 --- a/cmd/backend/config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -port: 8080 -postgres_url: "postgres://postgres:postgres@localhost:5432/postgres" -jwt_signing_key: "./jwt_signing_key" -kafka_url: "localhost:9091" -kafka_topic: "events" \ No newline at end of file diff --git a/cmd/shortlinks/conf.yml b/cmd/shortlinks/conf.yml deleted file mode 100644 index 7c8980d..0000000 --- a/cmd/shortlinks/conf.yml +++ /dev/null @@ -1,4 +0,0 @@ -service_url: http://localhost:8081 -http_port: 8081 -grpc_port: 8082 -postgres_url: "postgres://postgres:postgres@localhost:5432/postgres" \ No newline at end of file diff --git a/cmd/shortlinks/main.go b/cmd/shortlinks/main.go index 28dcc8b..5a7cef2 100644 --- a/cmd/shortlinks/main.go +++ b/cmd/shortlinks/main.go @@ -36,7 +36,6 @@ func main() { rootCmd.MarkPersistentFlagRequired("config") rootCmd.PersistentFlags().StringVarP(&logPath, "logfile", "l", "", "path to log file") - rootCmd.MarkPersistentFlagRequired("logfile") if err := rootCmd.Execute(); err != nil { panic(err) diff --git a/cmd/shortlinks/makefile b/cmd/shortlinks/makefile deleted file mode 100644 index 7145e0e..0000000 --- a/cmd/shortlinks/makefile +++ /dev/null @@ -1,2 +0,0 @@ -run: - go run . -c ./conf.yml -l ./../../.run/shortlinks.log \ No newline at end of file diff --git a/docker-compose.yaml b/compose.yml similarity index 59% rename from docker-compose.yaml rename to compose.yml index 87d56c3..1d5a649 100644 --- a/docker-compose.yaml +++ b/compose.yml @@ -31,45 +31,22 @@ services: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - grafana: - image: grafana/grafana:11.1.4 - shm_size: 256mb - ports: - - 3000:3000 - extra_hosts: - - "host.docker.internal:host-gateway" - volumes: - - grafana-volume:/var/lib/grafana - - ./deploy/grafana-ds.yaml:/etc/grafana/provisioning/datasources/datasources.yaml - - prometheus: - image: prom/prometheus:v2.54.0 - shm_size: 256mb - user: root - ports: - - 9090:9090 - extra_hosts: - - "host.docker.internal:host-gateway" - volumes: - - prometheus-volume:/etc/prometheus - - ./deploy/prometheus.yml:/etc/prometheus/prometheus.yml - - node_exporter: - image: quay.io/prometheus/node-exporter:latest - pid: host - command: - - '--path.procfs=/host/proc' - - '--path.rootfs=/rootfs' - - '--path.sysfs=/host/sys' - - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' - volumes: - - /proc:/host/proc:ro - - /sys:/host/sys:ro - - /:/rootfs:ro - extra_hosts: - - "host.docker.internal:host-gateway" - ports: - - 9100:9100 + # node_exporter: + # image: quay.io/prometheus/node-exporter:latest + # pid: host + # command: + # - '--path.procfs=/host/proc' + # - '--path.rootfs=/rootfs' + # - '--path.sysfs=/host/sys' + # - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + # volumes: + # - /proc:/host/proc:ro + # - /sys:/host/sys:ro + # - /:/rootfs:ro + # extra_hosts: + # - "host.docker.internal:host-gateway" + # ports: + # - 9100:9100 otel-collector: image: otel/opentelemetry-collector-contrib:0.108.0 @@ -82,25 +59,6 @@ services: # - 4317:4317 # OTLP gRPC receiver - 4318:4318 # OTLP http receiver - tempo-init: - image: &tempoImage grafana/tempo:r177-60780f7 - user: root - entrypoint: - - "chown" - - "10001:10001" - - "/var/tempo" - volumes: - - tempo-volume:/var/tempo - - tempo: - image: *tempoImage - command: [ "-config.file=/etc/tempo.yaml" ] - volumes: - - ./deploy/tempo.yaml:/etc/tempo.yaml - - tempo-volume:/var/tempo - depends_on: - - tempo-init - kafka: image: &kafkaImage apache/kafka:3.8.0 healthcheck: @@ -133,35 +91,34 @@ services: entrypoint: > /bin/bash -c "/opt/kafka/bin/kafka-topics.sh --bootstrap-server http://kafka:9092 --create --topic events --partitions 6" + # minio: + # image: quay.io/minio/minio:latest + # command: ["server", "/data", "--console-address", ":9001"] + # healthcheck: + # test: 'mc ready local' + # interval: 1s + # environment: + # MINIO_ROOT_USER: miniouser + # MINIO_ROOT_PASSWORD: miniouser + # MINIO_ACCESS_KEY: miniokey + # MINIO_SECRET_KEY: miniokey + # ports: + # - 9000:9000 + # - 9001:9001 + # volumes: + # - minio-volume:/data - minio: - image: quay.io/minio/minio:latest - command: ["server", "/data", "--console-address", ":9001"] - healthcheck: - test: 'mc ready local' - interval: 1s - environment: - MINIO_ROOT_USER: miniouser - MINIO_ROOT_PASSWORD: miniouser - MINIO_ACCESS_KEY: miniokey - MINIO_SECRET_KEY: miniokey - ports: - - 9000:9000 - - 9001:9001 - volumes: - - minio-volume:/data - - minio-init: - image: quay.io/minio/mc:latest - depends_on: - - minio - entrypoint: > - /bin/sh -c " - /usr/bin/mc alias set myminio http://minio:9000 miniouser miniouser; - /usr/bin/mc mb minio/bucket; - /usr/bin/mc anonymous set public minio/bucket; - exit 0; - " + # minio-init: + # image: quay.io/minio/mc:latest + # depends_on: + # - minio + # entrypoint: > + # /bin/sh -c " + # /usr/bin/mc alias set myminio http://minio:9000 miniouser miniouser; + # /usr/bin/mc mb minio/bucket; + # /usr/bin/mc anonymous set public minio/bucket; + # exit 0; + # " smtp4dev: image: rnwood/smtp4dev:v3 @@ -179,9 +136,35 @@ services: - RelayOptions__Login=maillogin - RelayOptions__Password=mailpass + backend: + build: + dockerfile: ./backend.Dockerfile + context: . + ports: + - 8080:8080 + volumes: + - ./deploy/backend-config.yaml:/backend/config.yaml + - ./deploy/backend-jwt-privkey:/backend/backend-jwt-privkey + + notifyer: + build: + dockerfile: ./notifyer.Dockerfile + context: . + ports: + - 8081:8081 + volumes: + - ./deploy/notifyer-config.yaml:/backend/config.yaml + + shortlinks: + build: + dockerfile: ./shortlinks.Dockerfile + context: . + ports: + - 8082:8082 #http + - 8083:8083 #grpc + volumes: + - ./deploy/notifyer-config.yaml:/backend/config.yaml + volumes: postgres-volume: - grafana-volume: - tempo-volume: - prometheus-volume: minio-volume: \ No newline at end of file diff --git a/deploy/backend-config.yaml b/deploy/backend-config.yaml new file mode 100644 index 0000000..ffcbfac --- /dev/null +++ b/deploy/backend-config.yaml @@ -0,0 +1,5 @@ +port: 8080 +postgres_url: "postgres://postgres:postgres@postgres:5432/postgres" +jwt_signing_key: "./backend-jwt-privkey" +kafka_url: "kafka:9091" +kafka_topic: "events" \ No newline at end of file diff --git a/cmd/backend/jwt_signing_key b/deploy/backend-jwt-privkey similarity index 100% rename from cmd/backend/jwt_signing_key rename to deploy/backend-jwt-privkey diff --git a/cmd/notifyer/config.yaml b/deploy/notifyer-config.yaml similarity index 64% rename from cmd/notifyer/config.yaml rename to deploy/notifyer-config.yaml index 1762b99..83bb25a 100644 --- a/cmd/notifyer/config.yaml +++ b/deploy/notifyer-config.yaml @@ -1,13 +1,13 @@ app: - port: 8082 - serviceUrl: "http://localhost:8080" + port: 8081 + serviceUrl: "http://backend:8080" kafka: brokers: - - localhost:9091 + - kafka:9091 topic: events consumerGroupId: notifyer-group smtp: - server: localhost + server: smtp4dev port: 12333 login: "maillogin" password: "mailpass" diff --git a/deploy/shortlinks-config.yaml b/deploy/shortlinks-config.yaml new file mode 100644 index 0000000..d9d1ca2 --- /dev/null +++ b/deploy/shortlinks-config.yaml @@ -0,0 +1,4 @@ +service_url: http://shortlinks:8082 +http_port: 8082 +grpc_port: 8083 +postgres_url: "postgres://postgres:postgres@postgres:5432/postgres" \ No newline at end of file diff --git a/go.mod b/go.mod index bcec722..4fab989 100644 --- a/go.mod +++ b/go.mod @@ -8,71 +8,47 @@ require ( github.com/go-playground/validator/v10 v10.22.0 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/uuid v1.6.0 + github.com/jackc/pgx/v5 v5.7.2 github.com/prometheus/client_golang v1.20.2 github.com/rs/zerolog v1.33.0 github.com/segmentio/kafka-go v0.4.47 + github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.9.0 go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 go.opentelemetry.io/otel/sdk v1.29.0 go.opentelemetry.io/otel/trace v1.29.0 - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.31.0 + google.golang.org/grpc v1.65.0 + google.golang.org/protobuf v1.34.2 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v3 v3.0.1 ) -require ( - github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - 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/puddle/v2 v2.2.1 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/pierrec/lz4/v4 v4.1.15 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.19.0 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.9.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/sync v0.8.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/grpc v1.65.0 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect -) - require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bytedance/sonic v1.12.1 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/jackc/pgx/v5 v5.6.0 + github.com/goccy/go-json v0.10.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -80,17 +56,23 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pierrec/lz4/v4 v4.1.15 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/cobra v1.8.1 + github.com/spf13/pflag v1.0.6 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.9.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + golang.org/x/arch v0.8.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect ) diff --git a/go.sum b/go.sum index 49a2138..4e3bf6d 100644 --- a/go.sum +++ b/go.sum @@ -2,11 +2,10 @@ github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= -github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -16,16 +15,12 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= @@ -43,8 +38,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= @@ -55,26 +50,24 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= -github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -84,16 +77,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -108,8 +97,6 @@ github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -124,24 +111,12 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0= github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -154,8 +129,6 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -181,19 +154,14 @@ go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt3 go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= -go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= -golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -207,8 +175,8 @@ golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -220,8 +188,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -234,8 +202,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -256,9 +224,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/makefile b/makefile index 88d70ce..5810d6a 100644 --- a/makefile +++ b/makefile @@ -14,6 +14,6 @@ grpc: # --go-grpc_out=. --go-grpc_opt=paths=source_relative \ # helloworld/helloworld.proto -run: install release - mkdir -p ./.run - ./.build/release/backend -c ./misc/config.yaml -o ./.run/log.txt -p ./.run/cpu.pprof \ No newline at end of file +# run: install release +# mkdir -p ./.run +# ./.build/release/backend -c ./misc/config.yaml -o ./.run/log.txt -p ./.run/cpu.pprof \ No newline at end of file diff --git a/monitoring-compose.yml b/monitoring-compose.yml new file mode 100644 index 0000000..9d8268e --- /dev/null +++ b/monitoring-compose.yml @@ -0,0 +1,47 @@ +services: + grafana: + image: grafana/grafana:11.1.4 + shm_size: 256mb + ports: + - 3000:3000 + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - grafana-volume:/var/lib/grafana + - ./deploy/grafana-ds.yaml:/etc/grafana/provisioning/datasources/datasources.yaml + + prometheus: + image: prom/prometheus:v2.54.0 + shm_size: 256mb + user: root + ports: + - 9090:9090 + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - prometheus-volume:/etc/prometheus + - ./deploy/prometheus.yml:/etc/prometheus/prometheus.yml + + tempo-init: + image: &tempoImage grafana/tempo:r177-60780f7 + user: root + entrypoint: + - "chown" + - "10001:10001" + - "/var/tempo" + volumes: + - tempo-volume:/var/tempo + + tempo: + image: *tempoImage + command: [ "-config.file=/etc/tempo.yaml" ] + volumes: + - ./deploy/tempo.yaml:/etc/tempo.yaml + - tempo-volume:/var/tempo + depends_on: + - tempo-init + +volumes: + grafana-volume: + tempo-volume: + prometheus-volume: \ No newline at end of file diff --git a/notifyer.Dockerfile b/notifyer.Dockerfile new file mode 100644 index 0000000..87373a5 --- /dev/null +++ b/notifyer.Dockerfile @@ -0,0 +1,22 @@ +FROM golang:1.22-alpine AS builder +WORKDIR /build + +COPY go.mod go.sum ./ +RUN go mod download && go mod verify + +COPY cmd/notifyer cmd/notifyer +COPY pkg pkg +COPY internal internal + +RUN go build -ldflags "-s -w" -o ./app ./cmd/notifyer +RUN chmod +x ./app + +FROM alpine:3.21.2 AS production +WORKDIR /backend + +COPY --from=builder /build/app . +COPY deploy/notifyer-config.yaml ./config.yaml + +EXPOSE 8081 + +CMD ["./app", "-c", "config.yaml"] \ No newline at end of file diff --git a/Dockerfile b/shortlinks.Dockerfile similarity index 76% rename from Dockerfile rename to shortlinks.Dockerfile index 5406cdf..46d2271 100644 --- a/Dockerfile +++ b/shortlinks.Dockerfile @@ -4,19 +4,18 @@ WORKDIR /build COPY go.mod go.sum ./ RUN go mod download && go mod verify -COPY cmd/backend cmd/backend +COPY cmd/shortlinks cmd/shortlinks COPY pkg pkg COPY internal internal -RUN GOEXPERIMENT=boringcrypto go build -ldflags "-s -w" -o ./app ./cmd/backend +RUN GOEXPERIMENT=boringcrypto go build -ldflags "-s -w" -o ./app ./cmd/shortlinks RUN chmod +x ./app FROM alpine:3.21.2 AS production WORKDIR /backend COPY --from=builder /build/app . -COPY cmd/backend/config.yaml . -COPY cmd/backend/jwt_signing_key . +COPY deploy/shortlinks-config.yaml ./config.yaml EXPOSE 8080