Пакет log
не отвечает за очистку базового io.Writer
.Для пакета log
было бы возможно выполнить утверждение типа, чтобы увидеть, имеет ли текущий io.Writer
метод Flush()
, и если это так, то вызвать его, но нет никакой гарантии, что если несколько io.Writer
s«сцеплены», данные в конечном итоге будут сброшены на самый нижний уровень.
И основная причина, по которой пакет log
, по моему мнению, не сбрасывается, - производительность .Мы используем буферизованные средства записи, поэтому нам не нужно достигать нижележащего слоя каждый раз, когда в него записывается один байт (или фрагмент байта), но мы можем кэшировать недавно записанные данные и когда мы достигаем определенного размера (или определенноговремя), мы можем эффективно написать "пакет" сразу.
Если пакет log
будет сбрасываться после каждого оператора журнала, это сделает буферизованный ввод-вывод бесполезным.Это может не иметь значения в случае небольших приложений, но если у вас веб-сервер с высоким трафиком, выдача сброса после каждого оператора журнала (которых может быть много в каждой обработке запроса) может привести к серьезному снижению производительности.
Тогда да, есть проблема, если приложение закрывается, последние операторы журнала могут не попасть в нижележащий слой.Правильное решение - сделать изящное завершение работы : реализовать обработку сигналов, а когда ваше приложение собирается завершить работу, должным образом очистить и закрыть базовый io.Writer
используемого вами регистратора.Подробнее см.
Можно ли захватить сигнал Ctrl + C и запустить функцию очистки "отложенным" способом?
есть что-то вроде finally () в Go, прямо противоположное init ()?
Вызываются ли отложенные функции при получении SIGINT в Go?
If–только для простоты - вам все еще нужен регистратор, который сбрасывается после каждого оператора журнала, вы можете легко добиться этого.Это связано с тем, что тип log.Logger
гарантирует, что каждое сообщение журнала доставляется в пункт назначения io.Writer
с помощью одного Writer.Write()
вызова:
Каждая операция записи создает одинвызов метода Writer Write.Logger может использоваться одновременно с несколькими программами;он гарантирует сериализацию доступа к Writer.
Таким образом, в основном все, что вам нужно сделать, это создать «обертку» io.Writer
, метод Write()
которой выполняет сброс после «пересылки» Write()
вызов его основного писателя.
Вот как это может выглядеть:
type myWriter struct {
io.Writer
}
func (m *myWriter) Write(p []byte) (n int, err error) {
n, err = m.Writer.Write(p)
if flusher, ok := m.Writer.(interface{ Flush() }); ok {
flusher.Flush()
} else if syncer := m.Writer.(interface{ Sync() error }); ok {
// Preserve original error
if err2 := syncer.Sync(); err2 != nil && err == nil {
err = err2
}
}
return
}
Эта реализация проверяет как метод Flush()
, так и os.File
's Sync()
метод и вызовы, если они «присутствуют».
Вот как это можно использовать, чтобы операторы журналирования всегда сбрасывались:
f, err := os.Create("log.txt")
if err != nil {
panic(err)
}
defer f.Close()
log.SetOutput(&myWriter{Writer: f})
log.Println("hi")
См. Связанные вопросы:
Go: создание интерфейса io.Writer для ведения журнала в базе данных mongodb
net / http set custom logger