Beats:创建你自己的Beat

Beats是构建轻量级开源数据采集器的平台,该采集器将各种数据发送到Elasticsearch供以后分析。 我们有Packetbeat来监视服务器之间交换的网络流量,还有Filebeat来从服务器获取日志,Metricbeat定期从外部系统获取指标。 如果需要收集其他自定义数据,则可以基于libbeat框架轻松构建自己的Beat。 社区已经有90多个社区Beats

Elastic提供了Beats生成器软件包,可帮助您创建自己的节拍。 在此博客文章中,你将看到如何使用Beat生成器创建自己的Beat。 我们今天为练习而创建的节拍是lsbeat。 lsbeat索引文件和目录的信息,类似于Unix命令ls。 本文基于Unix,因此,如果您是Windows或其他OS用户,请按照适合你的OS的说明进行操作。

在今天的开发环境中,我们将使用Ubuntu 18.04来作为我们beat的开发环境。

 

在今天的开发中,我们将使用vagrant来部署我的Ubuntu OS。如果你还不知道如何创建自己的Ubuntu虚机的话,请参考我之前的文章“Vagrant 入门教程”。

 

配置开发环境

安装go环境

Beats实际上是go程序。我们可以参照链接“Go get started”来安装自己的golang语言开发环境。

wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.14.2.linux-amd64.tar.gz

当我们解压上面的go安装包后,它将生成一个/usr/local/go的目录,里面含有go语言的所有的安装:

$ pwd
/usr/local
vagrant@ubuntu-bionic:/usr/local$ ls go
AUTHORS          LICENSE    SECURITY.md  bin          lib   robots.txt
CONTRIBUTING.md  PATENTS    VERSION      doc          misc  src
CONTRIBUTORS     README.md  api          favicon.ico  pkg   test

将/usr/local/go/bin添加到PATH环境变量中。 您可以通过将以下行添加到您的/etc/profile(用于系统范围的安装)或$HOME/.profile中来完成此操作。针对我们的Ubuntu OS情况,我们可以填加到.bashrc文件中:

export PATH=$PATH:/usr/local/go/bin

添加完后,我们打入如下的命令使它起作用:

source .bashrc

等我们安装好我们的go后,我们可以在terminal中打入如下的命令:

$ which go
/usr/local/go/bin/go

为了我们接下来的开发,我们也同时加入如下的变量。我们把下面的内容都加入到.bashrc中。

export GOROOT=/usr/local/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
export GOPATH=$HOME/go/beats

在这里,我也设置了以GOPATH。你可以设置自己的路径。针对我的情况,我在我的home目录下创建了一个go目录,并在go目录下生产一个叫做beats的目录。在一下,我们会在这个目录里生成我们的定制的beat。在修改完.bashrc文件后,千万要记得打入如下的命令让修改的内容起作用:

$ source .bashrc

下载Elastic beats源码

在这一步我们下载Elastic beats的源码。在termnial中打入如下的命令:

mkdir -p ${GOPATH}/src/github.com/elastic
git clone https://github.com/elastic/beats ${GOPATH}/src/github.com/elastic/beats

安装Python

目前的generator只适合Python2,所以我们只需要安装Python2。我们打入如下的指令:

 sudo apt install python-minimal

我们可以通过如下的方式来检查python的版本:

$ python --version
Python 2.7.17

安装virtualenv

我们必须安装virtualenv才能使得generator正常工作。在Ubuntu上, 我们打入如下的命令进行安装:

sudo apt install virtualenv

如果自己的电脑上同时已经安装了python3,那么我们需要同时设置如写变量:

export PYTHON_EXE='python2.7'
export VIRTUALENV_PARAMS='-p python2.7'
export VIRTUALENV_PYTHON='/usr/bin/python2.7'
 
export VIRTUALENV_PYTHON='/usr/local/bin/python' (for Mac)

请注意:这里的python是2.x版本的python,而不是python3。我们需要保证VIRTUALENV_PYTHON指向我们的Python2的执行文件。

安装mage

我们需要在地址https://github.com/magefile/mage下载这个源码,并编译:

go get -u -d github.com/magefile/mage
cd $GOPATH/src/github.com/magefile/mage
go run bootstrap.go

