2015-11-24 1 views
8

Я до сих пор избегал использования log.Fatal, но недавно я случайно встретил эти вопросы; code-coverage и tests-using-log-fatal.Должен ли пакет Go когда-либо использовать log.Fatal и когда?

Одно из замечаний вопросов покрытия на 100 кодов говорит:

... В подавляющем большинстве случаев log.Fatal следует использовать только в основных, или инициализации функций (или, возможно, некоторые вещи, которые предназначены для можно назвать только непосредственно от них)»

Это идет мне думать, так что я начал смотреть на стандартном коде библиотеки снабженного Go. Есть много примеров, когда теста код в библиотеке использует log.Fatal, который кажется прекрасным. несколько примеров вне тестового кода, например, в net/http, как показано ниже:

// net/http/transport.go 
func (t *Transport) putIdleConn(pconn *persistConn) bool { 
    ... 
    for _, exist := range t.idleConn[key] { 
     if exist == pconn { 
      log.Fatalf("dup idle pconn %p in freelist", pconn) 
     } 
    } 
    ... 
} 

Если его лучше практика, чтобы избежать использования log.Fatal, почему он используется вообще в стандартных библиотеках, я бы ожидал просто верните ошибку. Для пользователя библиотеки кажется несправедливым вызывать os.Exit и не дает возможности для очистки приложения.

Я могу быть наивным, поэтому мой вопрос, как лучший пример, может состоять в том, чтобы позвонить log.Panic, который может быть восстановлен, и мое теоретическое долговременное стабильное приложение может иметь шанс подняться из пепла.

Итак, что лучше всего сказать для Go about when log.Fatal следует использовать?

+3

Надеюсь, что этот код абсолютно недостижим. То, что ошибка, которая приводит к тому, что незанятое соединение остается в списке ожидания, а также используется как активное соединение, не должна быть чем-то, что должно происходить когда-либо, и для того, чтобы это произошло, должно быть что-то катастрофическое. Но поскольку они, похоже, правильно используют мьютексы вокруг списка простоя и т. Д., Я понятия не имею, почему этот цикл и код даже необходимы. Почему они будут дальше выходить из вашей программы, а не паниковать, это еще одна загадка. Отличный вопрос. – captncraig

+0

Являются ли какие-либо из тестов в этом пакете доступными для этой линии? – captncraig

+0

Хороший вопрос, немного поглядел и не мог видеть ничего похожего на его специально разработанное для достижения этой линии. Еще не окончательно ... – miltonb

ответ

8

Это может быть только я, но вот как я использую log.Fatal. В соответствии с соглашениями UNIX процесс, который сталкивается с ошибкой, должен как можно скорее сгенерировать ненужный код выхода. Это привело меня к следующим руководящим принципам, чтобы использовать log.Fatal когда ...

  1. ... ошибка происходит в любой из моих func init(), так как это происходит, когда импорт обрабатываются или перед главным FUNC называется, соответственно. И наоборот, я делаю то, что не влияет непосредственно на единицу работы, которую должна выполнять библиотека или cmd. Например, я настраиваю ведение журнала и проверяю, есть ли у нас нормальная среда и параметры. Нет необходимости запускать main, если у нас есть недопустимые флаги, не так ли? И если мы не сможем дать правильную обратную связь, мы должны сказать об этом раньше.
  2. ... ошибка, о которой я знаю, невосстановима. Предположим, у нас есть программа, которая создает миниатюру файла изображения, указанного в командной строке. Если этот файл не существует или не читается из-за недостаточных разрешений, нет причин для продолжения, и эта ошибка не может быть восстановлена. Поэтому мы придерживаемся конвенций и терпим неудачу.
  3. ... ошибка возникает во время процесса, который может не быть обратимым. Я знаю это довольно мягкое определение. Позвольте мне проиллюстрировать это. Предположим, что у нас есть реализация cp, и она была запущена, чтобы быть неинтерактивной и рекурсивно скопировать каталог. Теперь предположим, что мы сталкиваемся с файлом в целевом каталоге с таким же именем (но с другим контентом) в качестве файла для его копирования. Поскольку мы не можем попросить пользователя решить, что делать, и мы не можем скопировать этот файл, у нас есть проблема. Поскольку пользователь предположит, что исходные и целевые каталоги являются точными копиями, когда мы заканчиваем с нулевым кодом выхода, мы не можем просто пропустить указанный файл. Однако мы не можем просто перезаписать его, поскольку это может потенциально уничтожить информацию.Это ситуация, которую мы не можем восстановить из-за явного запроса пользователя, поэтому я бы воспользовался log.Fatal, чтобы объяснить ситуацию, тем самым повинуясь принципу неудачи как можно раньше.
+1

Мне нравится ваш ответ, так как он хорошо объясняет точки (и резонирует с моими собственными идеями по этой теме), но я боюсь, что он пропустил ключевой бит: OP явно спросил об использовании 'log.Fatal' * в пакете * - - то есть в куске кода, который не контролируется тем, кто пишет 'main()'. Как вы можете видеть, это фактически переводит вопрос из домена «хорошего поведения» в домен с «хорошим поведением» - совершенно другая история, на вопрос: можно ли безответственно отказаться от чьей-либо программы? – kostix

+1

Он покрыт, хотя и неявный: я применяю эти правила, независимо от того, где я пишу пакет или cmd: безвозвратная ошибка - это безвозвратная ошибка. Обязанностью программ является предоставление пакета для санированного ввода. Если это невозможно, следует вернуть ошибку, но только если вход не может быть предварительно продезинфицирован. Таким образом, со смертельным исходом, в случае необходимости, действительно помогает пользователю пакета писать лучший код. –

+1

Вещь, это не вызов сопровождающего пакета, если что-то безвозвратно или нет. Конечно, вы не смогли создать эскиз, но я использовал это как небольшую часть моего веб-сервера. Если пакет миниатюр вызывает os.Exit, потому что он не может загрузить файл, я буду возмущен. – captncraig

 Смежные вопросы

  • Нет связанных вопросов^_^