成爲七牛雲 Contributor -如何貢獻 logkit 代碼


logkit 是 Pandora 開源的一個通用的日誌收集工具,可以將不同數據源的數據方便的發送到 Pandora 進行數據分析。除了基本的數據發送功能,logkit 還有容錯、併發、監控、刪除等功能。具體的 logkit 設計可以參閱《數據收集工具的設計與最佳實踐》,本文將重點介紹如何 contribute logkit 。

我們也特別準備了七牛雲限量周邊作爲見面禮。歡迎大家加入我們,成爲七牛雲 Contributor (詳情請見文末) 【Contributor 登記表】

環境準備與運行

下載 go 源碼
下載地址:
https://golang.org/dl/

以 linux 爲例:

wget https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz

安裝 go 源碼
以 linux 爲例:
解壓並移動到相應的系統目錄,假設爲 /opt

tar xzf go1.8.3.linux-amd64.tar.gz && mv go /opt/

配置系統的環境變量
以 Linux 爲例:

export PATH=$PATH:/opt/go/bin
export GOROOT=/opt/go
export GOPATH=~/gopath
export PATH=$PATH:~/gopath/bin

請加入到 home 目錄的.bashrc中, windows 就設置爲系統環境變量(全局生效)

運行並生效環境變量

source ~/.bashrc

創建 logkit GOPATH 目錄,並進入
以 Linux 爲例:

mkdir -p  ~/gopath/src/github.com/qiniu/
cd  ~/gopath/src/github.com/qiniu/

下載 logkit 源碼

在此之前,可能你需要安裝一下 git 工具。
以 linux 爲例安裝 git :

apt-get install git
git clone https://github.com/qiniu/logkit.git

進入 logkit 源碼目錄

cd ~/gopath/src/github.com/qiniu/logkit

下載 logkit 包管理工具

go get -u github.com/kardianos/govendor

下載並同步所有 logkit 依賴包

govendor sync

運行 logkit

go run logkit.go -f logkit.conf

代碼更新

git pull
govender sync

貢獻 logkit 數據源插件

logkit 目前提供六種讀取日誌的方式,分別爲 File Reader、ElasticSearch Reader、MongoDB Reader、MySQL Reader、MicroSoft SQL Server Reader、Kafka Reader
* File Reader: 讀取文件中的日誌數據,包括 csv 格式的文件, kafka-rest 日誌文件,nginx 日誌文件等,並支持以 grok 的方式解析日誌。
* ElasticSearch Reader: 讀取 ElasticSearch 中的數據。
* MongoDB Reader: 讀取 MongoDB 中的數據。
* MySQL Reader: 讀取 MySQL 中的數據。
* MicroSoft SQL Server Reader: 讀取 Microsoft SQL Server 中的數據。
* Kafka Reader: 讀取 Kafka 中的數據。
*
而實現一個 logkit 的自定義 reader 只需要實現以下接口即可。

// Reader 是一個通用的行讀取 reader 接口
type Reader interface {
   Name( ) string
   Source( ) string
   ReadLine( ) (string, error)
   SetMode(mode string, v interface{}) error
   Close( ) error
   SyncMeta( )
}
  • Name( )方法是爲了方便的獲取 Reader 名稱,做出區別。
  • Source( )方法返回讀取的數據源說明,通常是一個自定義的標記,如讀取文件的話就是文件路徑,讀取 mysql 的話可以是數據庫地址、名稱、表等。
  • ReadLine( ) 就是讀取一行數據,這個「行」是一個寬泛的概念,並不一定以\n分隔就是行,那麼如何定義行呢? SetMode( )方法解決這個問題。
  • SetMode( )方法定義行首的正則表達式,也可以不做這個定義,默認以\n分隔作爲一行。
  • Close( )方法包括關閉文件句柄、服務連接等常規的結束操作。
  • SyncMeta( ) 同步讀取的元信息,記錄讀取位置,以便重啓等異常情況下可以繼續讀取,不會丟失數據也不會重複讀取。

從數據來源上分類,數據讀取大致可分爲從文件讀取、從數據存儲服務端讀取以及從消息隊列中讀取三類。