等上面的命令执行完后,我们可以在如下的目录中找到编译好的执行文件mage:

$ ls $GOPATH/bin
mage

让我们看看我们将用于lsbeat的代码。 这是一个简单的Golang程序,它接收目录作为命令行参数,并列出该目录下的所有文件和子目录。

lsbeat.go

package main
import (
    "fmt"
    "io/ioutil"
    "os"
)
func main() {
    //apply run path "." without argument.
    if len(os.Args) == 1 {
        listDir(".")
    } else {
        listDir(os.Args[1])
    }
}
func listDir(dirFile string) {
    files, _ := ioutil.ReadDir(dirFile)
    for _, f := range files {
        t := f.ModTime()
        fmt.Println(f.Name(), dirFile+"/"+f.Name(), f.IsDir(), t, f.Size())
        if f.IsDir() {
            listDir(dirFile + "/" + f.Name())
        }
    }
}

我们可以通过如下的方式来编译这个文件,并执行它:

go build lsbeat.go
./lsbeat

然后,lsbeat应用将会显示在目前目录下的所有的文件。

创建lsbeat

首先创建一个目录在$GOPATH下,并进入该目录。

mkdir ${GOPATH}/src/github.com/{user}
cd ${GOPATH}/src/github.com/{user}

注意这里的user指的是自己在github上的用户名。比如针对我的情况是liu-xiao-guo。我打入如下写的命令:

mkdir ${GOPATH}/src/github.com/liu-xiao-guo
cd  $GOPATH/src/github.com/elastic/beats/

接下来,我们运行如下的命令:

mage GenerateCustomBeat

执行的结果是:

$ mage GenerateCustomBeat
2020/05/06 14:38:24 Found Elastic Beats dir at /home/vagrant/go/beats/src/github.com/elastic/beats
Enter the beat name [examplebeat]: lsbeat
Enter your github name [your-github-name]: liu-xiao-guo
Enter the beat path [github.com/liu-xiao-guo/lsbeat]: 
Enter your full name [Firstname Lastname]: Xiaoguo Liu
Enter the beat type [beat]: 
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
2020/05/06 14:43:13 Found Elastic Beats dir at /home/vagrant/go/beats/src/github.com/liu-xiao-guo/lsbeat/vendor/github.com/elastic/beats
Generated fields.yml for lsbeat to /home/vagrant/go/beats/src/github.com/liu-xiao-guo/lsbeat/fields.yml
2020/05/06 14:43:14 Found Elastic Beats dir at /home/vagrant/go/beats/src/github.com/liu-xiao-guo/lsbeat/vendor/github.com/elastic/beats

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'vagrant@ubuntu-bionic.(none)')
Error: running "git commit -q -m Initial commit, Add generated files" failed with exit code 128

这样,我们基本上就生产了一个最基本的beat的框架。

接下来,我们进入到我们的beat目录里,并进行编译:

cd ${GOPATH}/src/github.com/{user}/lsbeat

针对我的情况:

cd ${GOPATH}/src/github.com/liu-xiao-guo/lsbeat
$ pwd
/home/vagrant/go/beats/src/github.com/liu-xiao-guo/lsbeat
vagrant@ubuntu-bionic:~/go/beats/src/github.com/liu-xiao-guo/lsbeat$ ls
CONTRIBUTING.md  _meta   docs                  lsbeat.yml    tests
LICENSE.txt      beater  fields.yml            magefile.go   vendor
Makefile         build   include               main.go
NOTICE.txt       cmd     lsbeat.docker.yml     main_test.go
README.md        config  lsbeat.reference.yml  make.bat

这里有最基本的框架文件。里面含有一个叫做lsbeat.yml的配置文件及一些标准的模板文件。我们在命令行中直接打入如下的指令

make

经过上面的编译,我们可以发现在当前的目录下,有一个已经编译好的lsbeat可执行文件:

在之前我们的Elasticsearch的IP地址是192.168.0.100,所以,我们需要修改lsbeat.yml这个配置文件:

我们在当前的目录下直接运行这个可执行的文件:

./lsbeat -e -d "*"

我们可以在terminal中看到:

