opentracing-go原始碼閱讀——Log儲存(完結篇)

cdh0805010118發表於2018-07-03

Log

該log設計參考了uber-go/zap, 日誌值型別非常多,該設計把日誌型別分為三類:string, int64和interface{}, 其中:

  1. string={string};
  2. int64={bool, int, int32, uint32, int64, uint64, float32, float64}, notice: 這裡沒有覆蓋int16和uint16
  3. interface{}={error, object, lazyLogger, noop}

根據Span interface中的LogFields和LogKVs方法, log.Field應該會包含{key, value}, 同時因為value值型別包含三類,所以Field的結構如下:

type Field struct {
    key         string
    fieldType   fieldType
    numericVal  int64
    stringVal   string
    interfaceVal    interface{}
}

Field提供了返回key,返回value和String三個方法操作,這已滿足需要;

注意,Span Tags和Span Logs不同的一點在於,Logs是可以累加的,並不是map結構,是列表儲存[]log.Fields

實現Span Logs的標準化結構如下:

func String(key, val string) Field {
    return Field{
        key:        key,
        fieldType:  stringType,
        stringVal:  val,  
    }
}

// 其他型別都類似處理, 對於error和lazyLogger型別,不需要指定key
func Error(err error) Field{
    return Field{
        key:        "error",
        fieldType:  errorType,
        interfaceVal:   err,
    }
}

// LazyLogger 對廠商暴露出的自定義日誌實現
type LazyLogger func(fv Encoder)

func Lazy(ll LazyLogger) Field{
    return Field{
        fieldType: lazyLoggerType,
        interfaceVal: ll,
    }
}

// Noop用於忽略一些日誌處理;
// 例如:dev/test/prod的trace日誌等
func Noop() Field{
    return Field{
        fieldType: noopType,
    }
}

我們可以對log.Field進行編碼操作,類似於json/xml Marshal操作;這個Encoder interface列出了log.Field中value值所有型別;所以,如果要對log.Field編碼操作,則需要實現所有值型別,共三大類。

對於Span interface中的LogFields和LogKVs兩個方法都是對[]log.Fields進行儲存,這兩個方法存在一個資料結構化轉換方法: InterleavedKVToFields, 把key-value鍵值對列表轉換成[]log.Field結構化日誌資料。

參考資料

opentracing-go

相關文章