beats软件
上周,我写了一篇关于如何从Java开发人员的背景开始开发Logstash插件的文章 。 但是,通过收购Packetbeat,Logstash现在可以从Beats获得帮助,将数据推送到Elasticsearch。 Beats是用Go开发的,这是传统Java开发人员的另一个挑战。 本周,我尝试将Logstash Reddit插件移植到专用的Beat。 这篇文章记录了我的发现(破坏者:我发现它比使用Ruby容易得多)。
搭建环境
在OSX上,安装go
可执行文件很容易:
brew install go
尽管Java或Ruby(或我所知道的任何一种语言)可以驻留在本地文件系统上的任何位置,但是Go项目必须全部位于一个单独的专用位置,该位置在$GOPATH
环境变量下可用。
创建项目
至于Logstash插件,可以从模板创建Beats项目。 做到这一点的文档非常简单。 鉴于Go对文件系统位置的严格要求,只需遵循以下说明即可生成一个新的即用型Go项目。
默认模板代码将在控制台中重复发送带有递增计数器的事件:
./redditbeat -e -d "*" 2016/12/13 22:55:56.013362 beat.go:267: INFO Home path: [/Users/i303869/projects/private/go/src/github.com/ajavageek/redditbeat] Config path: [/Users/i303869/projects/private/go/src/github.com/ajavageek/redditbeat] Data path: [/Users/i303869/projects/private/go/src/github.com/ajavageek/redditbeat/data] Logs path: [/Users/i303869/projects/private/go/src/github.com/ajavageek/redditbeat/logs] 2016/12/13 22:55:56.013390 beat.go:177: INFO Setup Beat: redditbeat; Version: 6.0.0-alpha1 2016/12/13 22:55:56.013402 processor.go:43: DBG Processors: 2016/12/13 22:55:56.013413 beat.go:183: DBG Initializing output plugins 2016/12/13 22:55:56.013417 logp.go:219: INFO Metrics logging every 30s 2016/12/13 22:55:56.013518 output.go:167: INFO Loading template enabled. Reading template file: /Users/i303869/projects/private/go/src/github.com/ajavageek/redditbeat/redditbeat.template.json 2016/12/13 22:55:56.013888 output.go:178: INFO Loading template enabled for Elasticsearch 2.x. Reading template file: /Users/i303869/projects/private/go/src/github.com/ajavageek/redditbeat/redditbeat.template-es2x.json 2016/12/13 22:55:56.014229 client.go:120: INFO Elasticsearch url: http://localhost:9200 2016/12/13 22:55:56.014272 outputs.go:106: INFO Activated elasticsearch as output plugin. 2016/12/13 22:55:56.014279 publish.go:234: DBG Create output worker 2016/12/13 22:55:56.014312 publish.go:276: DBG No output is defined to store the topology. The server fields might not be filled. 2016/12/13 22:55:56.014326 publish.go:291: INFO Publisher name: LSNM33795267A 2016/12/13 22:55:56.014386 async.go:63: INFO Flush Interval set to: 1s 2016/12/13 22:55:56.014391 async.go:64: INFO Max Bulk Size set to: 50 2016/12/13 22:55:56.014395 async.go:72: DBG create bulk processing worker (interval=1s, bulk size=50) 2016/12/13 22:55:56.014449 beat.go:207: INFO redditbeat start running. 2016/12/13 22:55:56.014459 redditbeat.go:38: INFO redditbeat is running! Hit CTRL-C to stop it. 2016/12/13 22:55:57.370781 client.go:184: DBG Publish: { "@timestamp": "2016-12-13T22:54:47.252Z", "beat": { "hostname": "LSNM33795267A", "name": "LSNM33795267A", "version": "6.0.0-alpha1" }, "counter": 1, "type": "redditbeat" }
关于命令行参数: -e
记录到标准err,而-d "*"
启用所有调试选择器。 有关参数的完整列表,请键入./redditbeat --help
。
代码
Go代码位于.go
的文件(一个惊喜......)中的项目子文件夹$GOPATH/src
文件夹中。
配置类型
第一个有趣的文件是config/config.go
,它定义了一个struct
来声明Beat的可能参数。 至于以前的Logstash插件,让我们添加一个subreddit
参数,并将其设置为默认值:
typeConfigstruct{
Periodtime.Duration`config:"period"`
Subredditstring`config:"subreddit"`
}
varDefaultConfig=Config{
Period:15*time.Second,
Subreddit:"elastic",
}
打浆机类型
Beat本身的代码可在beater/redditbean.go
找到。 默认模板为Beat和三个函数创建一个struct
:
- Beat构造函数-它读取配置:
funcNew(b*beat.Beat,cfg*common.Config)(beat.Beater,error){...}
-
Run
功能-应该循环播放Beat的主要功能:func(bt*Redditbeat)Run(b*beat.Beat)error{...}
-
Stop
功能可正常关闭:func(bt*Redditbeat)Stop(){...}
Go中没有明确的接口实现。 仅从接口实现所有方法都会创建一个隐式继承关系。 出于文档目的,这是Beater接口:键入Beater接口{Run(b * Beat)错误Stop()}
因此,由于Beat结构同时实现Run
和Stop
,因此它是 Beater
。
Go中没有类的概念,因此无法在具体类型上声明方法。 但是,它存在扩展功能的概念:可以向类型(在单个程序包内)添加行为的功能。 它需要声明接收者类型:这是在fun关键字和函数名称之间完成的-在这里,它是Redditbeat类型(或更正确的是,指向Redditbeat类型的指针,但是存在隐式转换)。
构造函数和Stop
函数可以保持不变,无论要开发什么功能,都必须在Run
函数中。 在这种情况下,功能是调用Reddit REST API并为每个Reddit帖子发送一条消息。
最终代码如下所示:
func(bt*Redditbeat)Run(b*beat.Beat)error{
bt.client=b.Publisher.Connect()
ticker:=time.NewTicker(bt.config.Period)
reddit:="https://www.reddit.com/r/"+bt.config.Subreddit+"/.json" (1)
client:=&http.Client{} (2)
for{
select{
case<-bt.done:
returnnil
case<-ticker.C:
}
req,reqErr:=http.NewRequest("GET",reddit,nil) (3)
req.Header.Add("User-Agent","Some existing header to bypass 429 HTTP") (4)
if(reqErr!=nil){ (5)
panic(reqErr) (6)
}
resp,getErr:=client.Do(req) (7)
if(getErr!=nil){
panic(getErr)
}
body,readErr:=ioutil.ReadAll(resp.Body) (8)
deferresp.Body.Close() (9)
if(readErr!=nil){
panic(readErr)
}
trimmedBody:=body[len(prefix):len(body)-len(suffix)] (10)
messages:=strings.Split(string(trimmedBody),separator) (11)
fori:=0;i<len(messages);i++{
event:=common.MapStr{ (12)
"@timestamp":common.Time(time.Now()),
"type":b.Name,
"message":"{"+messages[i]+"}",
}
bt.client.PublishEvent(event) (13)
}
}
}
这是最重要的部分的说明:
- 通过串联字符串(包括配置
Subreddit
参数)创建Reddit REST URL。 请记住,其默认值已在config.go
文件中定义。 - 获取有关新的HTTP客户端类型的参考
- 创建一个新的HTTP请求。 请注意,Go允许多个返回值。
- 如果未设置标准请求标头,则Reddit的API将返回
429
状态代码 - 执行标准错误不会通过异常处理,而是会与常规返回值一起返回。 根据Golang Wiki:
向调用者指示错误条件应通过返回错误值来完成
-
panic()
函数类似于在Java中引发异常,使堆栈爬升直到处理完。 有关更多信息,请参阅相关文档 。 - 执行HTTP请求
- 将响应主体读入字节数组
- 关闭体液。 注意
defer
关键字:defer语句将函数的执行推迟到周围的函数返回之前。
- 创建一个切片 -对整个响应正文字节数组的一部分数组的引用。 本质上,它删除了前缀和后缀以保留相关的JSON值。 将字节数组解析为JSON可能会过大。
- 分割切片以分别获取每个JSON片段
- 将消息创建为简单的字典结构
- 发送
配置,构建和启动
可以在项目根目录的redditbeat.yml
文件中找到默认配置参数。 请注意, redditbeat.full.yml
中列出了其他常见的Beat参数以及相关注释。
Beats的有趣之处在于,它们的消息可以直接发送到Elasticsearch或Logstash进行进一步处理。 这是在上述配置文件中配置的。
redditbeat:
period:10s
output.elasticsearch:
hosts:["localhost:9200"]
output.logstash:
hosts:["localhost:5044"]
enabled:true
此配置代码段将每10秒钟循环遍历Run
方法,并将消息发送到在端口5044上的localhost上运行的Logstash实例。运行Beat时可以覆盖此实例(请参见下文)。
为了使Logstash接受来自Beats的消息,必须安装Logstash Beat插件,并且必须为Beats配置Logstash输入:
input {
beats {
port => 5044
}
}
要构建项目,请在项目的根目录下键入make
。 它将创建一个可以运行的可执行文件。
./redditbeat -e -E redditbeat.subreddit=java
-E
标志可以覆盖在嵌入式redditbeat.yml
配置文件中找到的参数(请参见上文)。 在这里,它会将要读取的子reddit设置为“ java”,而不是默认的“ elastic”。
输出如下所示:
2016/12/17 14:51:19.748329 client.go:184: DBG Publish: { "@timestamp": "2016-12-17T14:51:19.748Z", "beat": { "hostname": "LSNM33795267A", "name": "LSNM33795267A", "version": "6.0.0-alpha1" }, "message": "{ \"kind\": \"t3\", \"data\": { \"contest_mode\": false, \"banned_by\": null, \"domain\": \"blogs.oracle.com\", \"subreddit\": \"java\", \"selftext_html\": null, \"selftext\": \"\", \"likes\": null, \"suggested_sort\": null, \"user_reports\": [], \"secure_media\": null, \"saved\": false, \"id\": \"5ipzgq\", \"gilded\": 0, \"secure_media_embed\": {}, \"clicked\": false, \"report_reasons\": null, \"author\": \"pushthestack\", \"media\": null, \"name\": \"t3_5ipzgq\", \"score\": 11, \"approved_by\": null, \"over_18\": false, \"removal_reason\": null, \"hidden\": false, \"thumbnail\": \"\", \"subreddit_id\": \"t5_2qhd7\", \"edited\": false, \"link_flair_css_class\": null, \"author_flair_css_class\": null, \"downs\": 0, \"mod_reports\": [], \"archived\": false, \"media_embed\": {}, \"is_self\": false, \"hide_score\": false, \"spoiler\": false, \"permalink\": \"/r/java/comments/5ipzgq/jdk_9_will_no_longer_bundle_javadb/\", \"locked\": false, \"stickied\": false, \"created\": 1481943248.0, \"url\": \"https://blogs.oracle.com/java-platform-group/entry/deferring_to_derby_in_jdk\", \"author_flair_text\": null, \"quarantine\": false, \"title\": \"JDK 9 will no longer bundle JavaDB\", \"created_utc\": 1481914448.0, \"link_flair_text\": null, \"distinguished\": null, \"num_comments\": 4, \"visited\": false, \"num_reports\": null, \"ups\": 11 } }", "type": "redditbeat" }
结论
奇怪的是,我发现开发Beat比使用Logstash插件容易。 Go的层次较低,有些概念确实很陌生(例如隐式接口实现),但是生态系统要简单得多-因为语言是最新的。 此外,Beats更具通用性,因为它们可以发送到Elasticsearch和/或Logstash。
翻译自: https://blog.frankel.ch/starting-beats-development-for-java-developers/
beats软件