前面已經介紹過日志在我們程式開發中起著很重要的作用,通過日志我們可以記錄除錯我們的資訊,當初介紹過一個日志系統seelog,根據不同的level輸出不同的日志,這個對于程式開發和程式部署來說至關重要,我們可以在程式開發中設定level低一點,部署的時候把level設定高,這樣我們開發中的除錯資訊可以屏蔽掉,
配置模塊對于應用部署牽涉到服務器不同的一些配置資訊非常有用,例如一些資料庫配置資訊、監聽埠、監聽地址等都是可以通過組態檔來配置,這樣我們的應用程式就具有很強的靈活性,可以通過組態檔的配置部署在不同的機器上,可以連接不同的資料庫之類的,
beego的日志設計
beego的日志設計部署思路來自于seelog,根據不同的level來記錄日志,但是beego設計的日志系統比較輕量級,采用了系統的log.Logger介面,默認輸出到os.Stdout,用戶可以實作這個介面然后通過beego.SetLogger設定自定義的輸出,詳細的實作如下所示:
// 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可以設定不同的分級,
// 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組態檔的一些全域性常量 :
var (
bComment = []byte{'#'}
bEmpty = []byte{}
bEqual = []byte{'='}
bDQuote = []byte{'"'}
)
定義了組態檔的格式:
// 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資料:
// 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:
// 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資料,實作如下:
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):
appname = hs
url ="http://www.api.com/api.html"
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/258992.html
標籤:其他
