пятница, 29 июня 2018 г.

Splunk. Dashboard + HTML.


Приветствую, уважаемый читатель!

Функциональность дашбордов в Splunk от версии к версии становятся всё шире. Достаточно давно в них появилась возможность встраивать блоки HTML текста, и, честно говоря, считал эту возможность бесполезной J Однако, как оказалось её можно использовать для динамического вывода вспомогательной информации к событиям.  




Для вывода HTML-текста необходимо добавить в исходном коде дашборда (source) добавить тэг <html>. Имеется возможность присоединить к дашборду созданный html-файлик, пример ниже:

<panel>
      <html>
        <h1>HTML text on dashboard</h1>
      </html>
      <html src="html/$html$.html"/>
   </panel>

Файлы для присоединения могут размещаться в - /opt/splunk/etc/apps/search/appserver/static/html/ (для приложения search).

Задачу сформулируем следующую, получить какую-либо вспомогательную информацию к событию, при переключении между ними. Например, получать информацию об IP-адресе через whois.

1.                  Пишем простенький скрипт, который принимает в качестве параметра IP-адрес, получает данные из whois и создаём html-файл с результатом. Подключаем скрипт к Splunk через commands.conf:

#!/usr/bin/env python
import sys
import os

def main():
            ip = sys.argv[1]
            locate_p = "/opt/splunk/etc/apps/search/appserver/static/html/"
            f_name = locate_p + ip + ".html"
            command = 'whois %s | grep descr' % ip
            res = os.popen(command)
            to_file = res.read()

            file_wr = open(f_name,'w')
            file_wr.write('<h2>')
            file_wr.write(str(to_file))
            file_wr.write('</h2>')
            file_wr.close()

if __name__ == "__main__":
            main()


commands.conf (/opt/splunk/etc/apps/search/local/commands.conf)

[whois]
filename = whois_info.py


2.                  Создаём дашборд с одной таблицей, в которую выводим несколько записей из логов Apache. При переключении между событиями сохраняем ip-адрес в токен (ips).
Далее передаём этот токен в глобальный поименованный поиск GetWhois, который запускает скрипт.


    
Сохранение токена:
   <drilldown>
          <condition field="clientip">
            <set token="ips">$click.value2$</set>
          </condition>
        </drilldown>

Передача токена в скрипт:
<search id="GetWhois">
    <query>| script whois $ips$</query>
    <finalized>
      <set token="html">$ips$</set>
    </finalized>
  </search>


Наиболее интересна тут секция finalized, в который мы укажем, что после выполнения скрипт поместить значение токена $ips$ в новый токен $html$.

Зачем это сделано? Как только выполнится запрос и в директорию будет загружен файл с результатом, токен $html$ получает значение ip-адреса и передаётся в html-блок на дашборде - <html src="html/$html$.html"/>.

Таким образом, при переключении между событиями в html-блоке будет обновляться информация из whois.




Полный код дашборда ниже:

<form>
  <label>Apache_whois</label>
  <search id="GetWhois">
    <query>| script whois $ips$</query>
    <finalized>
      <set token="html">$ips$</set>
    </finalized>
  </search>
  <fieldset submitButton="false">
    <input type="time" token="field1">
      <label></label>
      <default>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </default>
    </input>
  </fieldset>
  <row>
    <panel>
      <table>
        <search>
          <query>sourcetype="access_combined" | dedup clientip | table clientip, uri, bytes, useragent</query>
          <earliest>$field1.earliest$</earliest>
          <latest>$field1.latest$</latest>
          <sampleRatio>1</sampleRatio>
        </search>
        <option name="count">20</option>
        <option name="dataOverlayMode">none</option>
        <option name="drilldown">cell</option>
        <option name="percentagesRow">false</option>
        <option name="refresh.display">progressbar</option>
        <option name="rowNumbers">false</option>
        <option name="totalsRow">false</option>
        <option name="wrap">true</option>
        <drilldown>
          <condition field="clientip">
            <set token="ips">$click.value2$</set>
          </condition>
        </drilldown>
      </table>
    </panel>
  </row>
  <row>
    <panel>
      <html>
        <h1>HTML text on dashboard</h1>
      </html>
      <html src="html/$html$.html"/>
    </panel>
  </row>
</form>

Всем удачного использования, может кому пригодится J

7 комментариев:

  1. Подскажите как получить отсутствие евентов по какому либо хосту? Заранее благодарю

    ОтветитьУдалить
    Ответы
    1. Дмитрий, приветствую!
      Не совсем понял задачу, нужно узнать в рамках какого-либо sourcetype от какого хоста не было событий?

      Вот таким запросом, можно получить список IP-адресов с указанием, когда от него было получено последнее событие:

      source="/var/log/apache2/access.log"
      | stats count,last(req_time) as last_time by clientip
      | table clientip,last_time,count

      Удалить
  2. Спасибо за ответ.
    я попробую описать задачу.
    Есть справочник в котором есть ВСЕ объекты и их ID. Также есть некий источник событий с ID объектов. И вот вопрос как вывести все объекты по которым НЕ поступили события за последние сутки?
    Заранее благодарю

    ОтветитьУдалить
  3. Если правильно понял задачу, то можно вот так (в качестве ID объекта у меня выступает IP-адрес):

    sourcetype=access_combined earliest=-d@d latest=@d
    | stats count by clientip

    Запрос выше вернёт IP-адреса всех подключавшихся в период с 22.07.2018 00:00 по 22.07.2018 23:59, т.е. события с данного IP (или в вашем случае, с данного ID) не индексировались сегодня (23.07.2018). Интервалами времени можно играться по своему усмотрению и отодвигать или сдвигать границы earliest и latest.

    Можно встроить данный запрос в любой другой запрос и таким способом, например, исключить события с таким ID из базового поиска:

    sourcetype=access_combined
    | search NOT [search sourcetype=access_combined earliest=-d@d latest=@d | stats count by clientip | table clientip]
    | stats count by clientip

    или наоборот искать события только с такими ID

    sourcetype=access_combined
    | search [search sourcetype=access_combined earliest=-d@d latest=@d | stats count by clientip | table clientip]
    | stats count by clientip

    ОтветитьУдалить
    Ответы
    1. У меня получился вот такой запрос. Он в принципе рабочий но уж очень сильно грузит камень. Возможно ли как то его оптимизировать? эвентов порядка 5млн

      index="atd2_index"| dedup NAME_FULL_MAG|stats count by NAME_FULL_MAG
      | append
      [search |inputlookup append=t MAG.csv | fields + NAME_FULL_MAG |stats count by NAME_FULL_MAG ]
      | stats count by NAME_FULL_MAG
      | eval badMAG=if(count=1,"No Data","OK")
      | search badMAG="No Data"
      | table NAME_FULL_MAG badMAG

      Удалить
    2. Дмитрий, можно попробовать следующее:
      1. Убрать dedup NAME_FULL_MAG, т.к. следующий оператор stats отрабатывает по этому полю, и автоматом уберет дубли.
      2. Inputlookup можно заменить на inputcsv и через table перечислить список полей, который нужен в запросе.
      3. Поля, которые необходимо вернуть из подзапроса (NAME_FULL_MAG, count), лучше в явном виде перечислить в операторе table.
      4. Последний search можно заменить на оператор where (where badMAG="No Data")

      Можно кстати посмотреть где конкретно долго выполняется запрос в меню Job - InspectJob (находится около селектора времени).

      Удалить
    3. Попробовал использовать Ваш запрос, все равно на 5 млн евентов запрос выполняется порядка 14 секунд - это чуть лучше чем у меня. самое большое время у command.search

      Удалить