Правильный подход к глобальной регистрации в Golang
каков шаблон для входа в приложение Go? Если у меня есть, скажем, 5 goroutines, из которых мне нужно войти, должен ли я...
- создать один
log.Loggerи передать его? - передайте указатель на это
log.Logger? - должен ли каждый goroutine или функция создать регистратор?
- должен ли я создать логгер как глобальную переменную?
6 ответов:
- создать один журнал.Лесоруб и передать его вокруг?
это возможно. А log.Лесоруб может использоваться одновременно из нескольких goroutines.
- передайте указатель на этот журнал.Лесоруб?
log.Новый возвращает a
*Loggerчто обычно указывает на то, что вы должны передать объект в качестве указателя. Передача его в качестве значения создаст копию структуры (т. е. копия регистратора), а затем несколько goroutines могут писать в один и тот же io.Писатель по совместительству. Это может быть серьезной проблемой, в зависимости от реализации писателя.
- должен ли каждый goroutine или функция создать регистратор?
Я бы не создавал отдельный регистратор для каждой функции или goroutine. Goroutines (и функции) используются для очень легких задач, которые не оправдывают содержание отдельного регистратора. Это, вероятно, хорошая идея, чтобы создать регистратор для каждого большего компонента вашего проекта. Например, если ваш проект использует службу SMTP для отправки почты, создание отдельного регистратора для почтовой службы звучит как хорошая идея, так что вы можете фильтровать и отключать вывод отдельно.
- должен ли я создать логгер как глобальную переменную?
это зависит от твоего пакета. В предыдущей почте пример службы, вероятно, было бы неплохо иметь один регистратор для каждого экземпляра вашей службы, чтобы пользователи могли регистрировать сбои при использовании почтовой службы gmail иначе, чем сбои, возникшие при использовании локального MTA (например, sendmail).
для простых случаев существует глобальный регистратор, определенный в пакете журнала,
log.Logger. Этот глобальный регистратор можно настроить черезlog.SetFlags.после этого можно просто вызвать функции верхнего уровня пакета журнала, такие как
log.Printfиlog.Fatalf, которые используют этот глобальный экземпляр.
Я знаю, что этот вопрос немного стар, но если, как и я, ваши проекты состоят из нескольких небольших файлов, я голосую за Ваш 4-й вариант - я создал
logger.go, которая является частью основного пакета. Этот файл go создает регистратор, назначает его файлу и предоставляет его остальной части main. Обратите внимание, что я не придумал изящный способ закрыть errorlog...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) }
это простой регистратор
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), } }Вы можете использовать его таким образом
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") }
Это более старый вопрос, но я хотел бы предложить использовать http://github.com/romana/rlog (который мы разработали). Он настраивается через переменные среды, объект logger создается и инициализируется при импорте rlog. Поэтому нет необходимости обходить лесоруб.
rlog имеет довольно много функций:
- полностью настраиваемые метки даты/времени
- одновременный выход к stderr или stdout так же, как файл.
- стандартные уровни журнала (отладка, информация и т. д.) а также свободно настраиваемый многоуровневый журнал.
- по требованию Регистрация информации о вызывающем абоненте (файл, номер строки, функция).
- возможность установки различных уровней журнала для различных исходных файлов.
Он очень мал, не имеет внешних зависимостей, кроме стандартной библиотеки Golang и активно развивается. Примеры приведены в репо.
Я нашел пакет журнала по умолчанию (https://golang.org/pkg/log/) несколько ограничивает. Например, отсутствует поддержка журналов info и debug.
После некоторого ковыряния, остановились на использовании https://github.com/golang/glog . Это, кажется, порт https://github.com/google/glog и дает достойную гибкость в регистрации. Например, при локальном запуске приложения вам может потребоваться журнал уровня отладки, но может потребоваться запустить только в INFO / ERROR level in производство. Список полных функций / руководство, ЗДЕСЬ https://google-glog.googlecode.com/svn/trunk/doc/glog.html (это для модуля c++, но по большей части переводится на порт golang)
Comments