practices log golang example best logging go

logging - example - golang log to file



Enfoque correcto para el registro global en Golang (6)

¿Cuál es el patrón para el registro de aplicaciones en Go? Si tengo, digamos, 5 goroutines de los que necesito iniciar sesión, ¿debería ...?

  • Crear un solo log.Logger y pasarlo?
  • Pase alrededor de un puntero a ese log.Logger ¿ log.Logger ?
  • ¿Debería cada función de rutina crear un registrador?
  • ¿Debo crear el registrador como una variable global?

  • Crear un solo registro.¿Logger y pasarlo?

Eso es posible. Un log.Logger se puede usar al mismo tiempo desde múltiples goroutines.

  • Pase alrededor de un puntero a ese registro. ¿Logger?

log.New devuelve un *Logger que generalmente es una indicación de que debe pasar el objeto como un puntero. Pasarlo como valor crearía una copia de la estructura (es decir, una copia del registrador) y luego múltiples gorutines podrían escribir en el mismo io.Writer al mismo tiempo. Eso podría ser un problema grave, dependiendo de la implementación del escritor.

  • ¿Debería cada función de rutina crear un registrador?

No crearía un registrador por separado para cada función o goroutine. Las rutinas (y funciones) se usan para tareas muy livianas que no justificarán el mantenimiento de un registrador separado. Probablemente sea una buena idea crear un registrador para cada componente más grande de su proyecto. Por ejemplo, si su proyecto utiliza un servicio SMTP para enviar correos electrónicos, la creación de un registrador separado para el servicio de correo suena como una buena idea para que pueda filtrar y apagar la salida por separado.

  • ¿Debo crear el registrador como una variable global?

Eso depende de tu paquete. En el ejemplo del servicio de correo anterior, probablemente sería una buena idea tener un registrador para cada instancia de su servicio, de modo que los usuarios puedan registrar fallas mientras usan el servicio de correo de Gmail de forma diferente a las fallas que ocurrieron al usar el MTA local (por ejemplo, sendmail). )


Encontré el paquete de registro predeterminado ( https://golang.org/pkg/log/ ) un tanto limitado. Por ejemplo, no hay soporte para la información frente a los registros de depuración.
Después de hurgar un poco, se decidió por usar https://github.com/golang/glog . Este parece ser un puerto de https://github.com/google/glog y ofrece una flexibilidad decente para el inicio de sesión. Por ejemplo, al ejecutar una aplicación localmente, es posible que desee un registro de nivel de DEPURACIÓN, pero puede que desee ejecutarlo solo en el nivel INFO / ERROR en producción. La lista de características / guía completas es, aquí https://google-glog.googlecode.com/svn/trunk/doc/glog.html (Es para el módulo c ++, pero en su mayor parte se traduce al puerto golang)


Esta es una pregunta anterior, pero me gustaría sugerir el uso de http://github.com/romana/rlog (que desarrollamos). Se configura mediante variables de entorno, el objeto logger se crea y se inicializa cuando se importa rlog. Por lo tanto, no es necesario pasar un registrador.

rlog tiene bastantes características:

  • Sellos de fecha / hora totalmente configurables
  • Salida simultánea a stderr o stdout, así como archivo.
  • Niveles de registro estándar (depuración, información, etc.), así como el registro de niveles múltiples libremente configurable.
  • Registro a pedido de la información de la persona que llama (archivo, número de línea, función).
  • Posibilidad de establecer diferentes niveles de registro para diferentes archivos fuente.

Es muy pequeño, no tiene dependencias externas, excepto la biblioteca estándar de Golang y se está desarrollando activamente. Se proporcionan ejemplos en el repositorio.


Este es un registrador simple

package customlogger import ( "log" "os" "sync" ) type logger struct { filename string *log.Logger } var logger *logger var once sync.Once // start loggeando func GetInstance() *logger { once.Do(func() { logger = createLogger("mylogger.log") }) return logger } func createLogger(fname string) *logger { file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) return &logger{ filename: fname, Logger: log.New(file, "My app Name ", log.Lshortfile), } }

Puedes usarlo de esta manera

package main import ( "customlogger" "fmt" "net/http" ) func main() { logger := customlogger.GetInstance() logger.Println("Starting") http.HandleFunc("/", sroot) http.ListenAndServe(":8080", nil) } func sroot(w http.ResponseWriter, r *http.Request) { logger := customlogger.GetInstance() fmt.Fprintf(w, "welcome") logger.Println("Starting") }


Para casos simples, hay un registrador global definido en el paquete de registro, log.Logger . Este registrador global se puede configurar a través de log.SetFlags .

Después uno puede simplemente llamar a las funciones de nivel superior del paquete de registro como log.Printf y log.Fatalf , que usan esa instancia global.


Sé que esta pregunta es un poco antigua, pero si, como yo, sus proyectos están compuestos de varios archivos más pequeños, yo voto por su cuarta opción: he creado un logger.go que forma parte del paquete principal. Este archivo go crea el registrador, lo asigna a un archivo y lo proporciona al resto de main. Tenga en cuenta que no he encontrado una manera elegante de cerrar el registro de errores ...

package main import ( "fmt" "log" "os" ) var errorlog *os.File var logger *log.Logger func init() { errorlog, err := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { fmt.Printf("error opening file: %v", err) os.Exit(1) } logger = log.New(errorlog, "applog: ", log.Lshortfile|log.LstdFlags) }