簡介:
目前創(chuàng)新互聯(lián)公司已為1000+的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機(jī)、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、天津網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
怎么使用
從上面的例子中我們分幾步來看
當(dāng)然本文沒有介紹zap的其他基本用法,只是講解了本人經(jīng)常用到的方法,其他方法如果有時(shí)間,我也會(huì)一一列出。謝謝大家觀看,比心~~
本文介紹一些Go語言的基礎(chǔ)語法。
先來看一個(gè)簡單的go語言代碼:
go語言的注釋方法:
代碼執(zhí)行結(jié)果:
下面來進(jìn)一步介紹go的基礎(chǔ)語法。
go語言中格式化輸出可以使用 fmt 和 log 這兩個(gè)標(biāo)準(zhǔn)庫,
常用方法:
示例代碼:
執(zhí)行結(jié)果:
更多格式化方法可以訪問中的fmt包。
log包實(shí)現(xiàn)了簡單的日志服務(wù),也提供了一些格式化輸出的方法。
執(zhí)行結(jié)果:
下面來介紹一下go的數(shù)據(jù)類型
下表列出了go語言的數(shù)據(jù)類型:
int、float、bool、string、數(shù)組和struct屬于值類型,這些類型的變量直接指向存在內(nèi)存中的值;slice、map、chan、pointer等是引用類型,存儲(chǔ)的是一個(gè)地址,這個(gè)地址存儲(chǔ)最終的值。
常量是在程序編譯時(shí)就確定下來的值,程序運(yùn)行時(shí)無法改變。
執(zhí)行結(jié)果:
執(zhí)行結(jié)果:
Go 語言的運(yùn)算符主要包括算術(shù)運(yùn)算符、關(guān)系運(yùn)算符、邏輯運(yùn)算符、位運(yùn)算符、賦值運(yùn)算符以及指針相關(guān)運(yùn)算符。
算術(shù)運(yùn)算符:
關(guān)系運(yùn)算符:
邏輯運(yùn)算符:
位運(yùn)算符:
賦值運(yùn)算符:
指針相關(guān)運(yùn)算符:
下面介紹一下go語言中的if語句和switch語句。另外還有一種控制語句叫select語句,通常與通道聯(lián)用,這里不做介紹。
if語法格式如下:
if ... else :
else if:
示例代碼:
語法格式:
另外,添加 fallthrough 會(huì)強(qiáng)制執(zhí)行后面的 case 語句,不管下一條case語句是否為true。
示例代碼:
執(zhí)行結(jié)果:
下面介紹幾種循環(huán)語句:
執(zhí)行結(jié)果:
執(zhí)行結(jié)果:
也可以通過標(biāo)記退出循環(huán):
--THE END--
日常開發(fā)當(dāng)中需要將golang的log包打印的日志同時(shí)輸出到控制臺(tái)和文件,應(yīng)該如何解決這個(gè)問題?
log包可以通過SetOutput()方法指定日志輸出的方式(Writer),但是只能指定一個(gè)輸出的方式(Writer)。我們利用io.MultiWriter()將多個(gè)Writer拼成一個(gè)Writer使用的特性,把log.Println()輸出的內(nèi)容分流到控制臺(tái)和文件當(dāng)中。
原文地址
在一段 http get 的程序中,如果出現(xiàn)錯(cuò)誤,打印日志后會(huì)導(dǎo)致程序退出。
將 log.Fatal 修改為 log.Println 即可解決問題。
感覺一個(gè)函數(shù)做了本不該它做的事情,有些好奇,golang 設(shè)計(jì)者的設(shè)計(jì)哲學(xué)。
對于Go語言的日志來說,如何將log寫到指定的文件里面,下面是一個(gè)例子。
output:
output:
云和安全管理服務(wù)專家新鈦云服 張春翻譯
這種方法有幾個(gè)缺點(diǎn)。首先,它可以對程序員隱藏錯(cuò)誤處理路徑,特別是在捕獲異常不是強(qiáng)制性的情況下,例如在 Python 中。即使在具有必須處理的 Java 風(fēng)格的檢查異常的語言中,如果在與原始調(diào)用不同的級別上處理錯(cuò)誤,也并不總是很明顯錯(cuò)誤是從哪里引發(fā)的。
我們都見過長長的代碼塊包裝在一個(gè) try-catch 塊中。在這種情況下,catch 塊實(shí)際上充當(dāng) goto 語句,這通常被認(rèn)為是有害的(奇怪的是,C 中的關(guān)鍵字被認(rèn)為可以接受的少數(shù)用例之一是錯(cuò)誤后清理,因?yàn)樵撜Z言沒有 Golang- 樣式延遲語句)。
如果你確實(shí)從源頭捕獲異常,你會(huì)得到一個(gè)不太優(yōu)雅的 Go 錯(cuò)誤模式版本。這可能會(huì)解決混淆代碼的問題,但會(huì)遇到另一個(gè)問題:性能。在諸如 Java 之類的語言中,拋出異??赡鼙群瘮?shù)的常規(guī)返回慢數(shù)百倍。
Java 中最大的性能成本是由打印異常的堆棧跟蹤造成的,這是昂貴的,因?yàn)檫\(yùn)行的程序必須檢查編譯它的源代碼 。僅僅進(jìn)入一個(gè) try 塊也不是空閑的,因?yàn)樾枰4?CPU 內(nèi)存寄存器的先前狀態(tài),因?yàn)樗鼈兛赡苄枰趻伋霎惓5那闆r下恢復(fù)。
如果您將異常視為通常不會(huì)發(fā)生的異常情況,那么異常的缺點(diǎn)并不重要。這可能是傳統(tǒng)的單體應(yīng)用程序的情況,其中大部分代碼庫不必進(jìn)行網(wǎng)絡(luò)調(diào)用——一個(gè)操作格式良好的數(shù)據(jù)的函數(shù)不太可能遇到錯(cuò)誤(除了錯(cuò)誤的情況)。一旦您在代碼中添加 I/O,無錯(cuò)誤代碼的夢想就會(huì)破滅:您可以忽略錯(cuò)誤,但不能假裝它們不存在!
try {
doSometing()
} catch (IOException e) {
// ignore it
}
與大多數(shù)其他編程語言不同,Golang 接受錯(cuò)誤是不可避免的。 如果在單體架構(gòu)時(shí)代還不是這樣,那么在今天的模塊化后端服務(wù)中,服務(wù)通常和外部 API 調(diào)用、數(shù)據(jù)庫讀取和寫入以及與其他服務(wù)通信 。
以上所有方法都可能失敗,解析或驗(yàn)證從它們接收到的數(shù)據(jù)(通常在無模式 JSON 中)也可能失敗。Golang 使可以從這些調(diào)用返回的錯(cuò)誤顯式化,與普通返回值的等級相同。從函數(shù)調(diào)用返回多個(gè)值的能力支持這一點(diǎn),這在大多數(shù)語言中通常是不可能的。Golang 的錯(cuò)誤處理系統(tǒng)不僅僅是一種語言怪癖,它是一種將錯(cuò)誤視為替代返回值的完全不同的方式!
重復(fù) if err != nil
對 Go 錯(cuò)誤處理的一個(gè)常見批評是被迫重復(fù)以下代碼塊:
res, err := doSomething()
if err != nil {
// Handle error
}
對于新用戶來說,這可能會(huì)覺得沒用而且浪費(fèi)行數(shù):在其他語言中需要 3 行的函數(shù)很可能會(huì)增長到 12 行 :
這么多行代碼!這么低效!如果您認(rèn)為上述內(nèi)容不優(yōu)雅或浪費(fèi)代碼,您可能忽略了我們檢查代碼中的錯(cuò)誤的全部原因:我們需要能夠以不同的方式處理它們!對 API 或數(shù)據(jù)庫的調(diào)用可能會(huì)被重試。
有時(shí)事件的順序很重要:調(diào)用外部 API 之前發(fā)生的錯(cuò)誤可能不是什么大問題(因?yàn)閿?shù)據(jù)從未通過發(fā)送),而 API 調(diào)用和寫入本地?cái)?shù)據(jù)庫之間的錯(cuò)誤可能需要立即注意,因?yàn)?這可能意味著系統(tǒng)最終處于不一致的狀態(tài)。即使我們只想將錯(cuò)誤傳播給調(diào)用者,我們也可能希望用失敗的解釋來包裝它們,或者為每個(gè)錯(cuò)誤返回一個(gè)自定義錯(cuò)誤類型。
并非所有錯(cuò)誤都是相同的,并且向調(diào)用者返回適當(dāng)?shù)腻e(cuò)誤是 API 設(shè)計(jì)的重要部分,無論是對于內(nèi)部包還是 REST API 。
不必?fù)?dān)心在你的代碼中重復(fù) if err != nil ——這就是 Go 中的代碼應(yīng)該看起來的樣子。
自定義錯(cuò)誤類型和錯(cuò)誤包裝
從導(dǎo)出的方法返回錯(cuò)誤時(shí),請考慮指定自定義錯(cuò)誤類型,而不是單獨(dú)使用錯(cuò)誤字符串。字符串在意外代碼中是可以的,但在導(dǎo)出的函數(shù)中,它們成為函數(shù)公共 API 的一部分。更改錯(cuò)誤字符串將是一項(xiàng)重大更改——如果沒有明確的錯(cuò)誤類型,需要檢查返回錯(cuò)誤類型的單元測試將不得不依賴原始字符串值!事實(shí)上,基于字符串的錯(cuò)誤也使得在私有方法中測試不同的錯(cuò)誤案例變得困難,因此您也應(yīng)該考慮在包中使用它們?;氐藉e(cuò)誤與異常的爭論,返回錯(cuò)誤也使代碼比拋出異常更容易測試,因?yàn)殄e(cuò)誤只是要檢查的返回值。不需要測試框架或在測試中捕獲異常 。
可以在 database/sql 包中找到簡單自定義錯(cuò)誤類型的一個(gè)很好的示例。它定義了一個(gè)導(dǎo)出常量列表,表示包可以返回的錯(cuò)誤類型,最著名的是 sql.ErrNoRows。雖然從 API 設(shè)計(jì)的角度來看,這種特定的錯(cuò)誤類型有點(diǎn)問題(您可能會(huì)爭辯說 API 應(yīng)該返回一個(gè)空結(jié)構(gòu)而不是錯(cuò)誤),但任何需要檢查空行的應(yīng)用程序都可以導(dǎo)入該常量并在代碼中使用它不必?fù)?dān)心錯(cuò)誤消息本身會(huì)改變和破壞代碼。
對于更復(fù)雜的錯(cuò)誤處理,您可以通過實(shí)現(xiàn)返回錯(cuò)誤字符串的 Error() 方法來定義自定義錯(cuò)誤類型。自定義錯(cuò)誤可以包括元數(shù)據(jù),例如錯(cuò)誤代碼或原始請求參數(shù)。如果您想表示錯(cuò)誤類別,它們很有用。DigitalOcean 的本教程展示了如何使用自定義錯(cuò)誤類型來表示可以重試的一類臨時(shí)錯(cuò)誤。
通常,錯(cuò)誤會(huì)通過將低級錯(cuò)誤與更高級別的解釋包裝起來,從而在程序的調(diào)用堆棧中傳播。例如,數(shù)據(jù)庫錯(cuò)誤可能會(huì)以下列格式記錄在 API 調(diào)用處理程序中:調(diào)用 CreateUser 端點(diǎn)時(shí)出錯(cuò):查詢數(shù)據(jù)庫時(shí)出錯(cuò):pq:檢測到死鎖。這很有用,因?yàn)樗梢詭椭覀兏欏e(cuò)誤在系統(tǒng)中傳播的過程,向我們展示根本原因(數(shù)據(jù)庫事務(wù)引擎中的死鎖)以及它對更廣泛系統(tǒng)的影響(調(diào)用者無法創(chuàng)建新用戶)。
自 Go 1.13 以來,此模式具有特殊的語言支持,并帶有錯(cuò)誤包裝。通過在創(chuàng)建字符串錯(cuò)誤時(shí)使用 %w 動(dòng)詞,可以使用 Unwrap() 方法訪問底層錯(cuò)誤。除了比較錯(cuò)誤相等性的函數(shù) errors.Is() 和 errors.As() 外,程序還可以獲取包裝錯(cuò)誤的原始類型或標(biāo)識。這在某些情況下可能很有用,盡管我認(rèn)為在確定如何處理所述錯(cuò)誤時(shí)最好使用頂級錯(cuò)誤的類型。
Panics
不要 panic()!長時(shí)間運(yùn)行的應(yīng)用程序應(yīng)該優(yōu)雅地處理錯(cuò)誤而不是panic。即使在無法恢復(fù)的情況下(例如在啟動(dòng)時(shí)驗(yàn)證配置),最好記錄一個(gè)錯(cuò)誤并優(yōu)雅地退出。panic比錯(cuò)誤消息更難診斷,并且可能會(huì)跳過被推遲的重要關(guān)閉代碼。
Logging
我還想簡要介紹一下日志記錄,因?yàn)樗翘幚礤e(cuò)誤的關(guān)鍵部分。通常你能做的最好的事情就是記錄收到的錯(cuò)誤并繼續(xù)下一個(gè)請求。
除非您正在構(gòu)建簡單的命令行工具或個(gè)人項(xiàng)目,否則您的應(yīng)用程序應(yīng)該使用結(jié)構(gòu)化的日志庫,該庫可以為日志添加時(shí)間戳,并提供對日志級別的控制。最后一部分特別重要,因?yàn)樗鼘⒃试S您突出顯示應(yīng)用程序記錄的所有錯(cuò)誤和警告。通過幫助將它們與信息級日志分開,這將為您節(jié)省無數(shù)時(shí)間。
微服務(wù)架構(gòu)還應(yīng)該在日志行中包含服務(wù)的名稱以及機(jī)器實(shí)例的名稱。默認(rèn)情況下記錄這些時(shí),程序代碼不必?fù)?dān)心包含它們。您也可以在日志的結(jié)構(gòu)化部分中記錄其他字段,例如收到的錯(cuò)誤(如果您不想將其嵌入日志消息本身)或有問題的請求或響應(yīng)。只需確保您的日志沒有泄露任何敏感數(shù)據(jù),例如密碼、API 密鑰或用戶的個(gè)人數(shù)據(jù)!
對于日志庫,我過去使用過 logrus 和 zerolog,但您也可以選擇其他結(jié)構(gòu)化日志庫。如果您想了解更多信息,互聯(lián)網(wǎng)上有許多關(guān)于如何使用這些的指南。如果您將應(yīng)用程序部署到云中,您可能需要日志庫上的適配器來根據(jù)您的云平臺(tái)的日志 API 格式化日志 - 沒有它,云平臺(tái)可能無法檢測到日志級別等某些功能。
如果您在應(yīng)用程序中使用調(diào)試級別日志(默認(rèn)情況下通常不記錄),請確保您的應(yīng)用程序可以輕松更改日志級別,而無需更改代碼。更改日志級別還可以暫時(shí)使信息級別甚至警告級別的日志靜音,以防它們突然變得過于嘈雜并開始淹沒錯(cuò)誤。您可以使用在啟動(dòng)時(shí)檢查以設(shè)置日志級別的環(huán)境變量來實(shí)現(xiàn)這一點(diǎn)。
原文: