Подтвердить что ты не робот

Правильный подход к глобальным лесозаготовкам в Голанге

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

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

Ответ 1

  • Создайте один log.Logger и передайте его?

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

  • Пропустить указатель на этот log.Logger?

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

  • Должны ли каждый горутин или функция создавать журнал?

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

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

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

Ответ 2

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

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

Ответ 3

Я знаю, что этот вопрос немного устарел, но если, как и я, ваши проекты состоят из нескольких файлов меньшего размера, которые я голосую за ваш 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)
}

Ответ 4

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

rlog имеет немало возможностей:

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

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

Ответ 5

Я нашел пакет журнала по умолчанию (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 (для модуля С++, но по большей части переводится в порт golang)

Ответ 6

Это простой регистратор

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