我们打开Kibana,并查看lsbeat的索引信息:

 

从上面我们可以看出来,lsbeat的log信息已经导入到Elasticsearch中了,但是它里面的信息并不是我们所希望看到的文件目录的信息。我们需要在下面对它进行改造。

        "_source" : {
          "@timestamp" : "2020-05-06T14:57:01.751Z",
          "type" : "ubuntu-bionic",
          "counter" : 1,
          "ecs" : {
            "version" : "1.2.0"
          },
          "host" : {
            "id" : "feb6a76832e547e7909c1be08e939cf6",
            "containerized" : false,
            "name" : "ubuntu-bionic",
            "hostname" : "ubuntu-bionic",
            "architecture" : "x86_64",
            "os" : {
              "kernel" : "4.15.0-96-generic",
              "codename" : "bionic",
              "platform" : "ubuntu",
              "version" : "18.04.4 LTS (Bionic Beaver)",
              "family" : "debian",
              "name" : "Ubuntu"
            }
          },
          "agent" : {
            "id" : "7f65adcf-407a-4188-a5bf-0726693a8196",
            "version" : "8.0.0",
            "type" : "lsbeat",
            "ephemeral_id" : "83506f48-072f-4f8a-8a76-cf52ce0d3dd0",
            "hostname" : "ubuntu-bionic"
          }
        }
      },

它里面含有一个counter的整数值。时间上默认的lsbeat模板就是一个计数的beat。

所有关于beat的设计上的代码可以在目录${GOPATH}/src/github.com/liu-xiao-guo/lsbeat下的/beater/CountBeat.go文件里实现的。设计比较直接。大家可以看一下代码应该可以明白。

配置

我们首先来配置lsbeat.yml文件。

lsbeat.yml

lsbeat:
  # Defines how often an event is sent to the output
  period: 1s

period是发生器在所有beat中包括的参数。 它表示lsbeat每1秒迭代一次该过程。 让我们将该时间段从1秒更改为10秒,并添加新的path参数,该参数代表顶级目录程序将扫描的路径。 我们可以将这些参数添加到_meta目录下的beat.yml中。

beat.yml

lsbeat:
  # Defines how often an event is sent to the output
  period: 10s
  path: "."

添加新参数后,我们运行make update命令将更改应用于lsbeat.yml配置文件。 我们可以看到在lsbeat.yml中现在可以使用在_meta/beat.yml中设置的新参数。

$ make update
$ cat lsbeat.yml
$ cat lsbeat.yml 
################### {Beat} Configuration Example #########################

############################# {Beat} ######################################

lsbeat:
  # Defines how often an event is sent to the output
  period: 10s
  path: "."
 
...

在更新完后,千万要记得在lsbeat.yml中修改我们的Elasticsearch的地址:

更新配置文件后,应编辑config/config.go,以便可以添加path参数。

package config
import "time"
type Config struct {
    Period time.Duration `config:"period"`
    Path   string        `config:"path"`
}
var DefaultConfig = Config {
    Period: 10 * time.Second,
    Path:   ".",
}

让我们使用默认配置选项将时间段设置为10秒,将默认目录使用当前目录(.)。

添加代码

每个Beat都需要通过定义 Run() 和 Stop() 函数来实现Beater接口。 此处提供了有关Beater界面的更详细指南。

为此,你只需要定义一个名为lsbeat的结构即可定义应该实现Beater接口的lsbeat对象。 让我们添加lastIndexTime,它将用于保存上一个时间戳数据。我们打开如下的文件:

beater/lsbeat.go

// lsbeat configuration.
type lsbeat struct {
        done   chan struct{}
        config config.Config
        client beat.Client
        lastIndexTime time.Time
}

此外,每个Beat都需要实现 New() 函数,该函数接收Beat的配置并返回类型为lsbeat的Beat对象。

// New creates an instance of lsbeat.
func New(b *beat.Beat, cfg *common.Config) (beat.Beater, error) {
        c := config.DefaultConfig
        if err := cfg.Unpack(&c); err != nil {
                return nil, fmt.Errorf("Error reading config file: %v", err)
        }

        bt := &lsbeat{
                done:   make(chan struct{}),
                config: c,
        }
        return bt, nil
}

