Как и когда очищается регистратор Go SDK? - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь определить, сбрасываются ли функции по умолчанию / sdk logger log.PrintYYY () в определенный момент времени, при выходе, при панике и т. Д. Я не уверен, что мне нужно найти способ очисткимодуль записи, к которому подключен регистратор, особенно при настройке модуля записи с помощью SetOutput (...).Конечно, интерфейс писателя не имеет метода flush (), поэтому не совсем уверен, как это можно сделать.

Как и когда сбрасывается средство записи SDK Go?

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Пакет 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

0 голосов
/ 22 октября 2018

Регистратор не должен знать, как сбрасывать данные.Вы должны очистить выходной модуль записи, который вы указали при создании регистратора (если он имеет такую ​​возможность).

См. Пример из обсуждение на github

package main

import (
    "bufio"
    "flag"
    "log"
    "os"
    "strings"
)

func main() {
    var flush bool
    flag.BoolVar(&flush, "flush", false, "if set, will flush the buffered io before exiting")
    flag.Parse()

    br := bufio.NewWriter(os.Stdout)
    logger := log.New(br, "", log.Ldate)
    logger.Printf("%s\n", strings.Repeat("This is a test\n", 5))
    if flush {
        br.Flush()
    }
    logger.Fatalf("exiting now!")
}

Вы можете прочитать полностьюобсуждение вашей проблемы на github

Кроме того, вы можете посмотреть на сторонние регистраторы, которые имеют flush.Проверьте zap logger , у которого есть метод logger.Sync()

...