每一類 Reader 均在發送成功後通過 SyncMeta( ) 函數記錄讀取的位置,保證數據不會因爲 runner 意外中斷而丟失。

從文件讀取數據
這一類最爲常見,logkit 支持的已經較爲完善,可以參閱 file reader 瞭解相關內容,支持包括多文件編碼格式支持、讀取限速等多種功能。

從數據存儲服務中讀取數據
這一類目前 logkit 支持從 MongoDB、MySQL、MSSQL、Elasticsearch 這四個數據源中讀取。
* 在 SyncMeta( ) 的策略上,這一類從服務器中讀取的數據可以採用時間戳策略,如 MongoDB、MySQL 中記錄的數據,應該都包含一個時間戳 (timestamp) 的字段,每次讀取數據均按這個時間戳字段排序,以此獲得新增的數據或者數據更新(數據有更新也要更新這個時間戳字段)。
* 週期性運行,需要爲用戶設計類似定時器等策略,方便用戶可以週期性運行,不斷同步收集服務器中的數據。
* 考慮性能,在數據量大的情況下,要分批次獲取數據,可以參閱不同數據源服務器提供的批量獲取數據的方式,針對性的設計性能最優的數據拉取模式。

從消息隊列中讀取數據
從消息隊列中讀取數據在設計上最爲簡單,因爲消息隊列服務器在提供服務的時候就會考慮到讀取的各類問題,直接利用好消費隊列的 API 即可。注意記錄讀取的 Offset ,防止數據丟失。

貢獻 logkit 解析器插件

Parser 是在數據被 logkit 讀取後,用戶可以根據需要定製化的解析日誌格式,抽取數據中的字段,轉化爲結構化數據的方式。

目前 logkit 已經內置一部分數據解析方式,他們分別爲:
* csv (按行通過分隔符解析): csv parser
* json (通過 json 反序列化解析): json parser
* grok (通過配置 grok pattern 解析): grok parser
* qiniulog (七牛開源的 golang 日誌庫日誌格式解析): Qiniu Log Parser
* kafkarest (Kafkarest 日誌解析): KafkaRestLog Parser
* raw (直接按行讀取返回): Raw Parser

Parser 典型配置如下

   "parser":{
       "name":"req_csv",
       "type":"csv",
       "labels":"machine nb110,team pandora"
   },
  1. name parser 的 name,用來標識
  2. type parser 的類型
  3. labels 對於所有的 Parser ,我們均提供了標籤功能,用於記錄一些額外的信息,添加到結構化的數據字段中,如常見的日誌所在機器、業務所述團隊等信息,labels 的寫法則是標籤名稱和數值以空格隔開<標籤名> <標籤內容>,多個標籤提供逗號分隔。

根據不同的 Parser ,還需要填寫其他特定 Parser 相關的配置文件,詳情請參閱各 Parser 的配置頁面。

若上述內置的解析器無法滿足用戶需求, Logkit 也支持用戶根據需要自己實現解析邏輯,只需要實現如下兩個接口。

type LogParser interface {
   Name() string
   // parse lines into structured datas
   Parse(lines []string) (datas []sender.Data, err error)
}

Parser 的接口非常簡單,一共就 2 個方法。

首先 Name( ) 函數表示 Parser 的名稱,用於標識;其次就是批量解析數據的 Parse 方法,傳入的是一個字符串數組,數組的每一個元素就是 reader 中 readline 函數獲取的每一行,爲了性能更高傳入數組進行批量解析,返回的數據就是按照 sender 中定義的 Data 類型,實際上對應的就是 Go 語言的 map[string]interface{}類型。

所以 Parser 要做 2 件事情。
1. 確定最終要解析出的 schema ,即字段 (field 或者 key) 和類型 (type)。像 json 這種數據天生就含有 schema ,無需用戶定義,其他類型的解析器可能需要用戶在配置文件中寫明 schema 是怎麼樣的。
1. 定義規則將傳入的字符串按照 schema 解析。 Parser 之間的主要區別實際上就是規則的不同,如 csv parser 就是按照指定的分隔符分隔; json parser 就是按照 json 格式解析 等等。根據你 Parser 對應要解析的字符串內容實現你的解析規則即可。

