Анализ XML-данных из Filebeat с помощью Logstash

Я использую Filebeat для анализа файлов XML в Windows и отправляю их в Logstash для фильтрации и отправки в Elasticsearch.

Задание Filebeat сработало отлично, и я получаю блоки XML в Logstash, но похоже, что я неправильно сконфигурировал фильтр Logstash для разбора блоков XML на отдельные поля и инкапсуляции этих полей в тип Elasticsearch.

Вот мой образец данных XML:

<H_Ticket>
 <IDH_Ticket>26</IDH_Ticket>
 <CodeBus>186</CodeBus>
 <CodeCh>5531</CodeCh>
 <CodeConv>5531</CodeConv>
 <Codeligne>12</Codeligne>
 <Date>20150915</Date>
 <Heur>1110</Heur>
 <NomFR1>SOUK AHAD</NomFR1>
 <NomFR2>KANTAOUI </NomFR2>
 <Prix>0.66</Prix>
 <IDTicket>26</IDTicket>
 <CodeRoute>107</CodeRoute>
 <origine>01</origine>
 <Distination>06</Distination>
 <Num>6</Num>
 <Ligne>107</Ligne>
 <requisition> </requisition>
 <voyage>0</voyage>
 <faveur> </faveur>
 </H_Ticket>
<H_Ticket>
 <IDH_Ticket>26</IDH_Ticket>
 <CodeBus>186</CodeBus>
 <CodeCh>5531</CodeCh>
 <CodeConv>5531</CodeConv>
 <Codeligne>12</Codeligne>
 <Date>20150915</Date>
 <Heur>1110</Heur>
 <NomFR1>SOUK AHAD</NomFR1>
 <NomFR2>KANTAOUI </NomFR2>
 <Prix>0.66</Prix>
 <IDTicket>26</IDTicket>
 <CodeRoute>107</CodeRoute>
 <origine>01</origine>
 <Distination>06</Distination>
 <Num>6</Num>
 <Ligne>107</Ligne>
 <requisition> </requisition>
 <voyage>0</voyage>
 <faveur> </faveur>
 </H_Ticket>>     <H_Ticket>
 <IDH_Ticket>26</IDH_Ticket>
 <CodeBus>186</CodeBus>
 <CodeCh>5531</CodeCh>
 <CodeConv>5531</CodeConv>
 <Codeligne>12</Codeligne>
 <Date>20150915</Date>
 <Heur>1110</Heur>
 <NomFR1>SOUK AHAD</NomFR1>
 <NomFR2>KANTAOUI </NomFR2>
 <Prix>0.66</Prix>
 <IDTicket>26</IDTicket>
 <CodeRoute>107</CodeRoute>
 <origine>01</origine>
 <Distination>06</Distination>
 <Num>6</Num>
 <Ligne>107</Ligne>
 <requisition> </requisition>
 <voyage>0</voyage>
 <faveur> </faveur>
 </H_Ticket>

А вот и мой файл конфигурации logstash:

input {  
    beats {
    port => 5044
  }
}
filter 
{
    xml 
    {
        source => "ticket"
        xpath => 
        [
            "/ticket/IDH_Ticket/text()", "ticketId",
            "/ticket/CodeBus/text()", "codeBus",
            "/ticket/CodeCh/text()", "codeCh",
            "/ticket/CodeConv/text()", "codeConv",
            "/ticket/Codeligne/text()", "codeLigne",
            "/ticket/Date/text()", "date",
            "/ticket/Heur/text()", "heure",
            "/ticket/NomFR1/text()", "nomFR1",
            "/ticket/NomAR1/text()", "nomAR1",
            "/ticket/NomFR2/text()", "nomFR2",
            "/ticket/NomAR2/text()", "nomAR2",
            "/ticket/Prix/text()", "prix",
            "/ticket/IDTicket/text()", "idTicket",
            "/ticket/CodeRoute/text()", "codeRoute",
            "/ticket/origine/text()", "origine",
            "/ticket/Distination/text()", "destination",
            "/ticket/Num/text()", "num",
            "/ticket/Ligne/text()", "ligne",
            "/ticket/requisition/text()", "requisition",
            "/ticket/voyage/text()", "voyage",
            "/ticket/faveur/text()", "faveur"
        ]
        store_xml => true
        target => "doc"
    }
}

