Задать вопрос
Djam36
@Djam36

Как правильно объявить Logger в golang?

Привет, вопрос следующего характера, есть софтина, в ней нужно логировать различные сценарии её поведения, для этого я выбрал logrus
формат логирования написал в отдельном файле, назвал его Logger.go выглядит он следующим образом

package controllers

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/sirupsen/logrus"
)

type myFormatter struct {
	logrus.TextFormatter
}

func (f *myFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	// this whole mess of dealing with ansi color codes is required if you want the colored output otherwise you will lose colors in the logrus levels
	var levelColor int
	switch entry.Level {
	case logrus.DebugLevel, logrus.TraceLevel:
		levelColor = 31 // gray
	case logrus.WarnLevel:
		levelColor = 33 // yellow
	case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
		levelColor = 31 // red
	default:
		levelColor = 36 // blue
	}
	return []byte(fmt.Sprintf("[%s] - \x1b[%dm%s\x1b[0m - %s\n", entry.Time.Format(f.TimestampFormat), levelColor, strings.ToUpper(entry.Level.String()), entry.Message)), nil
}
func Logger() *logrus.Logger {
	f, _ := os.OpenFile("logrus.txt", os.O_CREATE|os.O_WRONLY, 0777)
	logger := &logrus.Logger{
		Out:   io.MultiWriter(os.Stderr, f),
		Level: logrus.InfoLevel,
		Formatter: &myFormatter{logrus.TextFormatter{
			FullTimestamp:          true,
			TimestampFormat:        "2006-01-02 15:04:05",
			ForceColors:            true,
			DisableLevelTruncation: true,
		},
		},
	}
	return logger
}


в файле Main.go следовательно его объявил таким образом
Logger := controllers.Logger()

Теперь вызвав в Main файле
Logger.Println("TEST")

Я получаю, формат кривой т.к вывод нормально работает для Linux, делаю я все это на Windows, т.е в каком-то виде все это работает
[2019-07-30 17:28:47] - ←[36mINFO←[0m - TEST

Теперь я хочу этот логер передать в другую функцию которая находится вообще в другом пакете, но у меня ничего не получается, как можно это сделать? или каким путем вообще идти? как сделать централизованный логер, где я смогу менять все 1 месте, а не лазить по всем файлам и что-то менять в зависимости от уровня логирования в конфиге
  • Вопрос задан
  • 3586 просмотров
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 1
@ghostiam
На Go писатель, серверов пинатель.
Вот 2 способа, но я предпочитаю передачу логера через структуру с конструктором.
Только за место реального логера(*logrus.Logger), структура и функция принимает интерфейс логера(logrus.FieldLogger), в таком случае, его можно будет несложно заменить(или отключить) для тестов.
func main {
	log := logrus.New()

	// Передача логера через параметр в функции
	pkg1MyFunc(log, "data1", "data2")

	// Структура с конструктором
	s := NewMyStruct(log, "data")
	s.Do("params")
}

// Передача логера через параметр в функции
func pkg1MyFunc(log logrus.FieldLogger, data1, data2 string) {
	log.Info(data1, data2)
}

// Структура с конструктором
type MyStruct struct {
	log  logrus.FieldLogger
	data string
}

func NewMyStruct(log logrus.FieldLogger, data string) *MyStruct {
	return &MyStruct{log: log, data: data}
}

func (s *MyStruct) Do(params string) {
	s.log.Info(s.data, params)
}


Самое главное, не используйте глобальную переменную с логером, потом будет не возможно его заменить или протестировать код без него. Да и вообще, глобальные переменные зло.

По мимо логера, таким же образом можно передавать интерфейсы к БД:
type MyStruct struct {
	log   logrus.FieldLogger
	store storage.Store
	data  string
}

func NewMyStruct(log logrus.FieldLogger, store storage.Store, data string) *MyStruct {
	return &MyStruct{log: log, data: data, store: store}
}

func (s *MyStruct) Do(params string) {
  s.log.Info(s.data, params)
  s.store.AddParams(params)
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы