2013-08-21 2 views
65

Каков шаблон для регистрации приложений в Go? Если у меня есть, скажем, 5 goroutines мне нужно войти в, я должен ...Правильный подход к глобальным регистрациям в Голанге

  • Создание единого log.Logger и передать его вокруг?
  • Пройдите указатель к этому указателю log.Logger?
  • Должен ли каждый горутин или функция создавать регистратор?
  • Должен ли я создать регистратор как глобальную переменную?

ответ

31
  • Создайте единый log.Logger и передайте его вокруг?

Это возможно. A log.Logger может использоваться одновременно с несколькими гортанами.

  • Pass вокруг указателя на этот log.Logger?

log.New возвращает *Logger, который, как правило, признак того, что вы должны передать объект вокруг как указатель. Передавая его как значение, создается копия структуры (т. Е. Копия Logger), а затем несколько goroutines могут одновременно записывать на тот же io.Writer. Это может быть серьезной проблемой, в зависимости от реализации писателя.

  • Если каждый goroutine или функция создания регистратора?

Я не создавал отдельный регистратор для каждой функции или goroutine. Горутины (и функции) используются для очень легких задач, которые не будут оправдывать обслуживание отдельного регистратора. Вероятно, это хорошая идея создать регистратор для каждого более крупного компонента вашего проекта. Например, если в вашем проекте используется служба SMTP для отправки писем, создание отдельного регистратора для почтовой службы звучит как хорошая идея, так что вы можете фильтровать и отключать вывод отдельно.

  • Должен ли я создать регистратор как глобальную переменную?

Это зависит от вашей упаковки. В предыдущем примере почтовой службы было бы неплохо иметь один регистратор для каждого экземпляра вашей службы, чтобы пользователи могли регистрировать сбои при использовании почтовой службы gmail иначе, чем сбои, возникающие при использовании локальной MTA (например, sendmail).

+0

Ваш ответ был в значительной степени ясен, спасибо – deFreitas

31

Для простых случаев существует глобальный регистратор, определенный в лог-пакете, log.Logger. Этот глобальный регистратор можно настроить через log.SetFlags.

После этого можно просто вызвать функции верхнего уровня пакета журнала, такие как log.Printf и log.Fatalf, которые используют этот глобальный экземпляр.

+0

мысли вы можете установить флаги, которые вы не можете использовать пользовательский регистратор. – 0xcaff

+0

@caffinatedmonkey. Фактически вы можете использовать пользовательские журналы, если они реализуют интерфейс 'io.Writer', и вы изменяете вывод регистратора по умолчанию с помощью' SetOutput() '. – congusbongus

5

Я знаю, что этот вопрос немного устарел, но если, как и я, ваши проекты состоят из нескольких файлов меньшего размера, которые я голосую за ваш 4-й вариант. Я создал logger.go, который является частью основного пакета. Этот файл go создает журнал, назначает его файлу и предоставляет его остальной части основного. Обратите внимание, я не придумал изящный способом закрыть 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) 
} 
+5

Для изящного закрытия вы могли бы, вероятно, «отложить errorlog.Close()» в конце выполнения или лучше обеспечить его закрытые, настроенные обработчики сигналов с помощью пакета сигналов Go https: // golang.org/pkg/os/signal/ – AJPennster

2

Я нашел пакет журнала по умолчанию (https://golang.org/pkg/log/) несколько ограничивающих. Например, нет поддержки журналов с отсканированными данными.
После того, как выкарабкались, заселили, используя https://github.com/golang/glog. Кажется, это порт https://github.com/google/glog и дает приличную гибкость при регистрации. Например, при запуске приложения локально вам может понадобиться журнал уровня DEBUG, но может потребоваться запустить только на уровне INFO/ERROR в процессе производства. Список полных функций/руководства здесь, здесь https://google-glog.googlecode.com/svn/trunk/doc/glog.html (Его для модуля C++, но по большей части переводится в порт golang)

3

Это старый вопрос, но я хотел бы предложить использовать http://github.com/romana/rlog (которые мы разработали). Он настраивается через переменные среды, объект журнала создается и инициализируется при импорте rlog. Поэтому нет необходимости проходить вокруг регистратора.

rlog имеет довольно много функций:

  • Полностью настраиваемые штампы даты/времени
  • одновременный вывод на стандартный вывод или поток ошибок, а также файл.
  • Стандартные уровни регистрации (Debug, Info и т. Д.), А также свободно настраиваемые многоуровневые протоколирования.
  • Ведение журнала звонков по запросу (файл, номер строки, функция).
  • Возможность установки разных уровней журналов для разных исходных файлов.

Он очень маленький, не имеет внешних зависимостей, кроме стандартной библиотеки Голанга и активно развивается. Примеры приведены в репо.

+2

Благодарим вас за то, что вы раскрыли свою принадлежность к продукту, который вы рекомендуете! Это ценно. –

3

Это простой Лог инфокодов

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") 
}