对于lsbeat,我们想扩展默认的 Run() 函数以导出有关目录中可用文件和子目录的信息。

在修改 Run() 函数之前,让我们首先在lsbeat.go文件底部添加 listDir() 函数,该函数收集文件和目录信息。 它生成的事件包括:

  • "@timestamp": common.Time(time.Now())
  • "type": beatname
  • "modtime": common.Time(t)
  • "filename": f.Name()
  • "path": dirFile + "/" + f.Name()
  • "directory": f.IsDir()
  • "filesize": f.Size()

它将第一次为所有文件和目录建立索引,但是在执行第一个例程后,它将检查在第一个例程之后是否创建或修改了文件或目录,以索引较新的文件和目录。 最后一个例程的时间戳将保存在lasIndexTime变量中。

func (bt *lsbeat) listDir(dirFile string, beatname string) {
    files, _ := ioutil.ReadDir(dirFile)
    for _, f := range files {
        t := f.ModTime()
        path := filepath.Join(dirFile, f.Name())
        if t.After(bt.lastIndexTime) {

            event := beat.Event{
                Timestamp: time.Now(),
                Fields: common.MapStr {
                        "type":       beatname,
                        "modtime":    common.Time(t),
                        "filename":   f.Name(),
                        "path":       path,
                        "directory":  f.IsDir(),
                        "filesize":   f.Size(),
                },
            }

            bt.client.Publish(event)
        }
        if f.IsDir() {
            bt.listDir(path, beatname)
        }
    }
}

并且不要忘记在导入库中添加 io/ioutil 及 path/filepath包。

import (
        "fmt"
        "io/ioutil"
        "path/filepath"
        "time"

        "github.com/elastic/beats/libbeat/beat"
        "github.com/elastic/beats/libbeat/common"
        "github.com/elastic/beats/libbeat/logp"

        "github.com/liu-xiao-guo/lsbeat/config"
)

现在,让我们看一下 Run() 函数,该函数调用 listDir() 函数并将时间戳保存在lasIndexTime变量中。

func (bt *lsbeat) Run(b *beat.Beat) error {
    logp.Info("lsbeat is running! Hit CTRL-C to stop it.")

    var err error
    bt.client, err = b.Publisher.Connect()
    if err != nil {
        return err
    }

    // fmt.Printf("%+v\n", b)

    ticker := time.NewTicker(bt.config.Period)
    for {
        now := time.Now()
        bt.listDir(bt.config.Path, b.Info.Beat) // call listDir
        bt.lastIndexTime = now                  // mark Timestamp
        logp.Info("Event sent")
        select {
        case <-bt.done:
            return nil
        case <-ticker.C:
        }
    }
    return nil
}

Stop() 函数应该中断运行循环,并且与生成的函数相同:

func (bt *lsbeat) Stop() {
    bt.client.Close()
    close(bt.done)
}

我们几乎完成了编码。 我们必须在映射上添加新字段。 在 _meta/fields.yml 文件中添加字段信息。

_meta/fields.yml

- key: lsbeat
  title: lsbeat
  description:
  fields:
    - name: lsbeat
      type: long
      required: true
      description: >
        PLEASE UPDATE DOCUMENTATION

    #new fiels added lsbeat
    - name: modtime
      type: date
    - name: filename
      type: text
    - name: path
    - name: directory
      type: boolean
    - name: filesize
      type: long

我们在上面的除了添加新的字段以外,同时也把name字段修改为lsbeat。

并应用新的更新:

$ make update

编译并运行

现在我们可以构建并运行。 只需运行make命令,它将编译代码并构建lsbeat(在Windows上为lsbeat.exe)可运行的二进制文件。

make

我们可以看到新生产的lsbeat运行文件:

我们运行我们刚才生产的lsbeat:

我们到Kibana中去查看:

我们来查看所有的文件:

最后整个beat的源码可以在地址下载:

https://github.com/liu-xiao-guo/beats-lsbeat

更多阅读

你可参阅另外一篇文章“Beats:如何创建一个定制的Elastic Beat”。

参考:

【1】https://www.elastic.co/guide/en/beats/devguide/7.6/newbeat-generate.html