elk处理基础数据_使用ELK堆栈和Ruby构建数据处理管道

elk处理基础数据

应用程序日志通常包含有价值的数据。 我们如何及时,经济地提取这些数据? 作为一个示例应用程序,我们将讨论一个多租户系统,在该系统中我们通过子域托管多个站点。 日志文件中的URL包含路径(/api, /search, etc)和参数(?foo=bar)

如果我们不想使用ELK ,则可以使用API​​构建不同的数据处理管道来接收消息,将消息放入队列中,然后由工作人员处理数据。 我在本博文中概述了这种方法,并将其与ELK进行了比较。

在我们的ELK解决方案中,我们将按客户和日期将数据划分为单独的Elasticsearch索引,并生成报告以显示访问了哪些URL路径。 在处理时间序列数据时,这是一种常见的模式。

为简单起见,我们将使用负载平衡器日志,该日志包含与Web服务器日志相同的信息,但它们是集中式的。 我们将配置我们的AWS负载平衡器,每隔五分钟将日志发布到S3存储桶。 从那里,Logstash将提取日志并将其处理到Elasticsearch中。

这是ELB日志文件中的示例行:


   
   
2018-05-10T18:26:13.276Z ELB_NAME 73.157.179.139:60708 10.0.1.42:80 0.000021
0.000303 0.000014 200 200 0 68 "GET https://site1.mysystem.com/api?foo=bar...
HTTP/1.1" "Mozilla/5.0 (Linux; Android 7.0; SM-T580 Build/NRD90M; wv)
AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Safari/537.36 [Pinterest/Android]"
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

Logstash配置

我们将从Logstash S3输入插件开始:


   
   
# /etc/logstash/conf.d/s3_elastic.conf
input {
  s3 {
    aws_credentials_file => "./aws_credentials_file.yml"
    bucket               => "my-elb-logs"
    prefix               => "subfolder/path/here/"
    sincedb_path         => "./data/plugins/inputs/s3/sincedb_s3_elastic"    
  }
}

Logstash使用sincedb文件来跟踪它在日志文件处理中的位置。 如果我们停止Logstash并在以后启动它,它将处理该停机期间累积的日志。

然后,我们配置Elasticsearch输出插件。 stdout可用于调试。 我们将在本文后面讨论[@metadata][index]


   
   
# /etc/logstash/conf.d/s3_elastic.conf
output {
  stdout { codec => rubydebug { metadata => true } }
  elasticsearch {
    hosts     => [127.0.0.1]
    user      => "elastic"
    password  => "password-here"
    index     => "%{[@metadata][index]}"
  }
}

为了进行过滤,我们将从Grok开始,然后删除不必要的字段:


   
   
# /etc/logstash/conf.d/s3_elastic.conf
filter {
  grok  {    
     match        => { "message" => "%{ELB_ACCESS_LOG}"}
     remove_field => [ "elb", "backendip", "backendport", ...]
  }
}

Logstash为我们提供了可靠的Grok模式,可将每个日志文件行解析为一个Event对象。 现在我们的数据如下所示:


   
   
{
       "request" => "http://site1.mysystem.com/api?foo=bar",
          "path" => "/api",
    "@timestamp" => 2018-05-10T18:26:13.276Z,
      "response" => 200,
      "clientip" => "73.157.179.139",
        "params" => "?foo=bar",
        "message" => "...",
        ...
}

Ruby代码

我们需要实施业务逻辑来验证和转换我们的数据。 鉴于此用例的简单要求,我们可以不用Ruby来完成它,但是它为我们提供了更多的灵活性和控制力。 我们需要提取URL主机,它将用作索引名称的一部分。 我们还想从URL中获取foo参数。 我们可以从内联Ruby代码开始:


   
   