實現完成 Parser 後,注意在 NewParserRegistry( ) 中註冊對應的 new 方法噢,如下所示。

func NewParserRegistry() *ParserRegistry {
   ps := &ParserRegistry{
       parserTypeMap: map[string]func(conf.MapConf) (LogParser, error){},
   }
   ps.RegisterParser(TypeCSV, NewCsvParser)
   ps.RegisterParser(TypeRaw, NewRawlogParser)
   ps.RegisterParser(TypeKafkaRest, NewKafaRestlogParser)
   ps.RegisterParser(TypeEmpty, NewEmptyParser)
   ps.RegisterParser(TypeGrok, NewGrokParser)
   ps.RegisterParser(TypeJson, NewJsonParser)
   ps.RegisterParser(TypeNginx, NewNginxParser)

      //ps.RegisterParser(TypeMyNewParser, NewMyNewParser)

   return ps
}

一個示例的自定義 Parser

package samples

import (
   "strings"

   "github.com/qiniu/logkit/conf"
   "github.com/qiniu/logkit/parser"
   "github.com/qiniu/logkit/sender"
)

// 一個自定義parser的示例,將日誌放到data中的log字段中
type CustomParser struct {
   // parser 的名字
   name string
   // 每行截斷最大字符數
   maxLen int
}

func NewMyParser(c conf.MapConf) (parser.LogParser, error) {
   // 獲取parser配置中的name項,默認myparser
   name, _ := c.GetStringOr("name", "myparsername")
   // 獲取parser配置中的max_len選項,默認1000
   maxLen, _ := c.GetIntOr("max_len", 1000)
   p := &CustomParser{
       name:   name,
       maxLen: maxLen,
   }
   return p, nil
}

func (p *CustomParser) Name() string {
   return p.name
}

func (p *CustomParser) Parse(lines []string) (datas []sender.Data, err error) {
   for _, l := range lines {
       d := sender.Data{}
       line := strings.TrimSpace(l)
       if len(line) > p.maxLen {
           line = line[:p.maxLen]
       }
       d["log"] = line
       datas = append(datas, d)
   }
   return datas, nil
}

貢獻更多的 Transformer 插件

Transformer 是 Parser 的一個補充,它針對字段進行數據變換。

在大多數場景下,你可能用 Parser 就解決了全部問題,但是有些場合,你使用的 Parser 可能比較簡單,如 json parser ,此時你發現數據裏面有一部分字段你希望做一些擴展,比如有個 ip 字符串,你希望將其擴展爲 ip 對應的區域、城市、省份、運營商等信息,此時你就可以配置一個 Transformer ,對 IP 字段進行轉換。

再比如,當你希望做一些字符串替換的時候,你又不想寫一個 Parser ,只希望對某個字段做一個字符串替換處理,那就可以寫配置一個 replace transformer 。

Transform 既可以在 Parser 前調用,也可以在 Parser 後調用。同樣,也可以連着調用,調用順序就是你在配置文件中配置的順序。
一份帶有 Transformer 的配置如下:

{
       "name":"test2.csv",
       "reader":{
           "log_path":"./tests/logdir",
           "mode":"dir"
       },
       "parser":{
           "name":"jsonps",
           "type":"json"
       },
       "transforms":[{
           "type":"replace",
           "stage":"before_parser",
           "old":"\\x",
           "new":"\\\\x"
       }],
       "senders":[{
           "name":"file_sender",
           "sender_type":"file",
           "file_send_path":"./test2/test2_csv_file.txt"
       }]
}

可以看到,在 reader、parser 和 sender 同級別下面,增加一個 transforms 字段,對應的就是不同 transformer 對應的列表。

type 字段是固定的,每個 Transformer 都有,表示 Transformer 的類型名稱,其他字段則根據 Transformer 表達的轉換行爲各不相同。可以參見每個 Transformer 的介紹頁。

