From b0c79808c15a04e5ae650e1415ccb9c47ebcb6e9 Mon Sep 17 00:00:00 2001 From: yeri Date: Wed, 19 Nov 2025 17:41:15 -0400 Subject: [PATCH 01/11] Feat: Se implemento log en la sincronizacion. --- internal/sync/fetcher.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/sync/fetcher.go b/internal/sync/fetcher.go index 5b17a68..6136b4f 100644 --- a/internal/sync/fetcher.go +++ b/internal/sync/fetcher.go @@ -3,11 +3,12 @@ package fetcher import ( "encoding/json" "fmt" - "github.com/tuusuario/go-sync-service/internal/email" "strconv" "strings" "time" + "github.com/tuusuario/go-sync-service/internal/email" + "github.com/tuusuario/go-sync-service/internal/config" "github.com/tuusuario/go-sync-service/internal/db" "github.com/tuusuario/go-sync-service/internal/domain/dto" @@ -122,6 +123,9 @@ func FetchAllPaginatedManual[T any](host string, service dto.ServiceConfig, logP return nil, fmt.Errorf("%s ❌ error en la petición: %w", logPrefix, err) } + // DEBUG: imprimir lo que devuelve el servicio + config.Log.Debugf("%s Body recibido (REST paginado): %s", logPrefix, string(resp.Body())) + var result struct { Value []T `json:"value"` } @@ -206,6 +210,10 @@ func FetchAllPaginatedManual[T any](host string, service dto.ServiceConfig, logP if err != nil { return nil, fmt.Errorf("%s ❌ error en la petición: %w", logPrefix, err) } + + // DEBUG: imprimir lo que devuelve el servicio sin paginación + config.Log.Debugf("%s Body recibido (REST sin paginación): %s", logPrefix, string(resp.Body())) + var result struct { Value []T `json:"value"` } From 20ee14599e6b8a01af0019e84ad42e080c1cfca8 Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 00:21:30 -0400 Subject: [PATCH 02/11] main updated --- cmd/go-sync-service/main.go | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/cmd/go-sync-service/main.go b/cmd/go-sync-service/main.go index 04f9ffc..f7d0919 100644 --- a/cmd/go-sync-service/main.go +++ b/cmd/go-sync-service/main.go @@ -7,6 +7,7 @@ import ( "os" "os/signal" "syscall" + "time" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/tuusuario/go-sync-service/internal/config" @@ -16,25 +17,28 @@ import ( ) func main() { + // Configurar zona horaria por defecto del proceso + initTimezone() + // Cargar configuración conf, err := config.LoadConfig() if err != nil { - fmt.Println("❌ Error cargando configuración:", err) + fmt.Println("Error cargando configuración:", err) os.Exit(1) } // Inicializar logger con configuración config.InitLogger(conf) - config.Log.Info("🚀 Iniciando servicio: go-sync-service") + config.Log.Info("Iniciando servicio: go-sync-service") emailService := email.NewSMTPEmailService(conf) // Conexión a Redis redisClient := config.GetRedisClient(conf) if err := redisClient.Ping(context.Background()).Err(); err != nil { - config.Log.Fatalf("❌ Redis no disponible: %v", err) + config.Log.Fatalf("Redis no disponible: %v", err) } - config.Log.Info("✅ Redis conectado") + config.Log.Info("Redis conectado") // Crear proveedor de configuración desde Redis redisManager := config.NewRedisManager(redisClient) @@ -43,14 +47,14 @@ func main() { // Conexión a Base de Datos database := config.GetDatabaseConnection(conf) if database == nil { - config.Log.Fatal("❌ No se pudo establecer la conexión con la base de datos.") + config.Log.Fatal("No se pudo establecer la conexión con la base de datos.") } - config.Log.Info("✅ Conexión a base de datos establecida") + config.Log.Info("Conexión a base de datos establecida") scheduler.Start(context.Background(), redisClient, redisConfigProvider, database, *emailService) - config.Log.Info("✅ Scheduler en ejecución y escuchando recargas") + config.Log.Info("Scheduler en ejecución y escuchando recargas") - //metrics Grafana + // Metrics Grafana/Prometheus metrics.Register() startMetricsServer() @@ -59,13 +63,24 @@ func main() { signal.Notify(stop, os.Interrupt, syscall.SIGTERM) <-stop - config.Log.Info("🛑 Señal de apagado recibida, cerrando servicio...") + config.Log.Info("Señal de apagado recibida, cerrando servicio...") +} + +func initTimezone() { + loc, err := time.LoadLocation("America/La_Paz") + if err != nil { + // Si falla la carga, mantenemos la zona por defecto del entorno + // y solo registramos el problema en stdout para no depender del logger aún. + fmt.Println("No se pudo cargar la zona horaria America/La_Paz:", err) + return + } + time.Local = loc } func startMetricsServer() { go func() { http.Handle("/metrics", promhttp.Handler()) - config.Log.Info("📊 Servidor de métricas en :9100/metrics") - http.ListenAndServe(":9100", nil) + config.Log.Info("Servidor de métricas en :9100/metrics") + _ = http.ListenAndServe(":9100", nil) }() } From c312cb79ba98c554d690c7e86fcdd339fe14645b Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 00:27:30 -0400 Subject: [PATCH 03/11] logger updated --- internal/config/logger.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/internal/config/logger.go b/internal/config/logger.go index 635a85e..0dc83ba 100644 --- a/internal/config/logger.go +++ b/internal/config/logger.go @@ -17,9 +17,34 @@ import ( // Log instancia global del logger var Log = logrus.New() +type LocalTimeHook struct { + loc *time.Location +} +func (h LocalTimeHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h LocalTimeHook) Fire(e *logrus.Entry) error { + if h.loc != nil { + e.Time = e.Time.In(h.loc) + } + return nil +} func InitLogger(cfg *Config) { +// ========================= + // Zona horaria Bolivia + // ========================= + loc, err := time.LoadLocation("America/La_Paz") + if err != nil { + // Fallback robusto para contenedores sin tzdata + loc = time.FixedZone("America/La_Paz", -4*60*60) + } + time.Local = loc + + // Hook para forzar timestamps de Logrus a hora Bolivia + Log.AddHook(LocalTimeHook{loc: loc}) // Configurar rotación de logs con Lumberjack rotator := &lumberjack.Logger{ Filename: cfg.LogFilePath, // Archivo de logs From 9eccbb71f472145e5f0c24617d1a0c05afb46e03 Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 01:11:49 -0400 Subject: [PATCH 04/11] updated --- .env | 6 +++--- docker-compose.yml | 26 ++++++++++++++++++++++++++ internal/config/logger.go | 2 +- internal/db/operaciones.go | 6 +++--- internal/http/session.go | 4 ++-- internal/utils/redis_loader.go | 2 +- 6 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 docker-compose.yml diff --git a/.env b/.env index 6992bbb..57ab332 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ #Configuración de la base de datos -DB_HOST=localhost -DB_PORT=5434 +DB_HOST=db +DB_PORT=5432 DB_USER=admin DB_PASSWORD=admin DB_NAME=gotestdb @@ -8,7 +8,7 @@ DB_MAX_OPEN_CONNS=25 DB_MAX_IDLE_CONNS=10 DB_CONN_MAX_LIFETIME=30m #Redis -REDIS_HOST=localhost +REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD=TuPasswordSegura123 REDIS_DB=0 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..36e9c7d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +services: + syncronizador: + container_name: rendicion_gasto_syncronizador + environment: + - TZ=America/La_Paz + - LANG=es_BO.UTF-8 + - LC_ALL=es_BO.UTF-8 + build: + context: . + dockerfile: Dockerfile + restart: always + env_file: + - .env + volumes: + - ./logs:/app/logs + networks: + - network_emba + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + compress: "true" +networks: + network_emba: + external: true \ No newline at end of file diff --git a/internal/config/logger.go b/internal/config/logger.go index 0dc83ba..a9d0753 100644 --- a/internal/config/logger.go +++ b/internal/config/logger.go @@ -81,7 +81,7 @@ func InitLogger(cfg *Config) { //elastic if cfg.ElasticEnabled { - Log.Debug("✅ Elasticsearch enabled") + Log.Info("✅ Elasticsearch enabled") es, err := elasticsearch.NewClient(elasticsearch.Config{ Addresses: []string{cfg.ElasticURL}, }) diff --git a/internal/db/operaciones.go b/internal/db/operaciones.go index 549237c..88d964e 100644 --- a/internal/db/operaciones.go +++ b/internal/db/operaciones.go @@ -64,7 +64,7 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st // Procesar lote if len(batch) == batchSize || i == len(*rawData)-1 { - config.Log.Debugf(logPrefix+" Procesando batch de %d registros", len(batch)) + config.Log.Info(logPrefix+" Procesando batch de %d registros", len(batch)) if len(persistencia.UpdateBy) > 0 { // Updates con múltiples campos @@ -173,12 +173,12 @@ func (g *GormDatabase) GetCredencialesFromTemplate(whereTemplate string, variabl query := whereTemplate var args []interface{} - config.Log.Debugf("🔎 Variables recibidas:") + config.Log.Info("🔎 Variables recibidas:") for k, v := range variables { placeholder := "@" + k query = strings.ReplaceAll(query, placeholder, "?") args = append(args, v) - config.Log.Debugf(" %s = %v", k, v) + config.Log.Infof(" %s = %v", k, v) } config.Log.Debugf("📝 Consulta final construida:") diff --git a/internal/http/session.go b/internal/http/session.go index b5336a0..a4c1ec7 100644 --- a/internal/http/session.go +++ b/internal/http/session.go @@ -155,13 +155,13 @@ func prepareAuthBody(auth dto.ServiceConfig, cred *model.CredencialesSAP, logPre } if auth.GQL { - config.Log.Debugf("%v 🧠 Preparando auth para GraphQL", logPrefix) + config.Log.Infof("%v 🧠 Preparando auth para GraphQL", logPrefix) auth.Rest.Body = map[string]string{ "username": cred.UserName, "password": cred.Password, } } else { - config.Log.Debugf("%v🧠 Preparando auth para REST", logPrefix) + config.Log.Infof("%v🧠 Preparando auth para REST", logPrefix) auth.Rest.Body = map[string]string{ "CompanyDB": cred.CompanyDB, "UserName": cred.UserName, diff --git a/internal/utils/redis_loader.go b/internal/utils/redis_loader.go index d22bc77..df0b7f4 100644 --- a/internal/utils/redis_loader.go +++ b/internal/utils/redis_loader.go @@ -17,7 +17,7 @@ func CargarDesdeRedis[T any](cfg ports.RedisConfigProvider, clave string) (*T, e return nil, fmt.Errorf("error al obtener clave [%s] de redis: %w", clave, err) } - config.Log.Debugf("🔑 Clave [%s] obtenida de Redis: %s", clave, data) + config.Log.Infof("🔑 Clave [%s] obtenida de Redis: %s", clave, data) var result T if err := json.Unmarshal([]byte(data), &result); err != nil { config.Log.Errorf("❌ error al parsear JSON [%s]: %s", clave, err) From 9bca990b5560267b10fbe4e1d45e16f7385ad354 Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 01:19:27 -0400 Subject: [PATCH 05/11] .env updated --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 57ab332..56a17e0 100644 --- a/.env +++ b/.env @@ -41,7 +41,7 @@ ENCRYPTION_KEY=12345678901234567890123456789012 -AUTH_ENDPOINT= http://localhost:8085/auth/headers +AUTH_ENDPOINT= http://authsvc:8080/auth/headers AUTH_AUTORIZATION= 'Basic d29ya2VyLXJlbmRpY2lvbjpwcnVlYmE=' AUTH_METHOD=POST From 286a1bb5e02f6a90a9e9c83c73f048a77fe94cb4 Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 01:22:03 -0400 Subject: [PATCH 06/11] .env updated --- .env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 56a17e0..532e8ed 100644 --- a/.env +++ b/.env @@ -23,11 +23,11 @@ LOG_MAX_AGE=30 LOG_COMPRESS=true #Cliente Rest -TIMEOUT_SECONDS= 30 +TIMEOUT_SECONDS=30 RETRY_COUNT=3 TLS_SKIP_VERIFY=true LOG_REQUESTS=false -ENABLE_DEBUG= false +ENABLE_DEBUG=false WHERE_UNITS_BUSINESS=company_name = @company_name AND company_db = @company_db AND status = 'A' From 548f6b628edc08263ce8b0d7601b53bfc6a79e99 Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 01:58:48 -0400 Subject: [PATCH 07/11] warning deleted --- internal/db/operaciones.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/db/operaciones.go b/internal/db/operaciones.go index 88d964e..ff49727 100644 --- a/internal/db/operaciones.go +++ b/internal/db/operaciones.go @@ -109,7 +109,7 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st return res.Error } if res.RowsAffected == 0 { - config.Log.Warnf("%s ⚠️ Ninguna fila afectada con campos: %v valores: %v", + config.Log.Debugf("%s ⚠️ Ninguna fila afectada con campos: %v valores: %v", logPrefix, strings.Join(whereParts, " AND "), printWhereValues(whereValues)) } } From 5dd63276cfe6e53480c4dc42d4abdd463eb3d50c Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 02:08:51 -0400 Subject: [PATCH 08/11] operaciones updated --- internal/db/operaciones.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/db/operaciones.go b/internal/db/operaciones.go index ff49727..2e5319d 100644 --- a/internal/db/operaciones.go +++ b/internal/db/operaciones.go @@ -181,9 +181,9 @@ func (g *GormDatabase) GetCredencialesFromTemplate(whereTemplate string, variabl config.Log.Infof(" %s = %v", k, v) } - config.Log.Debugf("📝 Consulta final construida:") - config.Log.Debugf(" Query: %s", query) - config.Log.Debugf(" Args: %v", args) + config.Log.Info("📝 Consulta final construida:") + config.Log.Infof(" Query: %s", query) + config.Log.Infof(" Args: %v", args) err := g.db.Where(query, args...).First(&cred).Error return &cred, err From dd07901869ca76bd082e7302240e0092047384b2 Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 02:16:12 -0400 Subject: [PATCH 09/11] updated --- internal/db/operaciones.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/db/operaciones.go b/internal/db/operaciones.go index 2e5319d..2b3be25 100644 --- a/internal/db/operaciones.go +++ b/internal/db/operaciones.go @@ -64,7 +64,7 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st // Procesar lote if len(batch) == batchSize || i == len(*rawData)-1 { - config.Log.Info(logPrefix+" Procesando batch de %d registros", len(batch)) + config.Log.Println(logPrefix+" Procesando batch de %d registros", len(batch)) if len(persistencia.UpdateBy) > 0 { // Updates con múltiples campos @@ -81,7 +81,7 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st whereValues = append(whereValues, val) } if len(whereParts) < len(persistencia.UpdateBy) { - config.Log.Warnf("⚠️ Registro incompleto para update (faltan claves): %+v", row) + config.Log.Debugf("⚠️ Registro incompleto para update (faltan claves): %+v", row) continue } From 7619678a0bc914aea546703f008fd149ec8aae0d Mon Sep 17 00:00:00 2001 From: mercierj Date: Sun, 7 Dec 2025 02:21:44 -0400 Subject: [PATCH 10/11] linea comentada --- internal/db/operaciones.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/db/operaciones.go b/internal/db/operaciones.go index 2b3be25..69cfc34 100644 --- a/internal/db/operaciones.go +++ b/internal/db/operaciones.go @@ -108,10 +108,10 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st config.Log.Errorf("%s ❌ Error en update: %v", logPrefix, res.Error) return res.Error } - if res.RowsAffected == 0 { + /* if res.RowsAffected == 0 { config.Log.Debugf("%s ⚠️ Ninguna fila afectada con campos: %v valores: %v", logPrefix, strings.Join(whereParts, " AND "), printWhereValues(whereValues)) - } + } */ } } else { // Inserts con conflicto por PK (UPSERT) From b5b0139503b76841f2f00827f21e73e9dc79fac6 Mon Sep 17 00:00:00 2001 From: mercierj Date: Fri, 12 Dec 2025 11:06:45 -0400 Subject: [PATCH 11/11] .env updated --- .env | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.env b/.env index 532e8ed..2209bee 100644 --- a/.env +++ b/.env @@ -16,7 +16,7 @@ REDIS_TTL=10m REDIS_SUBSCRIBE=cron:reload #Log LOG_FILE_PATH=logs/syncronizador.log -LOG_LEVEL=debug +LOG_LEVEL=info LOG_MAX_SIZE=10 LOG_MAX_BACKUPS=7 LOG_MAX_AGE=30 @@ -41,13 +41,13 @@ ENCRYPTION_KEY=12345678901234567890123456789012 -AUTH_ENDPOINT= http://authsvc:8080/auth/headers -AUTH_AUTORIZATION= 'Basic d29ya2VyLXJlbmRpY2lvbjpwcnVlYmE=' +AUTH_ENDPOINT=http://authsvc:8080/auth/headers +AUTH_AUTORIZATION='Basic d29ya2VyLXJlbmRpY2lvbjpwcnVlYmE=' AUTH_METHOD=POST TM_HEADER_ORIGIN=https://azure-function.timemanagerweb.com TM_HEADER_TENANT_NAME=pruebas-dos -TM_HEADER_USER_AGENT='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' +TM_HEADER_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 # Configuración de correo SMTP