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



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




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

  • передайте указатель на это log.Logger?

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

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

542   6  

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

    Ничего не найдено.