目前支持的 Transformer 有:
* replace transformer : 針對字段做字符串替換。
* IP transformer: 針對ip做運營商信息字段擴展。
* date transformer: 將字段解析爲時間並做一些轉換。
* discard transformer: 將指定字段的數據拋棄。
* split transformer: 將指定字段的數據切分爲字符串數組。
* convert transformer: 按照 dsl 將數據進行格式轉換。

目前 logkit 的 Transformer 接口如下:

// 注意: transform的規則是,出錯要把數據原樣返回
type Transformer interface {
   Description() string
   SampleConfig() string
   ConfigOptions() []utils.Option
   Type() string
   Transform([]sender.Data) ([]sender.Data, error)
   RawTransform([]string) ([]string, error)
   Stage() string
   Stats() utils.StatsInfo
}
  • Description( ) string : 描述並返回 Transformer 作用的字符串
  • SampleConfig( ) string: 描述並返回 Transformer 示例配置的字符串
  • ConfigOptions( ) [ ]utils.Option: 描述並返回 Transform 配置選項的方法。
  • Type() string: 描述 Transform 類型的方法
  • Transform([]sender.Data) ([]sender.Data, error): 轉換 Transform 數據,該方法轉換的是 Parser 後的數據,接受的是 Data 數組。
  • RawTransform([]string) ([]string, error): 轉換 Transform 數據,該方法轉換的是 Parser 前的數據,接受的是 string 數組
  • Stage() string: 表示 Transform 是用於 Parser 前還是 Parser 後
  • Stats() utils.StatsInfo: 統計 Transform 成功失敗的數據

Transformer 註冊
如下所示,每個 Transformer 需要在 init 方法中註冊自己,這樣只需 import 對應的包就能註冊,無需額外的代碼侵入。

func init() {
   transforms.Add("discard", func() transforms.Transformer {
       return &Discarder{}
   })
}

註冊時返回的實際上是一個 create 方法, create 的就是對應 Transformer 的結構體。