# /etc/logstash/conf.d/s3_elastic.conf
filter {
  ruby {
    code =>   "
              require 'uri'
              uri = URI(event.get('request'))
              event.set('host', uri.host)
              foo_value = CGI::parse(event.get('params'))['foo'].first
              event.set('foo', foo_value)              
              "

  }

现在,我们的Event对象包含单独的hostfoo字段:


   
   
{
       "request" => "http://site1.mysystem.com/api?foo=bar",
          "path" => "/api",
          ...
          "host" => "site1.mysystem.com",
           "foo" => "bar",
}

将代码放置在配置文件中不是可扩展的方法,并且将很难测试。 幸运的是,最新版本的Ruby过滤器插件支持从.conf文件中引用单独的Ruby脚本,并且我们可以使用自动化测试来测试代码。 我们通过指定Ruby脚本的路径来修改.conf文件:


   
   
# /etc/logstash/conf.d/s3_elastic.conf file
filter {
  ruby {
    path => "/etc/logstash/ruby/s3_elastic.rb"
    # script_params => {  }
  }
}

一个区别是,现在Ruby必须从外部脚本文件返回Event对象的数组。


   
   
# /etc/logstash/ruby/s3_elastic.rb
require 'uri'
# the value of `params` is the value of the hash passed to `script_params`
# in the logstash configuration
def register ( params )
end
# the filter method receives an event and must return a list of events.
# Dropping an event means not including it in the return array,
# while creating new ones only requires you to add a new instance of
# LogStash::Event to the returned array
def filter ( event )
  uri = URI ( event. get ( 'request' ) )
  event. set ( 'host' , uri. host )
  foo_value = CGI ::parse ( event. get ( 'params' ) ) [ 'foo' ] . first
  event. set ( 'foo' , foo_value )
  return [ event ]
end
test 'valid test' do
  parameters { {   } }
  in_event do { 'request' => 'http://site1.mysystem.com/api?foo=bar' } end
  expect ( 'params' ) do | events |
    events. first . get ( 'host' ) == 'site1.mysystem.com'
    events. first . get ( 'foo' ) == 'bar'
  end
end

我们可以通过指定-t标志来运行自动化测试,如下所示: logstash -f /etc/logstash/conf/s3_elastic.conf -t


   
   
[ logstash. filters . ruby . script ] Test run complete
{ :script_path => "/etc/logstash/ruby/s3_elastic.rb" ,
  :results => { :passed => 1 , :failed => 0 , :errored => 0 } }
Configuration OK
[ logstash. runner ] Using config. test_and_exit mode. Config Validation Result: OK.
Exiting Logstash

我们无法确定当前日期,因此需要确定在索引名称中使用哪个日期。 为此,我们将使用timestamp字段( 2018-05-10T18:26:13.276Z )。 我们还可以将用于确定索引的业务逻辑提取到单独的方法中。 万一有错误,我们将默认为今天的日期:


   
   
# /etc/logstash/ruby/s3_elastic.rb
def filter ( event )
  ...
  event . set ( "[@metadata][index]" , get_index ( event ) )
  return [ event ]
end
def get_index event
  host = event. get ( 'host' )
  date = event. get ( 'timestamp' ) . split ( 'T' ) . first
  "#{host}-#{date}"
rescue
  "#{host}-#{Time.now.strftime(" % Y. % m. % d ")}"
end
...

我们正在使用event.set创建[@metadata][index]字段。 它不会与文档一起保存,但可以在我们的.conf文件中用于指定索引。 这种方法使我们能够在同一Ruby方法中保持将主机和日期结合在一起的逻辑。

集合体

现在,我们可以使用Kibana(甚至curl )来运行聚合。 我们可以查询所有索引,以了解访问了哪些URL路径以及访问频率。


   
   
POST /*/_search?size=0
{
  "aggs" : {
    "path_count" : {
      "terms" : {
        "field" : "path.keyword"
      }
    }
  }
}

数据将像这样返回:


   
   
{
  "took": 709,
  "timed_out": false,
  "_shards": {
    ...
  },
  "hits": {
    ...
  },
  "aggregations": {
    "path_count": {
      ...
      "buckets": [
        {
          "key": "/api",
          "doc_count": 913281
        },
        {
          "key": "/search",
          "doc_count": 742813
        },
        ...
      ]
    }
  }
}

如果要查询特定客户或日期的数据,则需要在POST /*2018.05.10/_search?size=0其指定为索引模式。 Kibana还允许我们基于这些聚合来构建可视化和仪表板。

链接

翻译自: https://opensource.com/article/18/5/building-data-pipeline-elk-stack-ruby

elk处理基础数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值