package logger import ( "api-soap-facturacion/internal/config" "encoding/json" "fmt" "go.uber.org/zap" "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" lumberjack "gopkg.in/natefinch/lumberjack.v2" "os" "strings" ) // Logger es una interfaz que define los métodos necesarios para el logging type Logger interface { Debug(msg string, fields ...Field) Info(msg string, fields ...Field) Warn(msg string, fields ...Field) Error(msg string, fields ...Field) Fatal(msg string, fields ...Field) With(fields ...Field) Logger } // Field es un campo para agregar contexto a los logs type Field struct { Key string Value interface{} } // zapLogger implementa la interfaz Logger usando zap type zapLogger struct { logger *zap.Logger } // CustomEncoder implementa la interfaz zapcore.Encoder type CustomEncoder struct { zapcore.Encoder pool buffer.Pool serviceName string } // NewCustomEncoder crea un nuevo encoder personalizado func NewCustomEncoder(cfg zapcore.EncoderConfig, serviceName string) zapcore.Encoder { return &CustomEncoder{ Encoder: zapcore.NewJSONEncoder(cfg), pool: buffer.NewPool(), serviceName: serviceName, } } // EncodeEntry implementa el formato personalizado // EncodeEntry implementa el formato personalizado func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { line := e.pool.Get() // Agregar nivel (INFO:, WARN:, etc.) levelStr := entry.Level.CapitalString() line.AppendString(levelStr) line.AppendString(": ") // Agregar timestamp timestamp := entry.Time.Format("2006/01/02 15:04:05") line.AppendString(timestamp) line.AppendString(" ") // Agregar información del archivo/línea si está disponible if entry.Caller.Defined { // Convertir la ruta a formato Unix para manejar uniformemente las barras filePath := strings.ReplaceAll(entry.Caller.File, "\\", "/") // Opciones para encontrar la parte relevante del path possiblePrefixes := []string{ "/cmd/", "/internal/", "/pkg/", "/api/", "/app/", "/src/", } // Buscar el prefijo más cercano al final del path shortPath := filePath for _, prefix := range possiblePrefixes { if idx := strings.LastIndex(filePath, prefix); idx != -1 { // Encontramos un prefijo estándar de Go shortPath = filePath[idx+1:] // +1 para quitar el slash inicial break } } // Si no se encontró ningún prefijo, usar el último componente del path if shortPath == filePath { parts := strings.Split(filePath, "/") if len(parts) > 0 { shortPath = parts[len(parts)-1] } } caller := fmt.Sprintf("%s:%d: ", shortPath, entry.Caller.Line) line.AppendString(caller) } // Agregar nombre del servicio entre corchetes line.AppendString("[") line.AppendString(e.serviceName) line.AppendString("] ") // Agregar mensaje line.AppendString(entry.Message) // Procesar campos adicionales if len(fields) > 0 { // Usar encoder JSON para serializar los campos encoder := zapcore.NewMapObjectEncoder() // Agregar cada campo al encoder, excepto "service" for _, field := range fields { if field.Key != "service" { field.AddTo(encoder) } } // Solo mostramos los campos si hay alguno después de filtrar if len(encoder.Fields) > 0 { line.AppendString(" ") fieldsJSON, err := json.Marshal(encoder.Fields) if err == nil { line.AppendString(string(fieldsJSON)) } } } line.AppendString("\n") return line, nil } //func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { // line := e.pool.Get() // // // Agregar nivel (INFO:, WARN:, etc.) // levelStr := entry.Level.CapitalString() // line.AppendString(levelStr) // line.AppendString(": ") // // // Agregar timestamp // timestamp := entry.Time.Format("2006/01/02 15:04:05") // line.AppendString(timestamp) // line.AppendString(" ") // // // Agregar información del archivo/línea si está disponible // if entry.Caller.Defined { // // Obtener solo la parte relevante de la ruta (después del último "api-soap-facturacion") // filePath := entry.Caller.File // if idx := strings.LastIndex(filePath, "api-soap-facturacion"); idx != -1 { // // Si encontramos la cadena, tomamos lo que viene después más "api-soap-facturacion" // filePath = filePath[idx:] // } else { // // Si no encontramos la cadena, intentamos tomar solo el nombre del archivo // if idx := strings.LastIndex(filePath, "/"); idx != -1 { // filePath = filePath[idx+1:] // } else if idx := strings.LastIndex(filePath, "\\"); idx != -1 { // filePath = filePath[idx+1:] // } // } // // caller := fmt.Sprintf("%s:%d: ", filePath, entry.Caller.Line) // line.AppendString(caller) // } // // Agregar nombre del servicio entre corchetes // line.AppendString("[") // line.AppendString(e.serviceName) // line.AppendString("] ") // // // Agregar mensaje // line.AppendString(entry.Message) // // // Procesar campos adicionales // if len(fields) > 0 { // // Usar encoder JSON para serializar los campos // encoder := zapcore.NewMapObjectEncoder() // // // Agregar cada campo al encoder, excepto "service" // for _, field := range fields { // if field.Key != "service" { // field.AddTo(encoder) // } // } // // // Solo mostramos los campos si hay alguno después de filtrar // if len(encoder.Fields) > 0 { // line.AppendString(" ") // fieldsJSON, err := json.Marshal(encoder.Fields) // if err == nil { // line.AppendString(string(fieldsJSON)) // } // } // } // // line.AppendString("\n") // return line, nil //} //func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { // line := e.pool.Get() // // // Agregar nivel (INFO:, WARN:, etc.) // levelStr := entry.Level.CapitalString() // line.AppendString(levelStr) // line.AppendString(": ") // // // Agregar timestamp // timestamp := entry.Time.Format("2006/01/02 15:04:05") // line.AppendString(timestamp) // line.AppendString(" ") // // // Agregar información del archivo/línea si está disponible // if entry.Caller.Defined { // caller := fmt.Sprintf("%s:%d: ", entry.Caller.File, entry.Caller.Line) // line.AppendString(caller) // } // // // Agregar nombre del servicio entre corchetes // line.AppendString("[") // line.AppendString(e.serviceName) // line.AppendString("] ") // // // Agregar mensaje // line.AppendString(entry.Message) // // // Procesar campos adicionales // if len(fields) > 0 { // // Usar encoder JSON para serializar los campos // encoder := zapcore.NewMapObjectEncoder() // // // Agregar cada campo al encoder, excepto "service" // for _, field := range fields { // if field.Key != "service" { // field.AddTo(encoder) // } // } // // // Solo mostramos los campos si hay alguno después de filtrar // if len(encoder.Fields) > 0 { // line.AppendString(" ") // fieldsJSON, err := json.Marshal(encoder.Fields) // if err == nil { // line.AppendString(string(fieldsJSON)) // } // } // } // // line.AppendString("\n") // return line, nil //} // Clone implementa la interfaz Encoder func (e *CustomEncoder) Clone() zapcore.Encoder { return &CustomEncoder{ Encoder: e.Encoder.Clone(), pool: e.pool, serviceName: e.serviceName, } } // NewLogger crea una nueva instancia de Logger func NewLogger(cfg *config.Config) Logger { // Configurar nivel de log var level zapcore.Level switch cfg.App.LogLevel { case "debug": level = zapcore.DebugLevel case "info": level = zapcore.InfoLevel case "warn": level = zapcore.WarnLevel case "error": level = zapcore.ErrorLevel default: level = zapcore.InfoLevel } // Configuración básica para el encoder encoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", NameKey: "logger", CallerKey: "caller", FunctionKey: zapcore.OmitKey, MessageKey: "msg", StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.CapitalLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } // Crear el encoder personalizado customEncoder := NewCustomEncoder(encoderConfig, cfg.App.Name) // Configurar el output var core zapcore.Core if cfg.App.LogFilePath != "" { // Si se usa archivo con lumberjack logWriter := &lumberjack.Logger{ Filename: cfg.App.LogFilePath, MaxSize: cfg.App.LogMaxSize, MaxBackups: cfg.App.LogMaxBackups, MaxAge: cfg.App.LogMaxAge, Compress: cfg.App.LogCompress, } core = zapcore.NewCore( customEncoder, zapcore.AddSync(logWriter), level, ) } else { // Solo usar stdout core = zapcore.NewCore( customEncoder, zapcore.AddSync(os.Stdout), level, ) } // Habilitar el caller para mostrar información del archivo y línea zapLog := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) // Ya no agregamos el nombre del servicio como campo, ya que lo incluimos en el formato // zapLog = zapLog.With(zap.String("service", cfg.App.Name)) return &zapLogger{logger: zapLog} } // NewField crea un campo para agregar a los logs func NewField(key string, value interface{}) Field { return Field{Key: key, Value: value} } // convertFields convierte nuestros campos a campos de zap func (l *zapLogger) convertFields(fields []Field) []zap.Field { zapFields := make([]zap.Field, len(fields)) for i, field := range fields { zapFields[i] = zap.Any(field.Key, field.Value) } return zapFields } // Debug registra un mensaje con nivel Debug func (l *zapLogger) Debug(msg string, fields ...Field) { l.logger.Debug(msg, l.convertFields(fields)...) } // Info registra un mensaje con nivel Info func (l *zapLogger) Info(msg string, fields ...Field) { l.logger.Info(msg, l.convertFields(fields)...) } // Warn registra un mensaje con nivel Warn func (l *zapLogger) Warn(msg string, fields ...Field) { l.logger.Warn(msg, l.convertFields(fields)...) } // Error registra un mensaje con nivel Error func (l *zapLogger) Error(msg string, fields ...Field) { l.logger.Error(msg, l.convertFields(fields)...) } // Fatal registra un mensaje con nivel Fatal func (l *zapLogger) Fatal(msg string, fields ...Field) { l.logger.Fatal(msg, l.convertFields(fields)...) } // With retorna un nuevo logger con campos adicionales func (l *zapLogger) With(fields ...Field) Logger { return &zapLogger{ logger: l.logger.With(l.convertFields(fields)...), } } //package logger // //import ( // "api-soap-facturacion/internal/config" // "encoding/json" // "fmt" // "go.uber.org/zap" // "go.uber.org/zap/zapcore" // lumberjack "gopkg.in/natefinch/lumberjack.v2" // Usa este alias // "os" //) // //// Logger es una interfaz que define los métodos necesarios para el logging //type Logger interface { // Debug(msg string, fields ...Field) // Info(msg string, fields ...Field) // Warn(msg string, fields ...Field) // Error(msg string, fields ...Field) // Fatal(msg string, fields ...Field) // With(fields ...Field) Logger //} // //// Field es un campo para agregar contexto a los logs //type Field struct { // Key string // Value interface{} //} // //// zapLogger implementa la interfaz Logger usando zap //type zapLogger struct { // logger *zap.Logger //} // //// CustomEncoder implementa la interfaz zapcore.Encoder //type CustomEncoder struct { // zapcore.Encoder // pool buffer.Pool // serviceName string //} // //// NewCustomEncoder crea un nuevo encoder personalizado //func NewCustomEncoder(cfg zapcore.EncoderConfig, serviceName string) zapcore.Encoder { // return &CustomEncoder{ // Encoder: zapcore.NewJSONEncoder(cfg), // pool: buffer.NewPool(), // serviceName: serviceName, // } //} // //// EncodeEntry implementa el formato personalizado //func (e *CustomEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { // line := e.pool.Get() // // // Agregar nivel (INFO:, WARN:, etc.) // levelStr := entry.Level.CapitalString() // line.AppendString(levelStr) // line.AppendString(": ") // // // Agregar timestamp // timestamp := entry.Time.Format("2006/01/02 15:04:05") // line.AppendString(timestamp) // line.AppendString(" ") // // // Agregar información del archivo/línea si está disponible // if entry.Caller.Defined { // caller := fmt.Sprintf("%s:%d: ", entry.Caller.File, entry.Caller.Line) // line.AppendString(caller) // } // // // Agregar nombre del servicio entre corchetes // line.AppendString("[") // line.AppendString(e.serviceName) // line.AppendString("] ") // // // Agregar mensaje // line.AppendString(entry.Message) // // // Procesar campos adicionales // if len(fields) > 0 { // line.AppendString(" ") // fieldsMap := make(map[string]interface{}) // for _, field := range fields { // if field.Key != "service" { // field.AddTo(fieldsMap) // } // } // // if len(fieldsMap) > 0 { // fieldJSON, err := json.Marshal(fieldsMap) // if err == nil { // line.AppendString(string(fieldJSON)) // } // } // } // // line.AppendString("\n") // return line, nil //} // //// Clone implementa la interfaz Encoder //func (e *CustomEncoder) Clone() zapcore.Encoder { // return &CustomEncoder{ // Encoder: e.Encoder.Clone(), // pool: e.pool, // serviceName: e.serviceName, // } //} // //// NewLogger crea una nueva instancia de Logger tipo json ////func NewLogger(cfg *config.Config) Logger { //// // Configurar nivel de log //// var level zapcore.Level //// switch cfg.App.LogLevel { //// case "debug": //// level = zapcore.DebugLevel //// case "info": //// level = zapcore.InfoLevel //// case "warn": //// level = zapcore.WarnLevel //// case "error": //// level = zapcore.ErrorLevel //// default: //// level = zapcore.InfoLevel //// } //// //// // Configurar encoderConfig //// encoderConfig := zapcore.EncoderConfig{ //// TimeKey: "time", //// LevelKey: "level", //// NameKey: "logger", //// CallerKey: "caller", //// MessageKey: "msg", //// StacktraceKey: "stacktrace", //// LineEnding: zapcore.DefaultLineEnding, //// EncodeLevel: zapcore.LowercaseLevelEncoder, //// EncodeTime: zapcore.ISO8601TimeEncoder, //// EncodeDuration: zapcore.SecondsDurationEncoder, //// EncodeCaller: zapcore.ShortCallerEncoder, //// } //// //// // Crear escritores //// var cores []zapcore.Core //// //// // Siempre escribir a stdout //// cores = append(cores, zapcore.NewCore( //// zapcore.NewJSONEncoder(encoderConfig), //// zapcore.AddSync(os.Stdout), //// level, //// )) //// //// // Si se especificó una ruta de archivo de logs, configurar rotación //// if cfg.App.LogFilePath != "" { //// logWriter := &lumberjack.Logger{ //// Filename: cfg.App.LogFilePath, //// MaxSize: cfg.App.LogMaxSize, //// MaxBackups: cfg.App.LogMaxBackups, //// MaxAge: cfg.App.LogMaxAge, //// Compress: cfg.App.LogCompress, //// } //// //// cores = append(cores, zapcore.NewCore( //// zapcore.NewJSONEncoder(encoderConfig), //// zapcore.AddSync(logWriter), //// level, //// )) //// } //// //// // Combinar cores //// core := zapcore.NewTee(cores...) //// //// // Crear logger //// zapLog := zap.New(core) //// zapLog = zapLog.With(zap.String("service", cfg.App.Name)) //// //// return &zapLogger{logger: zapLog} ////} // //// fomato de texto mas flexible //// NewLogger crea una nueva instancia de Logger ////func NewLogger(cfg *config.Config) Logger { //// // Configurar nivel de log //// var level zapcore.Level //// switch cfg.App.LogLevel { //// case "debug": //// level = zapcore.DebugLevel //// case "info": //// level = zapcore.InfoLevel //// case "warn": //// level = zapcore.WarnLevel //// case "error": //// level = zapcore.ErrorLevel //// default: //// level = zapcore.InfoLevel //// } //// //// // Configurar encoderConfig para un formato más legible //// encoderConfig := zapcore.EncoderConfig{ //// TimeKey: "time", //// LevelKey: "level", //// NameKey: "logger", //// CallerKey: "caller", //// FunctionKey: zapcore.OmitKey, //// MessageKey: "msg", //// StacktraceKey: "stacktrace", //// LineEnding: zapcore.DefaultLineEnding, //// EncodeLevel: zapcore.CapitalLevelEncoder, // INFO en lugar de info //// EncodeTime: zapcore.TimeEncoderOfLayout("2006/01/02 15:04:05"), // Formato como 2025/05/15 00:13:07 //// EncodeDuration: zapcore.SecondsDurationEncoder, //// EncodeCaller: zapcore.ShortCallerEncoder, //// } //// //// // Crear un formato personalizado //// consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig) //// //// // Configurar el output final //// var core zapcore.Core //// if cfg.App.LogFilePath != "" && cfg.App.UseFileLogger { //// // Si se usa archivo con lumberjack //// logWriter := &lumberjack.Logger{ //// Filename: cfg.App.LogFilePath, //// MaxSize: cfg.App.LogMaxSize, //// MaxBackups: cfg.App.LogMaxBackups, //// MaxAge: cfg.App.LogMaxAge, //// Compress: cfg.App.LogCompress, //// } //// //// core = zapcore.NewCore( //// consoleEncoder, //// zapcore.AddSync(logWriter), //// level, //// ) //// } else { //// // Solo usar stdout //// core = zapcore.NewCore( //// consoleEncoder, //// zapcore.AddSync(os.Stdout), //// level, //// ) //// } //// //// // Habilitar el caller para mostrar información del archivo y línea //// zapLog := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) //// //// // Agregar nombre del servicio como prefijo constante //// zapLog = zapLog.With(zap.String("service", cfg.App.Name)) //// //// return &zapLogger{logger: zapLog} ////} // //// NewLogger crea una nueva instancia de Logger //func NewLogger(cfg *config.Config) Logger { // // Configurar nivel de log // var level zapcore.Level // switch cfg.App.LogLevel { // case "debug": // level = zapcore.DebugLevel // case "info": // level = zapcore.InfoLevel // case "warn": // level = zapcore.WarnLevel // case "error": // level = zapcore.ErrorLevel // default: // level = zapcore.InfoLevel // } // // // Configuración básica para el encoder // encoderConfig := zapcore.EncoderConfig{ // TimeKey: "time", // LevelKey: "level", // NameKey: "logger", // CallerKey: "caller", // FunctionKey: zapcore.OmitKey, // MessageKey: "msg", // StacktraceKey: "stacktrace", // LineEnding: zapcore.DefaultLineEnding, // EncodeLevel: zapcore.CapitalLevelEncoder, // EncodeTime: zapcore.ISO8601TimeEncoder, // EncodeDuration: zapcore.SecondsDurationEncoder, // EncodeCaller: zapcore.ShortCallerEncoder, // } // // // Crear el encoder personalizado // customEncoder := NewCustomEncoder(encoderConfig, cfg.App.Name) // // // Configurar el output // var core zapcore.Core // if cfg.App.LogFilePath != "" { // // Si se usa archivo con lumberjack // logWriter := &lumberjack.Logger{ // Filename: cfg.App.LogFilePath, // MaxSize: cfg.App.LogMaxSize, // MaxBackups: cfg.App.LogMaxBackups, // MaxAge: cfg.App.LogMaxAge, // Compress: cfg.App.LogCompress, // } // // core = zapcore.NewCore( // customEncoder, // zapcore.AddSync(logWriter), // level, // ) // } else { // // Solo usar stdout // core = zapcore.NewCore( // customEncoder, // zapcore.AddSync(os.Stdout), // level, // ) // } // // // Habilitar el caller para mostrar información del archivo y línea // zapLog := zap.New(core, zap.AddCaller()) // // // Ya no agregamos el nombre del servicio como campo, ya que lo incluimos en el formato // // zapLog = zapLog.With(zap.String("service", cfg.App.Name)) // // return &zapLogger{logger: zapLog} //} // //// NewField crea un campo para agregar a los logs //func NewField(key string, value interface{}) Field { // return Field{Key: key, Value: value} //} // //// convertFields convierte nuestros campos a campos de zap //func (l *zapLogger) convertFields(fields []Field) []zap.Field { // zapFields := make([]zap.Field, len(fields)) // for i, field := range fields { // zapFields[i] = zap.Any(field.Key, field.Value) // } // return zapFields //} // //// Debug registra un mensaje con nivel Debug //func (l *zapLogger) Debug(msg string, fields ...Field) { // l.logger.Debug(msg, l.convertFields(fields)...) //} // //// Info registra un mensaje con nivel Info //func (l *zapLogger) Info(msg string, fields ...Field) { // l.logger.Info(msg, l.convertFields(fields)...) //} // //// Warn registra un mensaje con nivel Warn //func (l *zapLogger) Warn(msg string, fields ...Field) { // l.logger.Warn(msg, l.convertFields(fields)...) //} // //// Error registra un mensaje con nivel Error //func (l *zapLogger) Error(msg string, fields ...Field) { // l.logger.Error(msg, l.convertFields(fields)...) //} // //// Fatal registra un mensaje con nivel Fatal //func (l *zapLogger) Fatal(msg string, fields ...Field) { // l.logger.Fatal(msg, l.convertFields(fields)...) //} // //// With retorna un nuevo logger con campos adicionales //// //// func (l *zapLogger) With(fields ...Field) Logger { //// return &zapLogger{ //// logger: l.logger.With(l.convertFields(fields)...), //// } //// } //func (l *zapLogger) With(fields ...Field) Logger { // return &zapLogger{ // logger: l.logger.With(l.convertFields(fields)...), // } //} // ////package logger //// ////import ( //// "api-soap-facturacion/internal/config" //// "go.uber.org/zap" //// "go.uber.org/zap/zapcore" ////) //// ////// Logger es una interfaz que define los métodos necesarios para el logging ////type Logger interface { //// Debug(msg string, fields ...Field) //// Info(msg string, fields ...Field) //// Warn(msg string, fields ...Field) //// Error(msg string, fields ...Field) //// Fatal(msg string, fields ...Field) //// With(fields ...Field) Logger ////} //// ////// Field es un campo para agregar contexto a los logs ////type Field struct { //// Key string //// Value interface{} ////} //// ////// zapLogger implementa la interfaz Logger usando zap ////type zapLogger struct { //// logger *zap.Logger ////} //// ////// NewLogger crea una nueva instancia de Logger ////func NewLogger(cfg *config.Config) Logger { //// // Configurar nivel de log //// var level zapcore.Level //// switch cfg.App.LogLevel { //// case "debug": //// level = zapcore.DebugLevel //// case "info": //// level = zapcore.InfoLevel //// case "warn": //// level = zapcore.WarnLevel //// case "error": //// level = zapcore.ErrorLevel //// default: //// level = zapcore.InfoLevel //// } //// //// // Configuración de zap //// zapConfig := zap.Config{ //// Level: zap.NewAtomicLevelAt(level), //// Development: cfg.App.Environment == "development", //// Encoding: "json", //// OutputPaths: []string{"stdout"}, //// ErrorOutputPaths: []string{"stderr"}, //// EncoderConfig: zapcore.EncoderConfig{ //// TimeKey: "time", //// LevelKey: "level", //// NameKey: "logger", //// CallerKey: "caller", //// MessageKey: "msg", //// StacktraceKey: "stacktrace", //// LineEnding: zapcore.DefaultLineEnding, //// EncodeLevel: zapcore.LowercaseLevelEncoder, //// EncodeTime: zapcore.ISO8601TimeEncoder, //// EncodeDuration: zapcore.SecondsDurationEncoder, //// EncodeCaller: zapcore.ShortCallerEncoder, //// }, //// } //// //// // Agregar service name a todos los logs //// logger, _ := zapConfig.Build() //// logger = logger.With(zap.String("service", cfg.App.Name)) //// //// return &zapLogger{logger: logger} ////} //// ////// NewField crea un campo para agregar a los logs ////func NewField(key string, value interface{}) Field { //// return Field{Key: key, Value: value} ////} //// ////// convertFields convierte nuestros campos a campos de zap ////func (l *zapLogger) convertFields(fields []Field) []zap.Field { //// zapFields := make([]zap.Field, len(fields)) //// for i, field := range fields { //// zapFields[i] = zap.Any(field.Key, field.Value) //// } //// return zapFields ////} //// ////// Debug registra un mensaje con nivel Debug ////func (l *zapLogger) Debug(msg string, fields ...Field) { //// l.logger.Debug(msg, l.convertFields(fields)...) ////} //// ////// Info registra un mensaje con nivel Info ////func (l *zapLogger) Info(msg string, fields ...Field) { //// l.logger.Info(msg, l.convertFields(fields)...) ////} //// ////// Warn registra un mensaje con nivel Warn ////func (l *zapLogger) Warn(msg string, fields ...Field) { //// l.logger.Warn(msg, l.convertFields(fields)...) ////} //// ////// Error registra un mensaje con nivel Error ////func (l *zapLogger) Error(msg string, fields ...Field) { //// l.logger.Error(msg, l.convertFields(fields)...) ////} //// ////// Fatal registra un mensaje con nivel Fatal ////func (l *zapLogger) Fatal(msg string, fields ...Field) { //// l.logger.Fatal(msg, l.convertFields(fields)...) ////} //// ////// With retorna un nuevo logger con campos adicionales ////func (l *zapLogger) With(fields ...Field) Logger { //// return &zapLogger{ //// logger: l.logger.With(l.convertFields(fields)...), //// } ////}