output 
{
    elasticsearch 
    { 
        hosts => "localhost"
        index => "buses"
        document_type => "ticket"
    }
    file {
    path => "C:\busesdata\logstash.log"
}
stdout { codec =>rubydebug}
}

Конфигурация Filebeat:

filebeat:
  # List of prospectors to fetch data.
  prospectors:
      paths:
        - C:\busesdata\*.xml
      input_type: log
      document_type: ticket
      scan_frequency: 10s
      multiline:
        pattern: '<H_Ticket'
        negate: true
        match: after
output:
  ### Logstash as output
  logstash:
    hosts: ["localhost:5044"]
    index: filebeat

А вот и часть стандартного вывода и вывода файла:

PS C:\logstash-2.3.3\bin> .\logstash -f .\logstash_temp.conf
io/console not supported; tty will not be manipulated
Settings: Default pipeline workers: 4
Pipeline main started

{
       "message" => "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n<?xml-stylesheet href=\"ticket.xsl\" type=\"text/xsl\"?>\n<HF_DOCUMENT>",
      "@version" => "1",
    "@timestamp" => "2016-07-03T12:13:28.892Z",
        "source" => "C:\\busesdata\\ticket2.xml",
          "type" => "ticket",
    "input_type" => "log",
        "fields" => nil,
          "beat" => {
        "hostname" => "hp-pavillion-g6",
            "name" => "hp-pavillion-g6"
    },
        "offset" => 0,
         "count" => 1,
          "host" => "hp-pavillion-g6",
          "tags" => [
        [0] "beats_input_codec_plain_applied"
    ]
}
{
       "message" => "\t<H_Ticket>\r\n\t\t<IDH_Ticket>1</IDH_Ticket>\r\n\t\t<CodeBus>186</CodeBus>\r\n\t\t<CodeCh>5531</CodeCh>\r\n\t\t<CodeConv>5531</CodeConv>\r\n\t\t<Codeligne>12</Codeligne>\r\n\t\t<Date>20150903</Date>\r\n\t\t<Heur>1101</Heur>\r\n\t\t<NomFR1>SOUK AHAD</NomFR1>\r\n\t\t<NomAR1>??? ?????</NomAR1>\r\n\t\t<NomFR2>SOVIVA </NomFR2>\r\n\t\t<NomAR2>??????</NomAR2>\r\n\t\t<Prix>0.66</Prix>\r\n\t\t<IDTicket>1</IDTicket>\r\n\t\t<CodeRoute>107</CodeRoute>\r\n\t\t<origine>01</origine>\r\n\t\t<Distination>07</Distination>\r\n\t\t<Num>3</Num>\r\n\t\t<Ligne>107</Ligne>\r\n\t\t<requisition> </requisition>\r\n\t\t<voyage>0</voyage>\r\n\t\t<faveur> </faveur>\r\n\t</H_Ticket>",
      "@version" => "1",
    "@timestamp" => "2016-07-03T12:13:28.892Z",
    "input_type" => "log",
        "source" => "C:\\busesdata\\ticket2.xml",
        "offset" => 125,
          "type" => "ticket",
         "count" => 1,
        "fields" => nil,
          "beat" => {
        "hostname" => "hp-pavillion-g6",
            "name" => "hp-pavillion-g6"
    },
          "host" => "hp-pavillion-g6",
          "tags" => [
        [0] "beats_input_codec_plain_applied"
    ]
}

person Fathi Jemli    schedule 01.07.2016    source источник
comment
Можете ли вы вставить вывод logstash, включив stdout { codec =>rubydebug}?   -  person Arpit Aggarwal    schedule 03.07.2016
comment
Я думал, что это вопрос сопоставления, после ручной настройки сопоставления типа в ES и повторной попытки Logstash не отправил никаких данных в ES ... Я почти уверен, что это проблема с фильтром: /   -  person Fathi Jemli    schedule 03.07.2016


Ответы (2)


Фильтр xml не будет работать, поскольку исходная конфигурация указывает на несуществующее поле.
В вашем документе нет поля ticket:

