Files
build-web-application-with-…/zh-tw/13.4.md
2019-02-26 01:40:54 +08:00

256 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 13.4 日誌和配置設計
## 日誌和配置的重要性
前面已經介紹過日誌在我們程式開發中起著很重要的作用透過日誌我們可以記錄除錯我們的資訊當初介紹過一個日誌系統seelog根據不同的level輸出不同的日誌這個對於程式開發和程式部署來說至關重要。我們可以在程式開發中設定level低一點部署的時候把level設定高這樣我們開發中的除錯資訊可以遮蔽掉。
配置模組對於應用部署牽涉到伺服器不同的一些配置資訊非常有用,例如一些資料庫配置資訊、監聽埠、監聽地址等都是可以透過配置檔案來配置,這樣我們的應用程式就具有很強的靈活性,可以透過配置檔案的配置部署在不同的機器上,可以連線不同的資料庫之類別的。
## beego的日誌設計
beego的日誌設計部署思路來自於seelog根據不同的level來記錄日誌但是beego設計的日誌系統比較輕量級採用了系統的log.Logger介面預設輸出到os.Stdout,使用者可以實現這個介面然後透過beego.SetLogger設定自訂的輸出詳細的實現如下所示
```Go
// Log levels to control the logging output.
const (
LevelTrace = iota
LevelDebug
LevelInfo
LevelWarning
LevelError
LevelCritical
)
// logLevel controls the global log level used by the logger.
var level = LevelTrace
// LogLevel returns the global log level and can be used in
// own implementations of the logger interface.
func Level() int {
return level
}
// SetLogLevel sets the global log level used by the simple
// logger.
func SetLevel(l int) {
level = l
}
```
上面這一段實現了日誌系統的日誌分級預設的級別是Trace使用者透過SetLevel可以設定不同的分級。
```Go
// logger references the used application logger.
var BeeLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime)
// SetLogger sets a new logger.
func SetLogger(l *log.Logger) {
BeeLogger = l
}
// Trace logs a message at trace level.
func Trace(v ...interface{}) {
if level <= LevelTrace {
BeeLogger.Printf("[T] %v\n", v)
}
}
// Debug logs a message at debug level.
func Debug(v ...interface{}) {
if level <= LevelDebug {
BeeLogger.Printf("[D] %v\n", v)
}
}
// Info logs a message at info level.
func Info(v ...interface{}) {
if level <= LevelInfo {
BeeLogger.Printf("[I] %v\n", v)
}
}
// Warning logs a message at warning level.
func Warn(v ...interface{}) {
if level <= LevelWarning {
BeeLogger.Printf("[W] %v\n", v)
}
}
// Error logs a message at error level.
func Error(v ...interface{}) {
if level <= LevelError {
BeeLogger.Printf("[E] %v\n", v)
}
}
// Critical logs a message at critical level.
func Critical(v ...interface{}) {
if level <= LevelCritical {
BeeLogger.Printf("[C] %v\n", v)
}
}
```
上面這一段程式碼預設初始化了一個BeeLogger物件預設輸出到os.Stdout使用者可以透過beego.SetLogger來設定實現了logger的介面輸出。這裡面實現了六個函式
- Trace一般的記錄資訊舉例如下
- "Entered parse function validation block"
- "Validation: entered second 'if'"
- "Dictionary 'Dict' is empty. Using default value"
- Debug除錯資訊舉例如下
- "Web page requested: http://somesite.com Params='...'"
- "Response generated. Response size: 10000. Sending."
- "New file received. Type:PNG Size:20000"
- Info列印資訊舉例如下
- "Web server restarted"
- "Hourly statistics: Requested pages: 12345 Errors: 123 ..."
- "Service paused. Waiting for 'resume' call"
- Warn警告資訊舉例如下
- "Cache corrupted for file='test.file'. Reading from back-end"
- "Database 192.168.0.7/DB not responding. Using backup 192.168.0.8/DB"
- "No response from statistics server. Statistics not sent"
- Error錯誤資訊舉例如下
- "Internal error. Cannot process request #12345 Error:...."
- "Cannot perform login: credentials DB not responding"
- Critical致命錯誤舉例如下
- "Critical panic received: .... Shutting down"
- "Fatal error: ... App is shutting down to prevent data corruption or loss"
可以看到每個函式裡面都有對level的判斷所以如果我們在部署的時候設定了level=LevelWarning那麼Trace、Debug、Info這三個函式都不會有任何的輸出以此類推。
## beego的配置設計
配置資訊的解析beego實現了一個key=value的配置檔案讀取類似ini配置檔案的格式就是一個檔案解析的過程然後把解析的資料儲存到map中最後在呼叫的時候通過幾個string、int之類別的函式呼叫返回相應的值具體的實現請看下面
首先定義了一些ini配置檔案的一些全域性性常量
```Go
var (
bComment = []byte{'#'}
bEmpty = []byte{}
bEqual = []byte{'='}
bDQuote = []byte{'"'}
)
```
定義了配置檔案的格式:
```Go
// A Config represents the configuration.
type Config struct {
filename string
comment map[int][]string // id: []{comment, key...}; id 1 is for main comment.
data map[string]string // key: value
offset map[string]int64 // key: offset; for editing.
sync.RWMutex
}
```
定義瞭解析檔案的函式解析檔案的過程是開啟檔案然後一行一行的讀取解析註釋、空行和key=value資料
```Go
// ParseFile creates a new Config and parses the file configuration from the
// named file.
func LoadConfig(name string) (*Config, error) {
file, err := os.Open(name)
if err != nil {
return nil, err
}
cfg := &Config{
file.Name(),
make(map[int][]string),
make(map[string]string),
make(map[string]int64),
sync.RWMutex{},
}
cfg.Lock()
defer cfg.Unlock()
defer file.Close()
var comment bytes.Buffer
buf := bufio.NewReader(file)
for nComment, off := 0, int64(1); ; {
line, _, err := buf.ReadLine()
if err == io.EOF {
break
}
if bytes.Equal(line, bEmpty) {
continue
}
off += int64(len(line))
if bytes.HasPrefix(line, bComment) {
line = bytes.TrimLeft(line, "#")
line = bytes.TrimLeftFunc(line, unicode.IsSpace)
comment.Write(line)
comment.WriteByte('\n')
continue
}
if comment.Len() != 0 {
cfg.comment[nComment] = []string{comment.String()}
comment.Reset()
nComment++
}
val := bytes.SplitN(line, bEqual, 2)
if bytes.HasPrefix(val[1], bDQuote) {
val[1] = bytes.Trim(val[1], `"`)
}
key := strings.TrimSpace(string(val[0]))
cfg.comment[nComment-1] = append(cfg.comment[nComment-1], key)
cfg.data[key] = strings.TrimSpace(string(val[1]))
cfg.offset[key] = off
}
return cfg, nil
}
```
下面實現了一些讀取配置檔案的函式返回的值確定為bool、int、float64或string
```Go
// Bool returns the boolean value for a given key.
func (c *Config) Bool(key string) (bool, error) {
return strconv.ParseBool(c.data[key])
}
// Int returns the integer value for a given key.
func (c *Config) Int(key string) (int, error) {
return strconv.Atoi(c.data[key])
}
// Float returns the float value for a given key.
func (c *Config) Float(key string) (float64, error) {
return strconv.ParseFloat(c.data[key], 64)
}
// String returns the string value for a given key.
func (c *Config) String(key string) string {
return c.data[key]
}
```
## 應用指南
下面這個函式是我一個應用中的例子用來取得遠端url地址的json資料實現如下
```Go
func GetJson() {
resp, err := http.Get(beego.AppConfig.String("url"))
if err != nil {
beego.Critical("http get info error")
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
err = json.Unmarshal(body, &AllInfo)
if err != nil {
beego.Critical("error:", err)
}
}
```
函式中呼叫了框架的日誌函式`beego.Critical`函式用來報錯,呼叫了`beego.AppConfig.String("url")`用來取得配置檔案中的資訊,配置檔案的資訊如下(app.conf)
```Go
appname = hs
url ="http://www.api.com/api.html"
```
## links
* [目錄](<preface.md>)
* 上一章: [controller設計](<13.3.md>)
* 下一節: [實現部落格的增刪改](<13.5.md>)