2015-11-24 14 views
8

Tôi đã tránh sử dụng log.Fatal, nhưng gần đây tôi đã vô tình phát hiện ra những câu hỏi này; code-coveragetests-using-log-fatal.Gói Go có nên sử dụng log.Fatal và khi nào không?

Một trong những ý kiến ​​từ những câu hỏi bảo hiểm 100 mã nói:

... Trong hầu hết các trường hợp log.Fatal nên chỉ được sử dụng trong các chức năng chính, hoặc init (hoặc có thể một số điều có nghĩa là để được gọi là chỉ trực tiếp từ họ)"

Nó đi tôi suy nghĩ, vì vậy tôi bắt đầu nhìn vào mã thư viện chuẩn được cung cấp với Go. có rất nhiều ví dụ về nơi kiểm tra mã trong thư viện tận dụng log.Fatal có vẻ ổn. một vài ví dụ bên ngoài của mã kiểm tra, chẳng hạn như trong net/http, hiển thị dưới đây:

// 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) 
     } 
    } 
    ... 
} 

Nếu nó là thực hành tốt nhất để tránh sử dụng log.Fatal, tại sao là nó được sử dụng ở tất cả trong các thư viện chuẩn, tôi lại có thể ngờ chỉ trả lại một lỗi. Có vẻ như không công bằng đối với người sử dụng thư viện làm cho os.Exit được gọi và không cung cấp bất kỳ cơ hội nào cho ứng dụng để dọn dẹp.

Tôi có thể ngây thơ, do đó, câu hỏi của tôi như là một thực hành tốt hơn có vẻ là để gọi log.Panic mà có thể được phục hồi và ứng dụng ổn định dài chạy của tôi lý thuyết có thể có cơ hội tăng từ đống tro tàn.

Vì vậy, thực hành tốt nhất nên nói gì về Tìm hiểu khi nào nên đăng nhập.Tiếp nên được sử dụng?

+3

Tôi hy vọng rằng mã này hoàn toàn không thể truy cập được. Đó là một lỗi gây ra một kết nối nhàn rỗi để được vẫn còn trong danh sách nhàn rỗi trong khi cũng đang được sử dụng như một kết nối hoạt động không phải là một cái gì đó sẽ xảy ra bao giờ hết, và cho nó xảy ra nên được một cái gì đó thảm khốc. Nhưng vì chúng dường như đang sử dụng các mutex đúng cách quanh danh sách nhàn rỗi và vân vân, tôi không biết tại sao vòng lặp và mã này lại cần thiết. Tại sao họ sẽ tiếp tục thoát khỏi chương trình của bạn ngay lập tức thay vì hoảng sợ là một bí ẩn khác. Câu hỏi tuyệt vời. – captncraig

+0

Có bất kỳ thử nghiệm nào trong gói đó có thể tiếp cận được dòng đó không? – captncraig

+0

Câu hỏi hay, có một chút nhìn và không thể nhìn thấy bất cứ điều gì trông giống như thiết kế đặc biệt của nó để đạt được dòng đó. Chưa kết luận ... – miltonb

Trả lời

8

Có thể chỉ là tôi, nhưng đây là cách tôi sử dụng log.Fatal. Theo các quy ước UNIX, một quá trình gặp lỗi sẽ thất bại càng sớm càng tốt với mã thoát khác không. Điều này dẫn tôi các nguyên tắc sau đây để sử dụng log.Fatal khi ...

  1. ... một lỗi xảy ra trong bất kỳ func init() của tôi, như những xảy ra khi nhập khẩu được chế biến hoặc trước func chính được gọi là, tương ứng. Ngược lại, tôi chỉ làm những thứ không ảnh hưởng trực tiếp đến đơn vị công việc mà thư viện hay cmd phải làm. Ví dụ, tôi thiết lập đăng nhập và kiểm tra thời tiết, chúng tôi có một môi trường và thông số lành mạnh. Không cần phải chạy chính nếu chúng ta có cờ không hợp lệ, phải không? Và nếu chúng ta không thể đưa ra phản hồi đúng, chúng ta nên nói điều này sớm.
  2. … một lỗi xảy ra mà tôi biết là không thể khôi phục. Giả sử chúng ta có một chương trình tạo ra một hình thu nhỏ của một tệp hình ảnh được đưa ra trên dòng lệnh. Nếu tệp này không tồn tại hoặc không thể đọc được vì không đủ quyền, không có lý do gì để tiếp tục và lỗi này không thể phục hồi được. Vì vậy, chúng tôi tuân thủ các quy ước và thất bại.
  3. … một lỗi xảy ra trong quá trình có thể không thể hoàn nguyên. Đây là một định nghĩa mềm, tôi biết. Hãy để tôi minh họa điều đó. Giả sử chúng ta có triển khai thực hiện cp và bắt đầu sao chép thư mục không tương tác và đệ quy. Bây giờ, giả sử chúng ta gặp phải một tệp trong thư mục đích có cùng tên (nhưng nội dung khác nhau) như một tệp được sao chép ở đó. Vì chúng tôi không thể yêu cầu người dùng quyết định phải làm gì và chúng tôi không thể sao chép tệp này, chúng tôi gặp sự cố. Bởi vì người dùng sẽ giả định rằng các thư mục nguồn và đích là các bản sao chính xác khi chúng ta kết thúc với mã thoát zero, chúng ta không thể bỏ qua tệp đang được đề cập đến. Tuy nhiên, chúng tôi không thể chỉ ghi đè lên nó, vì điều này có khả năng phá hủy thông tin.Đây là một tình huống chúng tôi không thể phục hồi từ mỗi yêu cầu rõ ràng của người sử dụng, và vì vậy tôi muốn sử dụng log.Fatal để giải thích tình hình, theo đây tuân theo nguyên tắc thất bại càng sớm càng tốt.
+1

Tôi thích câu trả lời của bạn vì nó giải thích các điểm tốt (và cộng hưởng với những ý tưởng của riêng tôi về chủ đề này) nhưng tôi sợ nó bỏ lỡ một chút quan trọng: OP yêu cầu rõ ràng về cách sử dụng 'log.Fatal' * trong một gói * - - đó là, trong một đoạn mã không được kiểm soát bởi bất cứ ai đã viết 'main()'. Như bạn có thể thấy, điều này thực sự chuyển câu hỏi từ một miền "quy trình hoạt động tốt" sang miền "gói ứng xử tốt" - câu chuyện hoàn toàn khác cho câu hỏi trở thành: liệu có ổn không làm hỏng chương trình của người khác không? – kostix

+1

Nó được bảo hiểm, mặc dù một chút ngầm: Tôi áp dụng các quy tắc bất kể thời tiết tôi viết một gói hoặc một cmd: một lỗi irrecoverable là một lỗi irrecoverable. Đó là trách nhiệm của chương trình khi đưa ra một gói đầu vào được vệ sinh. Nếu điều đó là không thể, một lỗi nên được trả lại, nhưng chỉ khi đầu vào không thể được khử trùng trước. Vì vậy, fataling khi thích hợp thực sự giúp người dùng của một gói để viết mã tốt hơn. –

+1

Thing là, nó không phải là cuộc gọi của người bảo trì gói nếu một cái gì đó là không thể phục hồi hay không. Chắc chắn, bạn không thể tạo hình thu nhỏ, nhưng tôi đã sử dụng nó như một phần nhỏ của máy chủ web của tôi. Nếu một gói hình thu nhỏ gọi os.Exit vì nó không thể tải một tệp, tôi sẽ bị kích động. – captncraig

Các vấn đề liên quan