# Помогите разобраться с grok filter

**URL:** <https://discuss.elastic.co/t/grok-filter/121988>\
**Category:** Вопросы на русском языке\
**Created:** [March 1, 2018, 6:48am UTC](https://discuss.elastic.co/t/grok-filter/121988 "2018-03-01T06:48:03Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 1, 2018, 6:48am UTC](https://discuss.elastic.co/t/grok-filter/121988/1 "2018-03-01T06:48:03Z")

</div>

Здравствуйте,

Вопрос у меня такой. Использую http\_poller input plugin для Logstash. По API выдергиваю данные в формате json из UserVoice. Там довольно большой объем данных приходит, все это улетает в ElasticSearch. В принципе, с этим всем работать можно, но хотелось бы весь этот поток как-то отфильтровать так, чтобы в ES шли только нужные мне поля. Выглядит эти данные примерно так:

```
<suggestion>
       <url>http://plesk.uservoice.com/forums/184549-feature-suggestions/suggestions/33450685-easy-change-the-main-website-on-a-subscription</url>
       <path>/forums/184549-feature-suggestions/suggestions/33450685-easy-change-the-main-website-on-a-subscription</path>
       <id type="integer">33450685</id>
       <state>published</state>
       <title>Easy change the main website on a subscription</title>
       <text>Currently the main domain must be renamed to change the main domain. This is cumbersome, especially if e-mail addresses are still assigned to this domain, because they will be also renamed. It would be more convenient if another already existing domain could be set as the main domain, e. g. by clicking on a button "Set as main domain". </text>
       <formatted_text>&lt;div class="typeset"&gt;&lt;p&gt;Currently the main domain must be renamed to change the main domain. This is cumbersome, especially if e-mail addresses are still assigned to this domain, because they will be also renamed. It would be more convenient if another already existing domain could be set as the main domain, e. g. by clicking on a button "Set as main domain". &lt;/p&gt;&lt;/div&gt;</formatted_text>
       <referrer>https://plesk.uservoice.com/forums/xxxxx</referrer>
       <vote_count type="integer">1</vote_count>
       <subscriber_count type="integer">1</subscriber_count>
       <comments_count type="integer">0</comments_count>
       <supporters_count type="integer">1</supporters_count>
       <merged_into_suggestion_id type="integer"/>
       <topic>
         <id type="integer">184549</id>
         <prompt>I suggest you ...</prompt>
         <example>Enter your idea... (in English)</example>
         <votes_allowed type="integer">20</votes_allowed>
         <suggestions_count type="integer">3909</suggestions_count>
         <open_suggestions_count type="integer">1898</open_suggestions_count>
         <closed type="boolean">false</closed>
         <anonymous_access type="boolean">false</anonymous_access>
         <unlimited_votes type="boolean">true</unlimited_votes>
         <classic_voting>false</classic_voting>
         <closed_at type="datetime"/>
         <created_at type="datetime">2012-11-20T07:23:47Z</created_at>
         <updated_at type="datetime">2018-01-25T05:54:41Z</updated_at>
         <forum>
           <id>184549</id>
           <name>Feature Suggestions</name>
         </forum>
       </topic>
       <category>
         <id type="integer">69397</id>
         <name>Plesk (general)</name>
       </category>
       <closed_at nil="true"/>
       <status nil="true"/>
       <creator>
       <id type="integer">185785938</id>
       <name>mai</name>
       <title></title>
       <url>http://plesk.uservoice.com/users/xxxxx</url>
       <avatar_url>https://secure.gravatar.com/xxxxx.png</avatar_url>
       <created_at type="datetime">2016-07-04T12:16:58Z</created_at>
       <updated_at type="datetime">2018-02-26T07:22:42Z</updated_at>
       </creator>
       <response nil="true"/>
       <attachments type="array">
       </attachments>
       <created_at type="datetime">2018-02-26T07:22:43Z</created_at>
       <updated_at type="datetime">2018-02-26T07:22:54Z</updated_at>
           </suggestion>

```

Хотелось бы понять, как отфильтровать с помощью grok filter этот поток так, чтобы выбирать из него только и какие-то еще нужные мне поля? Попробовал разными способами, что-то ничего у меня не получилось. Может быть подскажете какие-то примеры?  
Спасибо.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 2, 2018, 3:51am UTC](https://discuss.elastic.co/t/grok-filter/121988/2 "2018-03-02T03:51:30Z")

</div>

А почему вы хотите воспользоваться именно grok вместо [xml](https://www.elastic.co/guide/en/logstash/6.2/plugins-filters-xml.html#plugins-filters-xml-source)?

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 2, 2018, 4:05am UTC](https://discuss.elastic.co/t/grok-filter/121988/3 "2018-03-02T04:05:08Z")

</div>

Наверное потому, что почему-то думал, что задачу нужно выполнить именно с его помощью. Про xml не знал.

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 2, 2018, 4:10am UTC](https://discuss.elastic.co/t/grok-filter/121988/4 "2018-03-02T04:10:13Z")

</div>

То есть должно быть что-то вроде

```
filter {
  xml {
    source => "text"
    source => "supporters_count"
    source => "created_at"
  }
}

```

Верно?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 2, 2018, 4:18am UTC](https://discuss.elastic.co/t/grok-filter/121988/5 "2018-03-02T04:18:49Z")

</div>

Я думаю, что source должен быть только первый. Остальное - в xpath.

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 2, 2018, 4:37am UTC](https://discuss.elastic.co/t/grok-filter/121988/6 "2018-03-02T04:37:24Z")

</div>

Что-то ничего не изменилось. Все то же самое.

Может быть, нужно вместо

source =\> "text"

использовать

source =\> "suggestion.text"

?

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 2, 2018, 4:40am UTC](https://discuss.elastic.co/t/grok-filter/121988/7 "2018-03-02T04:40:58Z")

</div>

Нет и так не работает.  
Ни на что этот фильтр не влияет.  
Или я что-то неправильно понимаю...

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 2, 2018, 4:50pm UTC](https://discuss.elastic.co/t/grok-filter/121988/8 "2018-03-02T16:50:46Z")

</div>

`source` - это поле, в котором содержится XML. То есть `source => "text"` означает, что XML находиться в поле `text`. Если у вас этот XML - вся входящая запись, то должно быть `source => "message"`

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 2, 2018, 5:21pm UTC](https://discuss.elastic.co/t/grok-filter/121988/9 "2018-03-02T17:21:38Z")

</div>

Хорошо, но только как это решает мою первоначальную задачу? Мне из этого message нужно не все, а только определенные поля.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 2, 2018, 8:05pm UTC](https://discuss.elastic.co/t/grok-filter/121988/10 "2018-03-02T20:05:08Z")

</div>

```auto
filter {
  xml {
    source => "message"
    xpath => ["suggestion/supporters_count/text()", "supporters_count"]
    xpath => ["suggestion/created_at/text()", "created_at"]
    xpath => ["suggestion/text/text()", "text"]
    force_content => true
    force_array => false
    remove_field => ["message"]
    store_xml => false
  }
  mutate {
    convert => {
      "supporters_count" => "integer"
      "created_at" => "string"
      "text" => "string"
    }
    replace => {
      "supporters_count" => "%{[supporters_count][0]}"
      "created_at" => "%{[created_at][0]}"
      "text" => "%{[text][0]}"
    }
  }
}

```

для меня выводит

```auto
{
  "@timestamp": "2018-03-02T20:03:09.169Z",
  "@version": "1",
  "supporters_count": 1,
  "host": "my_laptop",
  "created_at": "2018-02-26T07:22:43Z",
  "text": "Currently the main domain must be renamed to change the main domain. This is cumbersome, especially if e-mail addresses are still assigned to this domain, because they will be also renamed. It would be more convenient if another already existing domain could be set as the main domain, e. g. by clicking on a button \"Set as main domain\". "
}

```

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 3, 2018, 3:34am UTC](https://discuss.elastic.co/t/grok-filter/121988/11 "2018-03-03T03:34:55Z")

</div>

Спасибо большое за пример, теперь легче будет разбираться 🙂  
Но он все равно не работает. В Kibana вижу, что весь массив попадает в поле suggestions а в created\_at вижу %{[created\_at][0]}. Тоже и для text - %{[text][0]}

Может это от того, что в input стоит codec =\> "json" ?

Скажите, а перевод в lowercase текста можно тоже делать в logstash или это уже забота ES? То же самое и про чистку текста от урлов и почтовых адресов.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 6, 2018, 4:48pm UTC](https://discuss.elastic.co/t/grok-filter/121988/12 "2018-03-06T16:48:28Z")

</div>

> [@pavuk](#):
>
> Может это от того, что в input стоит codec =\> "json" ?

Если у вас входящая запись в xml, то input codec должен быть `plain`. Нужно больше информации о том, как у вас записи поступают, что бы разобраться, что не работает. Я свой пример тестировал на XML в одной строке.

> [@pavuk](#):
>
> Скажите, а перевод в lowercase текста можно тоже делать в logstash или это уже забота ES? То же самое и про чистку текста от урлов и почтовых адресов.

Зависит от того, как вы этот почищенный текст будете использовать. Если только для поиска - то можно в Elasticsearch. Если для вывода - то лучше в logstash.

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 7, 2018, 5:48am UTC](https://discuss.elastic.co/t/grok-filter/121988/13 "2018-03-07T05:48:20Z")

</div>

> [@Igor\_Motov](#):
>
> Нужно больше информации о том, как у вас записи поступают, что бы разобраться, что не работает.

API запрос с выводом можно посмотреть вот тут [UserVoice API Request · GitHub](https://gist.github.com/anonymous/840c8699c4a95805887f0d6193a1d2cd)

> [@Igor\_Motov](#):
>
> Зависит от того, как вы этот почищенный текст будете использовать. Если только для поиска - то можно в Elasticsearch. Если для вывода - то лучше в logstash.

Хотелось бы, чтобы в ES текст попадал из Logstash уже в lowercase и очищенным.  
Спасибо.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 7, 2018, 4:13pm UTC](https://discuss.elastic.co/t/grok-filter/121988/14 "2018-03-07T16:13:13Z")

</div>

> [@pavuk](#):
>
> API запрос с выводом можно посмотреть вот тут

А как Вы с этим API работаете?

> [@pavuk](#):
>
> Хотелось бы, чтобы в ES текст попадал из Logstash уже в lowercase и очищенным.

В этом случае имеет смысл пропустить все через [mutate](https://www.elastic.co/guide/en/logstash/6.2/plugins-filters-mutate.html#plugins-filters-mutate-lowercase) фильтр в logstash.

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 7, 2018, 4:45pm UTC](https://discuss.elastic.co/t/grok-filter/121988/15 "2018-03-07T16:45:09Z")

</div>

> [@Igor\_Motov](#):
>
> А как Вы с этим API работаете?

В каком смысле как?  
Пока лишь хочу выбрать из вывода нужные поля.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 7, 2018, 4:58pm UTC](https://discuss.elastic.co/t/grok-filter/121988/16 "2018-03-07T16:58:20Z")

</div>

Я имел в виду настройки `http_poller`.

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 8, 2018, 2:49am UTC](https://discuss.elastic.co/t/grok-filter/121988/17 "2018-03-08T02:49:52Z")

</div>

> [@Igor\_Motov](#):
>
> Я имел в виду настройки http\_poller.

Там все просто:

```
input {
             http_poller {
               urls => {
                  test => {
                   # Supports all options supported by ruby's Manticore HTTP client
                   method => get
                   url => "https://plesk.uservoice.com/api/v1/forums/184549/suggestions.json?sort=newest"
                   headers => {
                      Accept => "application/json"
                      Authorization => "Bearer xxxxxxxxxx"
                   }

                 }
               }
               request_timeout => 60
               # Supports "cron", "every", "at" and "in" schedules by rufus scheduler
               # schedule => { cron => "* * * * * UTC"}
               schedule => { every => "1h"}
               codec => "json"
             }
           }

filter {
  xml {
    ......

 output {
           stdout {
           codec => rubydebug
# elasticsearch {
# hosts => ["http://xxxxxxxx.com:9200/"]
# user => elastic
# password => xxxxxx
## user => logstash_internal
## password => xxxxx
# index => "uservoice"
 }
             }

```

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 8, 2018, 3:53pm UTC](https://discuss.elastic.co/t/grok-filter/121988/18 "2018-03-08T15:53:47Z")

</div>

Я думаю, что `codec => "json"` здесь мешает. К тому же у вас может быть несколько записей в одном ответе сервера, поэтому их, скорее всего надо будет в два этапа разбивать - сначала xml филтром и split фильтром на записи, а потом еще одним xml фильтром на поля

---

<div class="post-metadata">

**Author:** ![pavuk](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/pavuk/32/28914_2.png) [@pavuk](https://discuss.elastic.co/u/pavuk)\
**Post date:** [March 12, 2018, 7:16am UTC](https://discuss.elastic.co/t/grok-filter/121988/19 "2018-03-12T07:16:05Z")

</div>

В общем, ничего не получается. Поставил codec =\> "plain"  
Сейчас конфиг выглядит как:

```
filter {
  xml {
    source => "message"
    xpath => ["response/suggestion/supporters_count/text()", "supporters_count"]
    xpath => ["response/suggestion/created_at/text()", "created_at"]
    xpath => ["response/suggestion/text/text()", "text"]
    force_content => true
    force_array => false
    remove_field => ["message"]
    store_xml => false
  }
  mutate {
    convert => {
      "supporters_count" => "integer"
      "created_at" => "string"
      "text" => "string"
    }
    replace => {
      "supporters_count" => "%{[supporters_count][0]}"
      "created_at" => "%{[created_at][0]}"
      "text" => "%{[text][0]}"
    }
  }
}

```

В результате, в Кибане вижу что-то неудобоваримое - [https://screenshots.firefox.com/1AKSZPP6YiozCbWQ/talkkib.plesk.com](https://screenshots.firefox.com/1AKSZPP6YiozCbWQ/talkkib.plesk.com)

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [March 12, 2018, 2:05pm UTC](https://discuss.elastic.co/t/grok-filter/121988/20 "2018-03-12T14:05:22Z")

</div>

Вы полностью проигнорировали мой совет в предыдущем посте использовать 2 xml фильтра 😕, и пути у вас в xml не правильные, поэтому у вас xml фильтр просто не отрабатывает и все остается в поле message.

Когда я работаю с конфигурацией logstash я обычно не пишу огромную конфигурацию и потом смотрю на результат в кибане. Я отлаживаю маленькими кусочками заменив output на stdout и смотря на вход и выход для каждого фильтра.

[Next page](https://discuss.elastic.co/t/grok-filter/121988.md?page=2)