{
    "message" => "\t<H_Ticket>\r\n\t\t<IDH_Ticket>1</IDH_Ticket>\r\n\t\t<CodeBus>186</CodeBus>\r\n\t\t<CodeCh>5531</CodeCh>\r\n\t\t<CodeConv>5531</CodeConv>\r\n\t\t<Codeligne>12</Codeligne>\r\n\t\t<Date>20150903</Date>\r\n\t\t<Heur>1101</Heur>\r\n\t\t<NomFR1>SOUK AHAD</NomFR1>\r\n\t\t<NomAR1>??? ?????</NomAR1>\r\n\t\t<NomFR2>SOVIVA </NomFR2>\r\n\t\t<NomAR2>??????</NomAR2>\r\n\t\t<Prix>0.66</Prix>\r\n\t\t<IDTicket>1</IDTicket>\r\n\t\t<CodeRoute>107</CodeRoute>\r\n\t\t<origine>01</origine>\r\n\t\t<Distination>07</Distination>\r\n\t\t<Num>3</Num>\r\n\t\t<Ligne>107</Ligne>\r\n\t\t<requisition> </requisition>\r\n\t\t<voyage>0</voyage>\r\n\t\t<faveur> </faveur>\r\n\t</H_Ticket>",
    "@version" => "1",
    "@timestamp" => "2016-07-03T12:13:28.892Z",
    "input_type" => "log",
    "source" => "C:\\busesdata\\ticket2.xml",
    "offset" => 125,
    "type" => "ticket",
    "count" => 1,
    "fields" => nil,
    "beat" => {
        "hostname" => "hp-pavillion-g6",
        "name" => "hp-pavillion-g6"
    },
    "host" => "hp-pavillion-g6",
    "tags" => [
        [0] "beats_input_codec_plain_applied"
    ]
}

Вам следует изменить фильтр xml на:

 xml {
        source => "message"
        ...
 }
person baudsp    schedule 04.07.2016
comment
Спасибо большое, все работает! но у меня все еще есть 2 проблемы: во-первых, содержимое полей представляет собой массив вроде этого: ticketId: [28], а во-вторых, как я могу применить сопоставление, чтобы указать каждый тип и формат поля, как я сделал в ES: PUT / transtu {сопоставления: {ticket: {dynamic: strict, properties: {ticketId: {type: integer}, codeBus: {type: integer}, date: {type: date, format: basic_date} и т. д. - person Fathi Jemli; 04.07.2016
comment
Для проблемы с массивом вам придется задать другой вопрос. Сопоставление: Elasticsearch автоматически создает сопоставление при вставке данных в индекс в соответствии с типом данных. Поэтому, если ваши данные в logstash имеют правильный тип, сопоставление будет правильным. Вам нужно будет выполнить преобразование в своем фильтре logstash (cf stackoverflow.com/questions/38006656/ для преобразования строки в int). Вы также можете использовать шаблон индекса в Elasticsearch, но данные все равно должны быть правильного типа. - person baudsp; 05.07.2016
comment
Я исправил это с помощью фильтра изменения - person Fathi Jemli; 05.07.2016

Можете ли вы попробовать отредактировать конфигурацию xpath в filter, как показано ниже:

filter 
{
    xml 
    {
        source => "ticket"
        xpath => 
        [
            "/IDH_Ticket/text()", "ticketId",
            "/CodeBus/text()", "codeBus",
            "/CodeCh/text()", "codeCh",
            "/CodeConv/text()", "codeConv",
            "/Codeligne/text()", "codeLigne",
            "/Date/text()", "date",
            "/Heur/text()", "heure",
            "/NomFR1/text()", "nomFR1",
            "/NomAR1/text()", "nomAR1",
            "/NomFR2/text()", "nomFR2",
            "/NomAR2/text()", "nomAR2",
            "/Prix/text()", "prix",
            "/IDTicket/text()", "idTicket",
            "/CodeRoute/text()", "codeRoute",
            "/origine/text()", "origine",
            "/Distination/text()", "destination",
            "/Num/text()", "num",
            "/Ligne/text()", "ligne",
            "/requisition/text()", "requisition",
            "/voyage/text()", "voyage",
            "/faveur/text()", "faveur"
        ]
        store_xml => true
        target => "doc"
    }
}
person Arpit Aggarwal    schedule 03.07.2016
comment
Это не сработало, у меня был такой же результат, я думаю, что это может быть достигнуто с помощью шаблонов Grok, вы знаете, как я могу использовать шаблоны Grok в этом случае? - person Fathi Jemli; 03.07.2016