Transformer 個性化配置
Transformer 中最有趣的是如何將各種不同的配置統一的定義到Transformer 中呢? 答案就是利用 json 協議,將配置的 json 字符串反序列化到生成 Transformer 結構體中,即實現了每個具體 Transformer 的賦值。
“`
creater, _ := transforms.Transformers[TransformType] //從註冊中獲得對應類型的Transformer creator
trans := creater() //調用Transformer creator創建Transformer對象
err = json.Unmarshal(bts, trans) // 將配置的json字符串反序列化到對象的結構體中

通過上述過程,用戶的不同配置就能讓不同 Transformer 感知了。

所以在定義 Transformer 時需要注意描述好對應的 json 格式 key 名稱,並且保證變量名是大寫的,如下所示爲一個表示字符串替換的 Transformer 定義:

type Replacer struct {
StageTime string json:"stage"
Key string json:"key"
Old string json:"old"
New string json:"new"
}

**Transformer 的執行順序**
Transformer 可以在 Parser 前使用也可以在 Parser 後使用,其中 Stage()方法表示的就是這個位置。

Parser 前使用即 Reader 剛剛獲取的數據就做一次 Transform 轉換,針對的就是 reader 中讀取的字符串,這裏你可以做一些諸如字符串替換、字符串切割的 Transformer ,以便直接使用諸如 json parser 這樣通用的 Parser ,省的再去編寫複雜的解析過程。

Parser 後使用的 Transform 就多了,因爲經過了 Parser ,帶有了 schema 信息,可以知道數據的字段名稱和類型,所以可以針對某些字段做轉換,比如字符串操作、 IP 擴展等等。

多個 Transformer 可以按順序串聯起來依次執行,寫配置文件的時候按順序填寫在 json 數組中即可。

**Transformer的參數說明**
爲了使 logkit 可以在前端更好的展示,Transformer 中還需要寫ConfigOptions()接口,該接口返回的就是每個 Transformer 的配置對應的字段名稱、數據類型以及作用說明。

## 一個示例的 Transformer

package mutate

import (
“errors”

“github.com/qiniu/logkit/sender”
“github.com/qiniu/logkit/transforms”
“github.com/qiniu/logkit/utils”
)

type Discarder struct {
Key string json:"key"
stats utils.StatsInfo
}

func (g *Discarder) RawTransform(datas []string) ([]string, error) {
return datas, errors.New(“discard transformer not support rawTransform”)
}

func (g *Discarder) Transform(datas []sender.Data) ([]sender.Data, error) {
var ferr error
errnums := 0
for i := range datas {
delete(datas[i], g.Key)
}
g.stats.Errors += int64(errnums)
g.stats.Success += int64(len(datas) - errnums)
return datas, ferr
}

func (g *Discarder) Description() string {
return “discard onefield from data”
}

func (g *Discarder) Type() string {
return “discard”
}

func (g *Discarder) SampleConfig() string {
return {
"type":"discard",
"key":"DiscardFieldKey"
}

}

func (g *Discarder) ConfigOptions() []utils.Option {
return []utils.Option{
transforms.KeyStageAfterOnly,
transforms.KeyFieldName,
}
}

func (g *Discarder) Stage() string {
return transforms.StageAfterParser
}

func (g *Discarder) Stats() utils.StatsInfo {
return g.stats
}

func init() {
transforms.Add(“discard”, func() transforms.Transformer {
return &Discarder{}
})
}

## 貢獻更多的發送端插件

Senders 的主要作用是將 Parser 後的數據發送至 Sender 支持的各類服務,目前支持發送到的服務包括: Pandora、ElasticSearch、File、InfluxDB、MongoDB 五種服務。

1. Pandora Sender: 發送到 Pandora (七牛大數據處理平臺)。
1. ElasticSearch Sender: 發送到 ElasticSearch。
1. File Sender: 發送到本地文件。
1. InfluxDB Sender: 發送到 InfluxDB。
1. MongoDB Accumulate Sender: 聚合後發送到 MongoDB。

除了上述五種發送到服務之外,logkit 還支持一種發送到本地磁盤進行數據發送預處理的模式( fault_tolerant 設置爲 true,ft_strategy 設置爲 always_save ),進行了 fault_tolerant 模式設置後,數據的 reader/parser 就和發送異步,數據可以持續讀取並解析進入磁盤隊列, sender 則可以多線程發送,可以有效提升發送效率,併發發送數據。

## 典型配置如下

“senders”:[{
“name”:”pandora_sender”,
“sender_type”:”pandora”,
“pandora_ak”:”“,
“pandora_sk”:”“,
“pandora_host”:”https://pipeline.qiniu.com“,
“pandora_repo_name”:”yourRepoName”,
“pandora_region”:”nb”,
“pandora_schema”:”field1 pandora_field1,field2,field3 pandora_field3”,
“fault_tolerant”:”true”,
“ft_sync_every”:”5”,
“ft_save_log_path”:”./ft_log”,
“ft_write_limit”:”1”,
“ft_strategy”:”always_save”,
“ft_procs”:”2”
}]

1. name: 是 sender 的標識
1. sender_type: sender 類型,支持file, mongodb_acc, pandora, influxdb
1. fault_tolerant: 是否用異步容錯方式進行發送,默認爲false。
1. ft_save_log_path: 當 fault_tolerant 爲 true 時候必填。該路徑必須爲文件夾,該文件夾會作爲本地磁盤隊列,存放數據,進行異步容錯發送。
1. ft_sync_every:當 fault_tolerant 爲 true 時候必填。多少次發送數據會記錄一次本地磁盤隊列的 offset 。
1. ft_write_limit:選填,爲了避免速率太快導致磁盤壓力加大,可以根據系統情況自行限定寫入本地磁盤的速率,單位 MB/s。默認10MB/s
1. ft_strategy: 選填,該選項設置爲 backup_only 的時候,數據不經過本地隊列直接發送到下游,設爲 always_save 時則所有數據會先發送到本地隊列,選 concurrent 的時候會直接併發發送,不經過隊列。無論該選項設置什麼,失敗的數據都會加入到重試隊列中異步循環重試。默認選項爲 always_save。
1. ft_procs :該選項表示從本地隊列獲取數據點並向下遊發送的併發數,如果 ft_strategy 設置爲 backup_only,則本項設置無效,只有本地隊列有數據時,該項配置纔有效,默認併發數爲 1.
1. ft_memory_channel : 選填,默認爲 "false" ,不啓用。開啓該選項會使用 memory channel 作爲 fault_tolerant 中 disk queue 的替代,相當於把 fault_tolerant 作爲一個隊列使用,使得發送和數據讀取解析變爲異步,加速整個發送的過程。但是使用 memory channel 數據不落磁盤,會有數據丟失的風險。該功能適合與 ft_procs 連用,利用內存隊列,異步後,在發送端多併發加速。
1. ft_memory_channel_size: 選填,默認爲 "100",單位爲 batch,也就是 100 代表 100個待發送的批次,當ft_memory_channel 啓用時有效,設置 memory channel 的大小。 注意:該選項設置的大小表達的是隊列中可存儲的元素個數,並不是佔用的內存大小。

**補充說明**

* 設置 fault_tolerant 爲 "true" 時,會維持一個本地隊列緩存起需要發送的數據。當數據發送失敗的時候會在本地隊列進行重試,此時如果發送錯誤,不會影響 logkit 繼續收集日誌。
* 設置 fault_tolerant 爲 "true" 時,可以保證每次服務重啓的時候都從上次的發送offset繼續進行發送。在 parse 過程中產生中間結果,需要高容錯性發送的時候最適合採用此種模式。
* 設置 fault_tolerant 爲 "true" 時,一般希望日誌收集程序對機器性能影響較小的時候,建議首先考慮將ft_strategy設置爲backup_only,配置這個選項會首先嚐試發送數據,發送失敗的數據才放到備份隊列等待下次重試。如果還希望更小的性能影響,並且數據敏感性不高,也可以不使用 fault_tolerant 模式。
* 當日志發送的速度已經趕不上日誌生產速度時,設置fault_tolerant爲"true",且 ft_strategy 設置爲 concurrent,通過設置 ft_procs 加大併發,ft_procs 設置越大併發度越高,發送越快,對機器性能帶來的影響也越大。
* 如果 ft_procs 增加已經不能再加大發送日誌速度,那麼就需要 加大 ft_write_limit 限制,爲 logkit 的隊列提升磁盤的讀寫速度。
* senders 支持多個 sender 配置,但是我們不推薦在 senders 中加入多個 sender,因爲一旦某個 sender 發送緩慢,就會導致其他 sender 等待這個 sender 發送成功後再發。簡單來說,配置多個 sender 會互相影響。

## 如何添加更多 Sender (自定義 Sender)?


Sender 的主要作用是將隊列中的數據發送至 Sender 支持的各類服務,實現 logkit 的 sender 僅需實現如下接口:

type Sender interface {
Name() string
Send([]Data) error
Close() error
}

其中包括三個函數,Name( ) 標識 Sender 名稱,Send( ) 發送數據,Close( ) 關閉一些服務連接等常規操作。

**實現一個 Sender 的注意事項**
1. 多線程發送:多線程發送可以充分利用 CPU 多核的能力,提升發送效率,這一點我們已經設計了 ft sender 作爲框架解決了該問題。
1. 錯誤處理與等待:服務端偶爾出現一些異常是很正常的事情,此時就要做好不同錯誤情況的處理,不會因爲某個錯誤而導致程序出錯,另外一方面,一旦發現出錯應該讓 sender 等待一定時間再發送,設定一個對後端友好的變長錯誤等待機制也非常重要。一般情況下,可以採用隨着連續錯誤出現遞增等待時間的方法,直到一個最頂峯(如10s),就不再增加,當服務端恢復後再取消等待。
1. 數據壓縮發送:帶寬是非常珍貴的資源,通常服務端都會提供 gzip 壓縮的數據接收接口,而 sender 利用這些接口,將數據壓縮後發送,能節省大量帶寬成本。
1. 帶寬限流:通常情況下數據收集工具只是機器上的一個附屬程序,主要資源如帶寬還是要預留給主服務,所以限制 sender 的帶寬用量也是非常重要的功能,限流的方法就可以採用前面 Channel 一節提到的令牌桶算法。
1. 字段填充( UUID/timestamp ):通常情況下收集的數據信息可能不是完備的,需要填充一些信息進去,如全局唯一的 UUID 、代表收集時間的 timestamp 等字段,提供這些字段自動填充的功能,有利於用戶對其數據做唯一性、時效性等方面的判斷。
1. 字段別名:解析後的字段名稱中經常會出現一些特殊字符,如"$","@"等符號,如果發送的服務端不支持這些特殊字符,就需要提供一些重命名的功能,將這些字段映射到一個別的名稱。
1. 字段篩選:未必解析後的所有字段數據都需要發送,這時候提供一個字段篩選的功能,可以方便用戶選擇去掉一些無用的字段,也可以節省傳輸的成本。也可以在 Transformer 中也提供類似 discard transformer 的功能,將某個字段去掉。
1. 類型轉換:類型轉換是一個說來簡單但是做起來非常繁瑣的事情,不只是純粹的整型轉換成浮點型,或者字符串轉成整型這麼簡單,還涉及到你發送到的服務端支持的一些特殊類型,如date時間類型等,更多的類型轉換實際上相當於最佳實踐,能夠做好這些類型轉換,就會讓用戶體驗得到極大提升。
1. 簡單、簡單、簡單:除了上述這些,剩下的就是儘可能的讓用戶使用簡單。比如假設我們要寫一個 mysql sender,mysql 的數據庫和表如果不存在,可能數據會發送失敗,那就可以考慮提前創建;又比如數據如果有更新了,那麼就需要將針對這些更新的字段去更新服務的 Schema 等等。

**註冊Sender**
與Parser類似,實現完畢的Sender注意要註冊進SenderRegistry中,如下所示:

func NewSenderRegistry() *SenderRegistry {
ret := &SenderRegistry{
senderTypeMap: map[string]func(conf.MapConf) (Sender, error){},
}
ret.RegisterSender(TypeFile, NewFileSender)
ret.RegisterSender(TypePandora, NewPandoraSender)
ret.RegisterSender(TypeMongodbAccumulate, NewMongodbAccSender)
ret.RegisterSender(TypeInfluxdb, NewInfluxdbSender)
ret.RegisterSender(TypeElastic, NewElasticSender)
ret.RegisterSender(TypeDiscard, NewDiscardSender)

  // ret.RegisterSender(TypeMyNewSender, NewMyNewSender)

return ret
}

**一個示例的自定義Sender**

package samples

import (
“fmt”

“github.com/qiniu/log”
“github.com/qiniu/logkit/conf”
“github.com/qiniu/logkit/sender”
)

// CustomSender 僅作爲示例,什麼都不做,只是把數據打印出來而已
type CustomSender struct {
name string
prefix string
}

func NewMySender(c conf.MapConf) (sender.Sender, error) {
name, _ := c.GetStringOr(“name”, “my_sender_name”)
prefix, _ := c.GetStringOr(“prefix”, “”)
return &CustomSender{
name: name,
prefix: prefix,
}, nil
}

func (c *CustomSender) Name() string {
return c.name
}

func (c *CustomSender) Send(datas []sender.Data) error {
for _, d := range datas {
var line string
for k, v := range d {
line += fmt.Sprintf(“%v=%v “, k, v)
}
log.Info(c.prefix, line)
}
return nil
}
func (c *CustomSender) Close() error {
return nil
}
“`
至此,就全部介紹完了,歡迎加入我們一起貢獻 logkit 代碼!

成爲七牛雲 Contributor

  1. 瀏覽以上內容;
  2. 點擊填寫「 Contributor 登記表」
  3. 當 PR 經我們 Review 合併後,貢獻者即自動成爲我們的 New Contributor;
  4. 我們的小夥伴會主動聯繫 New Contributor 並隨機將以下一件七牛雲限量周邊作爲見面禮,折躍到你的手中。
  5. 很高興認識你!



想了解更多?

  • 訪問我們的Github站:PandoraLogkit
  • 關注我們的知乎專欄:Pandora
  • 也歡迎投稿分享大家在大數據領域的開源經歷和實踐經驗

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章