From 0cae56b13abb49610cfdc153f5abb53cf2f52016 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Sat, 13 Apr 2024 12:35:16 +0300 Subject: [PATCH 01/22] feat(storage): Add InitDb function and FindKeysByPattern function for finding date in to the redis --- .env | 3 ++ cmd/app/main.go | 20 +++++++++-- go.mod | 2 ++ go.sum | 4 +++ internal/storage/storage.go | 69 +++++++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..b8e4921 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +REDIS_ADDR=localhost:6379 +REDIS_PASSWORD= +REDIS_DB=0 \ No newline at end of file diff --git a/cmd/app/main.go b/cmd/app/main.go index a755b6f..acfd214 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -4,16 +4,32 @@ import ( "context" "os" "os/signal" - "syscall" - "stats-of/internal/app" "stats-of/internal/config" "stats-of/internal/logger" + "stats-of/internal/storage" + "syscall" + + "go.uber.org/zap" ) func main() { logger.InitLogger() logger.Log.Info("reading config...") + // --------------------------------------------------- + rdb := storage.InitDb() + pattern := "*chat:77541*" + keys, err := storage.FindKeysByPattern(rdb, pattern) + if err != nil { + logger.Log.Error("Ошибка при поиске ключей", zap.Error(err)) + } + + // Вывод результатов + for _, key := range keys { + logger.Log.Info(key) + } + // --------------------------------------------------- + config, err := config.LoadFromEnv() if err != nil { logger.Log.Info("failed to read config") diff --git a/go.mod b/go.mod index dd0a037..9d48336 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,8 @@ require github.com/prometheus/client_golang v1.19.0 require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/go-redis/redis v6.15.9+incompatible // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect diff --git a/go.sum b/go.sum index 35b6c7d..345e302 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,12 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 82be054..5450063 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -1 +1,70 @@ package storage + +import ( + "os" + "stats-of/internal/logger" + "strconv" + + "github.com/go-redis/redis" + "github.com/joho/godotenv" + "go.uber.org/zap" +) + +func InitDb() *redis.Client { + // Загрузка переменных из файла .env + err := godotenv.Load() + if err != nil { + logger.Log.Fatal("Ошибка при загрузке файла .env", zap.Error(err)) + } + + // Получение конфигурации из переменных окружения + addr := os.Getenv("REDIS_ADDR") + password := os.Getenv("REDIS_PASSWORD") + dbStr := os.Getenv("REDIS_DB") // Получаем значение как строку + + // Преобразуем значение DB из строки в число + db, err := strconv.Atoi(dbStr) + if err != nil { + logger.Log.Fatal("Ошибка при преобразовании REDIS_DB в число", zap.Error(err)) + } + + // Создаем новый клиент Redis с использованием переменных окружения + rdb := redis.NewClient(&redis.Options{ + Addr: addr, + Password: password, + DB: db, // Используем преобразованное значение + }) + + // Выполняем команду PING + pong, err := rdb.Ping().Result() + if err != nil { + logger.Log.Info("Ошибка при подключении к Redis", zap.Error(err)) + } + + // Logging with zap + logger.Log.Info("Ответ от Redis:", zap.String("response", pong)) + + return rdb +} + +// Функция для поиска ключей в Redis по шаблону +func FindKeysByPattern(rdb *redis.Client, pattern string) ([]string, error) { + + // Используем Scan для поиска ключей по шаблону без блокировки базы данных + var cursor uint64 + var keys []string + for { + var err error + var k []string + k, cursor, err = rdb.Scan(cursor, pattern, 0).Result() + if err != nil { + return nil, err // Возвращаем ошибку, если что-то пошло не так + } + keys = append(keys, k...) + if cursor == 0 { // Если курсор равен 0, значит обход всех ключей завершен + break + } + } + + return keys, nil // Возвращаем найденные ключи +} From c3655ed7bbf15307120ccb4a4c6c6ff5f5f1d2b8 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Sat, 13 Apr 2024 13:00:27 +0300 Subject: [PATCH 02/22] refactor(storage): Add RedisService structure --- cmd/app/main.go | 11 +++----- internal/storage/storage.go | 51 ++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/cmd/app/main.go b/cmd/app/main.go index acfd214..eb932f8 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -17,16 +17,13 @@ func main() { logger.InitLogger() logger.Log.Info("reading config...") // --------------------------------------------------- - rdb := storage.InitDb() - pattern := "*chat:77541*" - keys, err := storage.FindKeysByPattern(rdb, pattern) + redisService := storage.NewRedisService() + keys, err := redisService.FindKeysByPattern("*pattern*") if err != nil { - logger.Log.Error("Ошибка при поиске ключей", zap.Error(err)) + logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) } - - // Вывод результатов for _, key := range keys { - logger.Log.Info(key) + logger.Log.Info("Найден ключ", zap.String("key", key)) } // --------------------------------------------------- diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 5450063..e2f8912 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -2,69 +2,68 @@ package storage import ( "os" - "stats-of/internal/logger" "strconv" + "stats-of/internal/logger" + "github.com/go-redis/redis" "github.com/joho/godotenv" "go.uber.org/zap" ) -func InitDb() *redis.Client { - // Загрузка переменных из файла .env +// RedisService структура для работы с Redis +type RedisService struct { + Client *redis.Client +} + +// NewRedisService функция для создания нового экземпляра RedisService +func NewRedisService() *RedisService { + // Загрузка переменных окружения из файла .env err := godotenv.Load() if err != nil { logger.Log.Fatal("Ошибка при загрузке файла .env", zap.Error(err)) } - // Получение конфигурации из переменных окружения addr := os.Getenv("REDIS_ADDR") password := os.Getenv("REDIS_PASSWORD") - dbStr := os.Getenv("REDIS_DB") // Получаем значение как строку + dbStr := os.Getenv("REDIS_DB") - // Преобразуем значение DB из строки в число db, err := strconv.Atoi(dbStr) if err != nil { logger.Log.Fatal("Ошибка при преобразовании REDIS_DB в число", zap.Error(err)) } - // Создаем новый клиент Redis с использованием переменных окружения - rdb := redis.NewClient(&redis.Options{ + client := redis.NewClient(&redis.Options{ Addr: addr, Password: password, - DB: db, // Используем преобразованное значение + DB: db, }) - // Выполняем команду PING - pong, err := rdb.Ping().Result() + pong, err := client.Ping().Result() if err != nil { - logger.Log.Info("Ошибка при подключении к Redis", zap.Error(err)) + logger.Log.Fatal("Ошибка при подключении к Redis", zap.Error(err)) + } else { + logger.Log.Info("Успешное подключение к Redis", zap.String("pong", pong)) } - // Logging with zap - logger.Log.Info("Ответ от Redis:", zap.String("response", pong)) - - return rdb + return &RedisService{Client: client} } -// Функция для поиска ключей в Redis по шаблону -func FindKeysByPattern(rdb *redis.Client, pattern string) ([]string, error) { - - // Используем Scan для поиска ключей по шаблону без блокировки базы данных +// FindKeysByPattern метод для поиска ключей в Redis по шаблону +func (rs *RedisService) FindKeysByPattern(pattern string) ([]string, error) { var cursor uint64 var keys []string for { - var err error - var k []string - k, cursor, err = rdb.Scan(cursor, pattern, 0).Result() + k, nextCursor, err := rs.Client.Scan(cursor, pattern, 0).Result() if err != nil { - return nil, err // Возвращаем ошибку, если что-то пошло не так + return nil, err } keys = append(keys, k...) - if cursor == 0 { // Если курсор равен 0, значит обход всех ключей завершен + cursor = nextCursor + if cursor == 0 { break } } - return keys, nil // Возвращаем найденные ключи + return keys, nil } From 2d3ec31c75a19e89a8dc166f65376911857498ad Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Sat, 13 Apr 2024 13:11:49 +0300 Subject: [PATCH 03/22] feat(storage): Add FindKeyByGetRequest function --- .gitignore | 5 +++++ cmd/app/main.go | 11 +++++++++++ internal/storage/storage.go | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/.gitignore b/.gitignore index b8c2a57..898252d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ vendor/ # Go workspace file go.work + +docker-compose.yml +internal/logger/logs +mytestfiles +internal/storagetestsutils diff --git a/cmd/app/main.go b/cmd/app/main.go index eb932f8..8862249 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -25,6 +25,17 @@ func main() { for _, key := range keys { logger.Log.Info("Найден ключ", zap.String("key", key)) } + + key := "chat:5481:user:121190002:type:CHANNEL" + + // Получение значения по ключу + value, err := storage.NewRedisService().FindKeyByGetRequest(key) + if err != nil { + logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) + } + + // Вывод полученного значения + logger.Log.Info("Полученное значение", zap.String("value", value)) // --------------------------------------------------- config, err := config.LoadFromEnv() diff --git a/internal/storage/storage.go b/internal/storage/storage.go index e2f8912..aa75b23 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -67,3 +67,14 @@ func (rs *RedisService) FindKeysByPattern(pattern string) ([]string, error) { return keys, nil } + +func (rs *RedisService) FindKeyByGetRequest(key string) (string, error) { + // Используем метод Get клиента Redis для получения значения по ключу + result, err := rs.Client.Get(key).Result() + if err != nil { + // Если произошла ошибка, возвращаем пустую строку и саму ошибку + return "", err + } + // Возвращаем результат и nil в качестве ошибки, если всё прошло успешно + return result, nil +} From a925211c6815816198c9e2f47d2a321e122c4c5f Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Sat, 13 Apr 2024 13:52:27 +0300 Subject: [PATCH 04/22] refactor(main): Move the search logic to Redis from main.go to README.md file in the storage package --- cmd/app/main.go | 24 ------------------------ internal/storage/README.md | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 24 deletions(-) create mode 100644 internal/storage/README.md diff --git a/cmd/app/main.go b/cmd/app/main.go index 8862249..7f65470 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -7,36 +7,12 @@ import ( "stats-of/internal/app" "stats-of/internal/config" "stats-of/internal/logger" - "stats-of/internal/storage" "syscall" - - "go.uber.org/zap" ) func main() { logger.InitLogger() logger.Log.Info("reading config...") - // --------------------------------------------------- - redisService := storage.NewRedisService() - keys, err := redisService.FindKeysByPattern("*pattern*") - if err != nil { - logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) - } - for _, key := range keys { - logger.Log.Info("Найден ключ", zap.String("key", key)) - } - - key := "chat:5481:user:121190002:type:CHANNEL" - - // Получение значения по ключу - value, err := storage.NewRedisService().FindKeyByGetRequest(key) - if err != nil { - logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) - } - - // Вывод полученного значения - logger.Log.Info("Полученное значение", zap.String("value", value)) - // --------------------------------------------------- config, err := config.LoadFromEnv() if err != nil { diff --git a/internal/storage/README.md b/internal/storage/README.md new file mode 100644 index 0000000..8bbd334 --- /dev/null +++ b/internal/storage/README.md @@ -0,0 +1,27 @@ +## Пример реализации функций поиска данных в redis + + +``` +// --------------------------------------------------- + redisService := storage.NewRedisService() + keys, err := redisService.FindKeysByPattern("*pattern*") + if err != nil { + logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) + } + for _, key := range keys { + logger.Log.Info("Найден ключ", zap.String("key", key)) + } + + key := "chat:5481:user:121190002:type:CHANNEL" + + // Получение значения по ключу + value, err := storage.NewRedisService().FindKeyByGetRequest(key) + if err != nil { + logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) + } + + // Вывод полученного значения + logger.Log.Info("Полученное значение", zap.String("value", value)) + // --------------------------------------------------- + + ``` \ No newline at end of file From 4cc2470fd861e354d0e357c354e8b378154c4550 Mon Sep 17 00:00:00 2001 From: Evgeniy Sedov Date: Tue, 16 Apr 2024 17:36:42 +0700 Subject: [PATCH 05/22] adds storage interface and redis implementation --- go.mod | 14 +++-- go.sum | 89 ++++++++++++++++++++++++++++++- internal/storage/README.md | 42 +++++++-------- internal/storage/redis/options.go | 42 +++++++++++++++ internal/storage/redis/storage.go | 60 +++++++++++++++++++++ internal/storage/storage.go | 87 ++++++++---------------------- 6 files changed, 241 insertions(+), 93 deletions(-) create mode 100644 internal/storage/redis/options.go create mode 100644 internal/storage/redis/storage.go diff --git a/go.mod b/go.mod index 9d48336..76d3a55 100644 --- a/go.mod +++ b/go.mod @@ -2,18 +2,22 @@ module stats-of go 1.22.1 -require github.com/prometheus/client_golang v1.19.0 +require ( + github.com/go-redis/redis v6.15.9+incompatible + github.com/joho/godotenv v1.5.1 + github.com/prometheus/client_golang v1.19.0 + go.uber.org/zap v1.27.0 +) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/go-redis/redis v6.15.9+incompatible // indirect - github.com/joho/godotenv v1.5.1 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/onsi/gomega v1.32.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect go.uber.org/multierr v1.10.0 // indirect - go.uber.org/zap v1.27.0 // indirect golang.org/x/sys v0.16.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/go.sum b/go.sum index 345e302..f761fd2 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,43 @@ 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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +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/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= @@ -18,11 +47,67 @@ github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSz github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +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.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/storage/README.md b/internal/storage/README.md index 8bbd334..e056934 100644 --- a/internal/storage/README.md +++ b/internal/storage/README.md @@ -1,27 +1,25 @@ -## Пример реализации функций поиска данных в redis +# Пример реализации функций поиска данных в redis - -``` +```go // --------------------------------------------------- - redisService := storage.NewRedisService() - keys, err := redisService.FindKeysByPattern("*pattern*") - if err != nil { - logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) - } - for _, key := range keys { - logger.Log.Info("Найден ключ", zap.String("key", key)) - } - - key := "chat:5481:user:121190002:type:CHANNEL" +redisService := storage.NewRedisService() +keys, err := redisService.FindKeysByPattern("*pattern*") +if err != nil { + logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) +} - // Получение значения по ключу - value, err := storage.NewRedisService().FindKeyByGetRequest(key) - if err != nil { - logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) - } +for _, key := range keys { + logger.Log.Info("Найден ключ", zap.String("key", key)) +} +key := "chat:5481:user:121190002:type:CHANNEL" - // Вывод полученного значения - logger.Log.Info("Полученное значение", zap.String("value", value)) - // --------------------------------------------------- +// Получение значения по ключу +value, err := storage.NewRedisService().FindKeyByGetRequest(key) +if err != nil { + logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) +} - ``` \ No newline at end of file +// Вывод полученного значения +logger.Log.Info("Полученное значение", zap.String("value", value)) +// --------------------------------------------------- +``` diff --git a/internal/storage/redis/options.go b/internal/storage/redis/options.go new file mode 100644 index 0000000..7cea26f --- /dev/null +++ b/internal/storage/redis/options.go @@ -0,0 +1,42 @@ +package redis + +import ( + "github.com/joho/godotenv" + "go.uber.org/zap" + "os" + "stats-of/internal/logger" + "strconv" +) + +type ( + Options struct { + Addr string + Password string + DB int + } +) + +func CreateOptions() (opt *Options, err error) { + // Загрузка переменных окружения из файла .env + err = godotenv.Load() + if err != nil { + logger.Log.Fatal("Ошибка при загрузке файла .env", zap.Error(err)) + return nil, err + } + + addr := os.Getenv("REDIS_ADDR") + password := os.Getenv("REDIS_PASSWORD") + dbStr := os.Getenv("REDIS_DB") + + db, err := strconv.Atoi(dbStr) + if err != nil { + logger.Log.Fatal("Ошибка при преобразовании REDIS_DB в число", zap.Error(err)) + return nil, err + } + + return &Options{ + Addr: addr, + Password: password, + DB: db, + }, nil +} diff --git a/internal/storage/redis/storage.go b/internal/storage/redis/storage.go new file mode 100644 index 0000000..b2d4e6d --- /dev/null +++ b/internal/storage/redis/storage.go @@ -0,0 +1,60 @@ +package redis + +import ( + "context" + + "github.com/go-redis/redis" +) + +type ( + // Storage структура для работы с redis клиентом + Storage struct { + Client *redis.Client + } +) + +// NewRedisService функция для создания нового экземпляра DBService +func NewRedisClient(opt *Options) *Storage { + client := redis.NewClient(&redis.Options{ + Addr: opt.Addr, + Password: opt.Password, + DB: opt.DB, + }) + + return &Storage{Client: client} +} + +func (r *Storage) Ping(ctx context.Context) (err error) { + err = r.Ping(ctx) + return err +} + +// FindKeysByPattern метод для поиска ключей в Redis по шаблону +func (r *Storage) FindKeysByPattern(pattern string) ([]string, error) { + var cursor uint64 + var keys []string + for { + k, nextCursor, err := r.Client.Scan(cursor, pattern, 0).Result() + if err != nil { + return nil, err + } + keys = append(keys, k...) + cursor = nextCursor + if cursor == 0 { + break + } + } + + return keys, nil +} + +func (r *Storage) FindKeyByGetRequest(key string) (string, error) { + // Используем метод Get клиента Redis для получения значения по ключу + result, err := r.Client.Get(key).Result() + if err != nil { + // Если произошла ошибка, возвращаем пустую строку и саму ошибку + return "", err + } + // Возвращаем результат и nil в качестве ошибки, если всё прошло успешно + return result, nil +} diff --git a/internal/storage/storage.go b/internal/storage/storage.go index aa75b23..d906865 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -1,80 +1,39 @@ package storage import ( - "os" - "strconv" - - "stats-of/internal/logger" - - "github.com/go-redis/redis" - "github.com/joho/godotenv" - "go.uber.org/zap" + "context" + "stats-of/internal/storage/redis" ) -// RedisService структура для работы с Redis -type RedisService struct { - Client *redis.Client -} - -// NewRedisService функция для создания нового экземпляра RedisService -func NewRedisService() *RedisService { - // Загрузка переменных окружения из файла .env - err := godotenv.Load() - if err != nil { - logger.Log.Fatal("Ошибка при загрузке файла .env", zap.Error(err)) - } - - addr := os.Getenv("REDIS_ADDR") - password := os.Getenv("REDIS_PASSWORD") - dbStr := os.Getenv("REDIS_DB") +type ( + StorageType string - db, err := strconv.Atoi(dbStr) - if err != nil { - logger.Log.Fatal("Ошибка при преобразовании REDIS_DB в число", zap.Error(err)) + Storage interface { + // Open() error + Ping(ctx context.Context) error + FindKeysByPattern(pattern string) ([]string, error) + FindKeyByGetRequest(key string) (string, error) } +) - client := redis.NewClient(&redis.Options{ - Addr: addr, - Password: password, - DB: db, - }) - - pong, err := client.Ping().Result() - if err != nil { - logger.Log.Fatal("Ошибка при подключении к Redis", zap.Error(err)) - } else { - logger.Log.Info("Успешное подключение к Redis", zap.String("pong", pong)) - } +const ( + Redis StorageType = "redis" + // Map StorageType = "map" +) - return &RedisService{Client: client} -} +var client Storage -// FindKeysByPattern метод для поиска ключей в Redis по шаблону -func (rs *RedisService) FindKeysByPattern(pattern string) ([]string, error) { - var cursor uint64 - var keys []string - for { - k, nextCursor, err := rs.Client.Scan(cursor, pattern, 0).Result() +// Фабричная функция для создания экземпляра базы данных в соответствии с указанным типом +func NewStorage(storageType StorageType) (Storage, error) { + if storageType == Redis { + options, err := redis.CreateOptions() if err != nil { return nil, err } - keys = append(keys, k...) - cursor = nextCursor - if cursor == 0 { - break - } - } - - return keys, nil -} -func (rs *RedisService) FindKeyByGetRequest(key string) (string, error) { - // Используем метод Get клиента Redis для получения значения по ключу - result, err := rs.Client.Get(key).Result() - if err != nil { - // Если произошла ошибка, возвращаем пустую строку и саму ошибку - return "", err + client = redis.NewRedisClient(options) + return client, nil } - // Возвращаем результат и nil в качестве ошибки, если всё прошло успешно - return result, nil + + return nil, nil } From f6b6c19338bfbc5b4f3ee87fb6e402f8b6bdc1dc Mon Sep 17 00:00:00 2001 From: Evgeniy Sedov Date: Tue, 16 Apr 2024 19:16:19 +0700 Subject: [PATCH 06/22] changes name db on rdb from redis --- internal/storage/redis/options.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/storage/redis/options.go b/internal/storage/redis/options.go index 7cea26f..38eaf87 100644 --- a/internal/storage/redis/options.go +++ b/internal/storage/redis/options.go @@ -26,9 +26,9 @@ func CreateOptions() (opt *Options, err error) { addr := os.Getenv("REDIS_ADDR") password := os.Getenv("REDIS_PASSWORD") - dbStr := os.Getenv("REDIS_DB") + rdbStr := os.Getenv("REDIS_DB") - db, err := strconv.Atoi(dbStr) + rdb, err := strconv.Atoi(rdbStr) if err != nil { logger.Log.Fatal("Ошибка при преобразовании REDIS_DB в число", zap.Error(err)) return nil, err @@ -37,6 +37,6 @@ func CreateOptions() (opt *Options, err error) { return &Options{ Addr: addr, Password: password, - DB: db, + DB: rdb, }, nil } From 76d2ea71c1993352dbf367c6a510c2f2f3b3638c Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Tue, 16 Apr 2024 20:20:13 +0300 Subject: [PATCH 07/22] fix(storage): Fix bugs in the Ping and FindKeyByGetRequest functions, made changes to the README file --- internal/storage/README.md | 52 +++++++++++++++++++++---------- internal/storage/redis/storage.go | 23 +++++++++----- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/internal/storage/README.md b/internal/storage/README.md index e056934..ab520b2 100644 --- a/internal/storage/README.md +++ b/internal/storage/README.md @@ -2,24 +2,44 @@ ```go // --------------------------------------------------- -redisService := storage.NewRedisService() -keys, err := redisService.FindKeysByPattern("*pattern*") -if err != nil { - logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) -} +opts, err := redis.CreateOptions() + if err != nil { + logger.Log.Fatal("Не удалось загрузить настройки Redis", zap.Error(err)) + } -for _, key := range keys { - logger.Log.Info("Найден ключ", zap.String("key", key)) -} -key := "chat:5481:user:121190002:type:CHANNEL" + // Создание клиента Redis + redisClient := redis.NewRedisClient(opts) -// Получение значения по ключу -value, err := storage.NewRedisService().FindKeyByGetRequest(key) -if err != nil { - logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) -} + // Пример использования: Пинг до Redis для проверки соединения + err = redisClient.Ping(context.Background()) + if err != nil { + logger.Log.Fatal("Ошибка соединения с Redis", zap.Error(err)) + } else { + logger.Log.Info("Успешное соединение с Redis") + } -// Вывод полученного значения -logger.Log.Info("Полученное значение", zap.String("value", value)) + // Использование FindKeysByPattern для поиска ключей по шаблону + pattern := "*Pattern*" // Можно заменить на любой другой шаблон + keys, err := redisClient.FindKeysByPattern(pattern) + if err != nil { + logger.Log.Fatal("Ошибка при поиске ключей", zap.Error(err)) + } + + // Логгирование найденных ключей + for _, key := range keys { + logger.Log.Info("Найден ключ", zap.String("key", key)) + } + + key := "key" + + // Получение значения по ключу + value, err := redisClient.FindKeyByGetRequest(key) + if err != nil { + logger.Log.Fatal("Ошибка при получении значения из Redis", zap.Error(err)) + } else if value == "" { + logger.Log.Info("Ключ не найден", zap.String("key", key)) + } else { + logger.Log.Info("Полученное значение", zap.String("key", key), zap.String("value", value)) + } // --------------------------------------------------- ``` diff --git a/internal/storage/redis/storage.go b/internal/storage/redis/storage.go index b2d4e6d..dbd47f0 100644 --- a/internal/storage/redis/storage.go +++ b/internal/storage/redis/storage.go @@ -2,8 +2,10 @@ package redis import ( "context" + "stats-of/internal/logger" "github.com/go-redis/redis" + "go.uber.org/zap" ) type ( @@ -24,9 +26,13 @@ func NewRedisClient(opt *Options) *Storage { return &Storage{Client: client} } -func (r *Storage) Ping(ctx context.Context) (err error) { - err = r.Ping(ctx) - return err +func (r *Storage) Ping(ctx context.Context) error { + result, err := r.Client.Ping().Result() // Использование Ping из библиотеки go-redis + if err != nil { + return err + } + logger.Log.Info("Redis Ping Response", zap.String("response", result)) + return nil } // FindKeysByPattern метод для поиска ключей в Redis по шаблону @@ -49,12 +55,15 @@ func (r *Storage) FindKeysByPattern(pattern string) ([]string, error) { } func (r *Storage) FindKeyByGetRequest(key string) (string, error) { - // Используем метод Get клиента Redis для получения значения по ключу result, err := r.Client.Get(key).Result() - if err != nil { - // Если произошла ошибка, возвращаем пустую строку и саму ошибку + if err == redis.Nil { + // Ключ не найден + logger.Log.Info("Ключ не найден", zap.String("key", key)) + return "", nil // Возвращаем пустую строку без ошибки, если такое поведение приемлемо + } else if err != nil { + // Произошла другая ошибка return "", err } - // Возвращаем результат и nil в качестве ошибки, если всё прошло успешно + // Возвращаем результат, если ключ найден и ошибок нет return result, nil } From 3d6646e445b34e22391215f275aa732711af4019 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Thu, 18 Apr 2024 23:57:04 +0300 Subject: [PATCH 08/22] feat(storage): Add logging to the NewRedisClient functoion --- internal/storage/redis/storage.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/storage/redis/storage.go b/internal/storage/redis/storage.go index dbd47f0..441cb5e 100644 --- a/internal/storage/redis/storage.go +++ b/internal/storage/redis/storage.go @@ -23,6 +23,17 @@ func NewRedisClient(opt *Options) *Storage { DB: opt.DB, }) + // Логирование при создании клиента + logger.Log.Info("Creating new Redis client", zap.String("address", opt.Addr), zap.Int("db", opt.DB)) + + // Проверка соединения с Redis + _, err := client.Ping().Result() + if err != nil { + logger.Log.Error("Failed to connect to Redis", zap.Error(err)) + } else { + logger.Log.Info("Connected to Redis successfully") + } + return &Storage{Client: client} } From dd107fb9a6d2515ce1f97922f91b22e55f81e680 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:01:14 +0300 Subject: [PATCH 09/22] feat(storage): Add logging to the Ping function --- internal/storage/redis/storage.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/internal/storage/redis/storage.go b/internal/storage/redis/storage.go index 441cb5e..65897e7 100644 --- a/internal/storage/redis/storage.go +++ b/internal/storage/redis/storage.go @@ -38,10 +38,19 @@ func NewRedisClient(opt *Options) *Storage { } func (r *Storage) Ping(ctx context.Context) error { - result, err := r.Client.Ping().Result() // Использование Ping из библиотеки go-redis + // Логирование перед отправкой запроса + logger.Log.Info("Sending ping to Redis") + + // Отправка ping и получение результата + result, err := r.Client.Ping().Result() + + // Логирование ошибки, если она произошла if err != nil { + logger.Log.Error("Failed to ping Redis", zap.Error(err)) return err } + + // Логирование успешного получения ответа logger.Log.Info("Redis Ping Response", zap.String("response", result)) return nil } From f1dd156ad2db9c6eac555e11e17e01653cd8c71a Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:09:03 +0300 Subject: [PATCH 10/22] feat(storage): Add logging to the FindKeysByPattern function --- internal/storage/redis/storage.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/storage/redis/storage.go b/internal/storage/redis/storage.go index 65897e7..22f34ae 100644 --- a/internal/storage/redis/storage.go +++ b/internal/storage/redis/storage.go @@ -57,20 +57,32 @@ func (r *Storage) Ping(ctx context.Context) error { // FindKeysByPattern метод для поиска ключей в Redis по шаблону func (r *Storage) FindKeysByPattern(pattern string) ([]string, error) { + // Логирование начала операции + logger.Log.Info("Starting key search by pattern", zap.String("pattern", pattern)) + var cursor uint64 var keys []string for { + // Выполнение команды SCAN для поиска ключей k, nextCursor, err := r.Client.Scan(cursor, pattern, 0).Result() if err != nil { + logger.Log.Error("Failed to scan keys", zap.Error(err)) return nil, err } + keys = append(keys, k...) cursor = nextCursor + + // Логирование промежуточных результатов + logger.Log.Info("Batch of keys fetched", zap.Strings("keys", k), zap.Uint64("nextCursor", nextCursor)) + if cursor == 0 { break } } + // Логирование успешного завершения операции + logger.Log.Info("Key search completed", zap.Int("totalKeys", len(keys))) return keys, nil } From f2ee257c322f2134e48672cb0c70ed0e915b3ed0 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:14:28 +0300 Subject: [PATCH 11/22] feat(storage): Add logging in to the FindKeyByGetRequest function --- internal/storage/redis/storage.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/storage/redis/storage.go b/internal/storage/redis/storage.go index 22f34ae..be08221 100644 --- a/internal/storage/redis/storage.go +++ b/internal/storage/redis/storage.go @@ -87,15 +87,20 @@ func (r *Storage) FindKeysByPattern(pattern string) ([]string, error) { } func (r *Storage) FindKeyByGetRequest(key string) (string, error) { + // Логирование попытки получения значения по ключу + logger.Log.Info("Attempting to retrieve key", zap.String("key", key)) + result, err := r.Client.Get(key).Result() if err == redis.Nil { - // Ключ не найден - logger.Log.Info("Ключ не найден", zap.String("key", key)) + // Логирование отсутствия ключа + logger.Log.Info("Key not found", zap.String("key", key)) return "", nil // Возвращаем пустую строку без ошибки, если такое поведение приемлемо } else if err != nil { - // Произошла другая ошибка + // Логирование ошибки при попытке получить ключ + logger.Log.Error("Error retrieving key", zap.String("key", key), zap.Error(err)) return "", err } - // Возвращаем результат, если ключ найден и ошибок нет + // Логирование успешного получения значения + logger.Log.Info("Key retrieved successfully", zap.String("key", key), zap.String("value", result)) return result, nil } From bea7bace31226bc4b919eb55b435c57689902bfd Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:20:16 +0300 Subject: [PATCH 12/22] feat(app): Add logging in to the New function --- internal/app/app.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/app/app.go b/internal/app/app.go index 114e791..ddf3d30 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -8,10 +8,13 @@ import ( "strconv" "time" - "github.com/prometheus/client_golang/prometheus/promhttp" "stats-of/internal/config" "stats-of/internal/entities" "stats-of/internal/healthz" + "stats-of/internal/logger" + + "github.com/prometheus/client_golang/prometheus/promhttp" + "go.uber.org/zap" ) var appInfo = &entities.AppInfo{ @@ -27,6 +30,9 @@ type App struct { } func New(config *config.Config) (*App, error) { + // Логирование начала создания нового экземпляра приложения + logger.Log.Info("Initializing new application instance", zap.Int("ServerPort", config.ServerPort)) + const ( defaultHTTPServerWriteTimeout = time.Second * 15 defaultHTTPServerReadTimeout = time.Second * 15 @@ -45,6 +51,11 @@ func New(config *config.Config) (*App, error) { ReadTimeout: defaultHTTPServerReadTimeout, } + // Логирование завершения инициализации сервера + logger.Log.Info("HTTP server configured", zap.String("address", app.server.Addr), + zap.Duration("writeTimeout", app.server.WriteTimeout), + zap.Duration("readTimeout", app.server.ReadTimeout)) + return app, nil } From 010608895dcebca7cb357b0f8f4e574836f1275c Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:47:53 +0300 Subject: [PATCH 13/22] feat(app): Add logging to the Run function --- internal/app/app.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/app/app.go b/internal/app/app.go index ddf3d30..35343c7 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -60,11 +60,18 @@ func New(config *config.Config) (*App, error) { } func (a *App) Run() error { + // Логирование попытки запуска сервера + logger.Log.Info("Starting HTTP server", zap.String("address", a.server.Addr)) + err := a.server.ListenAndServe() if err != nil && err != http.ErrServerClosed { - return fmt.Errorf("server was stop with err: %w", err) + // Логирование ошибки, если сервер не был закрыт нормально + logger.Log.Error("HTTP server stopped with error", zap.Error(err)) + return fmt.Errorf("server was stopped with error: %w", err) } + // Логирование нормального закрытия сервера + logger.Log.Info("HTTP server stopped gracefully") return nil } From 2cc9405192644fd802c9be7016b9043de082f75e Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:51:06 +0300 Subject: [PATCH 14/22] feat(app): Add logging to the stop function --- internal/app/app.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/app/app.go b/internal/app/app.go index 35343c7..fa19b73 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -76,11 +76,18 @@ func (a *App) Run() error { } func (a *App) stop(ctx context.Context) error { + // Логирование начала процесса остановки сервера + logger.Log.Info("Initiating server shutdown") + err := a.server.Shutdown(ctx) if err != nil { + // Логирование ошибки при попытке остановить сервер + logger.Log.Error("Error during server shutdown", zap.Error(err)) return fmt.Errorf("server was shutdown with error: %w", err) } + // Логирование успешного завершения остановки сервера + logger.Log.Info("Server shutdown successfully") return nil } From 3c5bbeb31ab4552c65aef4d75bd746a6a5d105b5 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 00:56:51 +0300 Subject: [PATCH 15/22] feat(app): Add logging to the GracefulStop function --- internal/app/app.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index fa19b73..10c8be5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -92,22 +92,33 @@ func (a *App) stop(ctx context.Context) error { } func (a *App) GracefulStop(serverCtx context.Context, sig <-chan os.Signal, serverStopCtx context.CancelFunc) { - <-sig + logger.Log.Info("Waiting for stop signal") + <-sig // Ожидание сигнала + + // Логирование получения сигнала + logger.Log.Info("Stop signal received, initiating graceful shutdown") + var timeOut = 30 * time.Second shutdownCtx, shutdownStopCtx := context.WithTimeout(serverCtx, timeOut) go func() { <-shutdownCtx.Done() if shutdownCtx.Err() == context.DeadlineExceeded { + // Логирование исчерпания времени ожидания + logger.Log.Error("Shutdown timed out, forcing exit") os.Exit(1) } }() err := a.stop(shutdownCtx) if err != nil { + // Логирование ошибки при попытке остановить сервер + logger.Log.Error("Error during server shutdown", zap.Error(err)) os.Exit(1) } - serverStopCtx() - shutdownStopCtx() + // Логирование успешного завершения процесса остановки + logger.Log.Info("Server shutdown completed successfully") + serverStopCtx() // Остановка контекста сервера + shutdownStopCtx() // Остановка контекста тайм-аута } From 7c827665f541ab7263d61605e40f01e4f315ecbe Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 01:41:27 +0300 Subject: [PATCH 16/22] feat(config): Add logging to the LoadFromEnv function --- internal/config/config.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/internal/config/config.go b/internal/config/config.go index ef72105..6742e23 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,7 +3,10 @@ package config import ( "fmt" "os" + "stats-of/internal/logger" "strconv" + + "go.uber.org/zap" ) const ( @@ -15,17 +18,26 @@ type Config struct { } func LoadFromEnv() (*Config, error) { + // Логирование начала загрузки конфигурации + logger.Log.Info("Loading configuration from environment variables") + conf := &Config{} var err error serverPort := os.Getenv("SERVER_PORT") if serverPort == "" { + // Логирование использования порта по умолчанию при отсутствии переменной окружения + logger.Log.Info("SERVER_PORT not set, using default", zap.String("defaultServerPort", defaultServerPort)) serverPort = defaultServerPort } conf.ServerPort, err = strconv.Atoi(serverPort) if err != nil { - return nil, fmt.Errorf("failed to parse %s as int: %w", os.Getenv("SERVER_PORT"), err) + // Логирование ошибки при преобразовании порта из строки в число + logger.Log.Error("Failed to parse SERVER_PORT as integer", zap.String("serverPort", serverPort), zap.Error(err)) + return nil, fmt.Errorf("failed to parse %s as int: %w", serverPort, err) } + // Логирование успешной загрузки конфигурации + logger.Log.Info("Configuration loaded successfully", zap.Int("serverPort", conf.ServerPort)) return conf, nil } From cec54bfa0047b68eff2be1989cd428a8c5f05136 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 01:44:59 +0300 Subject: [PATCH 17/22] feat(endpoint): Add logging to the MakeHandler function --- internal/healthz/endpoint.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/healthz/endpoint.go b/internal/healthz/endpoint.go index 993511e..cc1b906 100644 --- a/internal/healthz/endpoint.go +++ b/internal/healthz/endpoint.go @@ -5,7 +5,10 @@ import ( "net/http" "stats-of/internal/entities" + "stats-of/internal/logger" "stats-of/internal/utils" + + "go.uber.org/zap" ) type response struct { @@ -25,9 +28,18 @@ func MakeHandler(info *entities.AppInfo) func(w http.ResponseWriter, r *http.Req GitTag: info.GitTag, GitHash: info.GitHash, } + + // Логирование попытки отправки ответа + logger.Log.Info("Sending application info response", zap.Any("response", response)) + err := utils.SuccessRespondWith200(w, response) if err != nil { + // Логирование ошибки при отправке ответа + logger.Log.Error("Failed to send application info response", zap.Any("response", response), zap.Error(err)) fmt.Printf("failed to decode response = %v, error = %v\n", response, err) + } else { + // Логирование успешной отправки ответа + logger.Log.Info("Application info response sent successfully") } } } From a26ed81bf0f3e0be8e47548027c81f58ec23594b Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 01:55:03 +0300 Subject: [PATCH 18/22] feat(storage): Add logging to the NewStorage function --- internal/storage/storage.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/internal/storage/storage.go b/internal/storage/storage.go index d906865..1dfa3c3 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -2,7 +2,11 @@ package storage import ( "context" + "fmt" + "stats-of/internal/logger" "stats-of/internal/storage/redis" + + "go.uber.org/zap" ) type ( @@ -25,15 +29,23 @@ var client Storage // Фабричная функция для создания экземпляра базы данных в соответствии с указанным типом func NewStorage(storageType StorageType) (Storage, error) { + logger.Log.Info("Initializing new storage", zap.String("storageType", string(storageType))) + if storageType == Redis { + // Создание опций для Redis options, err := redis.CreateOptions() if err != nil { + logger.Log.Error("Failed to create Redis options", zap.Error(err)) return nil, err } - client = redis.NewRedisClient(options) + // Создание клиента Redis + client := redis.NewRedisClient(options) + logger.Log.Info("Redis client created successfully") return client, nil } - return nil, nil + // Если тип хранилища не поддерживается или не указан + logger.Log.Warn("Storage type not supported or not specified", zap.String("storageType", string(storageType))) + return nil, fmt.Errorf("storage type '%s' is not supported", storageType) } From a869241d535d5b1cc419ad6e8aba9de450e077d1 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 02:01:49 +0300 Subject: [PATCH 19/22] feat(utils): Add logging to the RespondWithJSON function --- internal/utils/utils.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 13ac89e..2856f71 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -4,25 +4,43 @@ import ( "encoding/json" "fmt" "net/http" + "stats-of/internal/logger" + + "go.uber.org/zap" ) func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) error { + // Логирование попытки преобразования payload в JSON + logger.Log.Info("Attempting to marshal payload to JSON", zap.Any("payload", payload)) + response, err := json.Marshal(payload) if err != nil { - respondErr := RespondWithError(w, - http.StatusInternalServerError, - http.StatusText(http.StatusInternalServerError)) + // Логирование ошибки маршалинга + logger.Log.Error("Failed to marshal payload", zap.Error(err)) + + // Попытка отправить ответ об ошибке + respondErr := RespondWithError(w, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) if respondErr != nil { + // Логирование ошибки при отправке HTTP ответа об ошибке + logger.Log.Error("Failed to send error response", zap.Error(respondErr)) return err } return fmt.Errorf("failed to marshall payload: %w", err) } + // Установка заголовков ответа w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) + + // Отправка JSON ответа if _, err = w.Write(response); err != nil { + // Логирование ошибки при записи ответа + logger.Log.Error("Failed to write JSON response", zap.Error(err)) return fmt.Errorf("failed to write response: %w", err) } + + // Логирование успешной отправки ответа + logger.Log.Info("JSON response sent successfully", zap.Int("statusCode", code), zap.ByteString("response", response)) return nil } From 9585738accbd942410359571aab00d999cf0018a Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 02:04:47 +0300 Subject: [PATCH 20/22] fefat(utils): Add logging to the RespondWithError function --- internal/utils/utils.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 2856f71..c493f52 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -45,13 +45,26 @@ func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) error } func RespondWithError(w http.ResponseWriter, code int, message string) error { - return RespondWithJSON(w, + // Логирование попытки отправить ошибочный ответ + logger.Log.Info("Attempting to respond with error", zap.Int("statusCode", code), zap.String("errorMessage", message)) + + err := RespondWithJSON(w, code, struct { Error string `json:"error"` }{ Error: message, }) + + if err != nil { + // Логирование ошибки при попытке отправить JSON ответ об ошибке + logger.Log.Error("Failed to respond with error JSON", zap.Error(err)) + return err + } + + // Логирование успешной отправки ошибочного ответа + logger.Log.Info("Error response sent successfully", zap.Int("statusCode", code)) + return nil } func RespondWith400(w http.ResponseWriter, message string) error { From a12fb204bb49d6c5a119039f7cd4155fde7fcdd9 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Fri, 19 Apr 2024 02:11:47 +0300 Subject: [PATCH 21/22] feat(utils): Add detailed logging to HTTP response functions This commit enhances the HTTP response utility functions with detailed logging at various stages of response handling. The following changes have been implemented: 1. Added informative logging statements before attempting to send HTTP responses in functions: RespondWith400, RespondWith404, RespondWith500, SuccessRespondWith200, and SuccessRespondWith201. These logs provide insights into the intended response status and content. 2. Included error logging to capture and report failures during the response sending process in all the aforementioned functions. This is crucial for diagnosing serialization issues, network problems, or server-side errors that might prevent successful response delivery. 3. Each function now logs successful responses, ensuring that there is a clear trace of successful operations and the exact content delivered in the response. These additions aim to improve monitoring, facilitate debugging, and enhance the overall reliability of the web service by providing better visibility into its operations and failures. --- internal/utils/utils.go | 47 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index c493f52..c981f53 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -68,31 +68,46 @@ func RespondWithError(w http.ResponseWriter, code int, message string) error { } func RespondWith400(w http.ResponseWriter, message string) error { - return RespondWithError(w, - http.StatusBadRequest, - message) + logger.Log.Info("Responding with 400 Bad Request", zap.String("message", message)) + err := RespondWithError(w, http.StatusBadRequest, message) + if err != nil { + logger.Log.Error("Failed to send 400 response", zap.Error(err)) + } + return err } func RespondWith404(w http.ResponseWriter) error { - return RespondWithError(w, - http.StatusNotFound, - http.StatusText(http.StatusNotFound)) + logger.Log.Info("Responding with 404 Not Found") + err := RespondWithError(w, http.StatusNotFound, http.StatusText(http.StatusNotFound)) + if err != nil { + logger.Log.Error("Failed to send 404 response", zap.Error(err)) + } + return err } func RespondWith500(w http.ResponseWriter) error { - return RespondWithError(w, - http.StatusInternalServerError, - http.StatusText(http.StatusInternalServerError)) + logger.Log.Info("Responding with 500 Internal Server Error") + err := RespondWithError(w, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) + if err != nil { + logger.Log.Error("Failed to send 500 response", zap.Error(err)) + } + return err } func SuccessRespondWith200(w http.ResponseWriter, payload interface{}) error { - return RespondWithJSON(w, - http.StatusOK, - payload) + logger.Log.Info("Responding with 200 OK", zap.Any("payload", payload)) + err := RespondWithJSON(w, http.StatusOK, payload) + if err != nil { + logger.Log.Error("Failed to send 200 response", zap.Error(err)) + } + return err } -func SuccessRepondWith201(w http.ResponseWriter, payload interface{}) error { - return RespondWithJSON(w, - http.StatusCreated, - payload) +func SuccessRespondWith201(w http.ResponseWriter, payload interface{}) error { + logger.Log.Info("Responding with 201 Created", zap.Any("payload", payload)) + err := RespondWithJSON(w, http.StatusCreated, payload) + if err != nil { + logger.Log.Error("Failed to send 201 response", zap.Error(err)) + } + return err } From c3810a7c261899c27e11e192f133c476bd4943c3 Mon Sep 17 00:00:00 2001 From: ryazanovs Date: Sat, 20 Apr 2024 17:46:56 +0300 Subject: [PATCH 22/22] refactor(app): Move RunApp() function to internal/app package --- cmd/app/main.go | 36 +++++------------------------------ internal/app/app.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/cmd/app/main.go b/cmd/app/main.go index 7f65470..2676eca 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -1,43 +1,17 @@ package main import ( - "context" - "os" - "os/signal" "stats-of/internal/app" - "stats-of/internal/config" "stats-of/internal/logger" - "syscall" + + "go.uber.org/zap" ) func main() { logger.InitLogger() - logger.Log.Info("reading config...") - - config, err := config.LoadFromEnv() - if err != nil { - logger.Log.Info("failed to read config") - os.Exit(1) - } + logger.Log.Info("Starting application and reading configuration...") - serverCtx, serverStopCtx := context.WithCancel(context.Background()) - app, err := app.New(config) - if err != nil { - logger.Log.Info("failed to read config") - os.Exit(1) + if err := app.RunApp(); err != nil { + logger.Log.Fatal("Error occurred", zap.Error(err)) } - - sig := make(chan os.Signal, 1) - signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - go func() { - app.GracefulStop(serverCtx, sig, serverStopCtx) - }() - - err = app.Run() - if err != nil { - logger.Log.Info("failed to read config") - os.Exit(1) - } - - <-serverCtx.Done() } diff --git a/internal/app/app.go b/internal/app/app.go index 10c8be5..31ec00a 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -5,7 +5,9 @@ import ( "fmt" "net/http" "os" + "os/signal" "strconv" + "syscall" "time" "stats-of/internal/config" @@ -122,3 +124,47 @@ func (a *App) GracefulStop(serverCtx context.Context, sig <-chan os.Signal, serv serverStopCtx() // Остановка контекста сервера shutdownStopCtx() // Остановка контекста тайм-аута } + +func RunApp() error { + // Load configuration from environment variables + appConfig, err := config.LoadFromEnv() + if err != nil { + logger.Log.Error("Failed to load configuration from environment", zap.Error(err)) + return fmt.Errorf("failed to load configuration from environment: %w", err) + } + logger.Log.Info("Configuration loaded successfully") + + // Initialize server context + serverCtx, serverStopCtx := context.WithCancel(context.Background()) + defer serverStopCtx() // Make sure the cancel function is called to prevent context leaks + + // Create a new application instance + myApp, err := New(appConfig) + if err != nil { + logger.Log.Error("Failed to initialize the application", zap.Error(err)) + return fmt.Errorf("failed to initialize the application: %w", err) + } + logger.Log.Info("Application initialized successfully") + + // Prepare to handle system signals + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + go func() { + logger.Log.Info("Waiting for system signals") + s := <-sig + logger.Log.Info("Received system signal", zap.String("signal", s.String())) + myApp.GracefulStop(serverCtx, sig, serverStopCtx) + }() + + // Start the main application loop + logger.Log.Info("Running the application...") + if err := myApp.Run(); err != nil { + logger.Log.Error("Failed to run the application", zap.Error(err)) + return fmt.Errorf("failed to run the application: %w", err) + } + + logger.Log.Info("Application is now running. Waiting for shutdown signal...") + <-serverCtx.Done() + logger.Log.Info("Application shutdown completed successfully") + return nil +}