elk笔记21--将DSL查询转为kibana短链接

elk笔记21--将DSL查询转为kibana短链接

1 简介

较新版本的 kibana 前端都有一个 Share -> Short URL 的功能,用起来非常方便。因此想着能否将该功能用代码自动生成,将其集成到告警通知中,让用户收到告警通知的时候可以通过短链接快速定位到错误原因。

查询文档发现官方提供 Shorten URL API 实现锻炼功能,该功能处于实验阶段,没有详细的参数介绍,因此需要自己结合kibana 的url 和查询的字段分析其参数生成模式。笔者多次测试后, 结合shorten_url 和 query 语句实现该功能,分享在这里供有需要的小伙伴们学习。

2 功能实现

kibana 官方文档 Shorten URL API 的介绍相当简洁,提供了一个很简单的案例,然而并没有介绍 url 中的参数,因此还需要自己通过开发工具一步步测试验证。

笔者在完成这个demo的时候,也是结合kibana URL、share-> PERMALINK-> Short URL-> Chrome 开发工具, 多次对比才找到处一种比较可靠的方式。

主要过程:

  1. 根据用户的index pattern 找到其index pattern id,对应请求方法可以在刷新index pattern 的时候通过 Chrome 找到kibana 查询函数;
  2. 用户输入query请求,将请求封装为符合kibana查询需求的url, 然后通过 /api/shorten_url 生成一个urlId,将urlId 拼装为一个kibana 的短链接即可;
  3. 用户点击短链接的时候,kibana会自动将其解析为具体的查询条件,通过该条件查询数据并显示给用户。

以下为源码实现和测试过程

2.1 源码

源码结构如下:
alarm_shorten_url$ tree -L 2
.
├── generate_url.py
├── readme.md
└── rison
    ├── constants.py
    ├── decoder.py
    ├── encoder.py
    ├── __init__.py
    └── utils.py

1)从 [github pifantastic/python-rison](https://github.com/pifantastic/python-rison) 下载rison库, 注意 py3 没有basestring类型,因此需要修改 basestringstr,否则会报错;
按需拷贝python-rison 的 rison 目录即可,此处就不再贴一长串代码了;

2)按需获取 index pattern id, 然后组装kibana url 中的参数

vim generate_url.py 
#!/usr/bin/pytnon3
# -*- coding:utf-8 -*-

import sys
import requests
from base64 import b64encode
sys.path.append('./rison')
import rison


def get_base64_str(str_text):
    str_user_pwd = b64encode(str_text.encode('ascii'))
    return str_user_pwd.decode('ascii')


def generate_rison(bool_query):
    ret = rison.dumps(bool_query)
    return ret


class GenerateShortUrl:
    def __init__(self, base_url, user, pwd, time_from, time_to, index_pattern, bool_query):
        """

        :param base_url:
        :param user:
        :param pwd:
        :param time_from: 'now-15d'
        :param time_to: 'now'
        :param index_pattern: 'kibana_sample_data_logs'
        :param bool_query:
        注: 本函数只验证了一个完整类型的bool查询,
        因此bool_query_dict必须是 {"query": {"bool":{ ...must,must_not,should...}}}
        """
        self.base_url = base_url
        self.user = user
        self.pwd = pwd
        self.time_from = time_from
        self.time_to = time_to
        self.index_pattern = index_pattern
        self.bool_query = bool_query

    def get_index_pattern_id(self):
        url = f'{self.base_url}/api/saved_objects/_find?fields=title&fields=type&per_page=10000&type=index-pattern'
        headers = {'Authorization': 'Basic ' + get_base64_str(self.user + ':' + self.pwd)}
        ret = requests.get(url=url, headers=headers)
        for item in (ret.json())['saved_objects']:
            if item['attributes']['title'] == self.index_pattern:
                return item['id']
        return None

    def generate_shorten_url(self):
        url = f'{self.base_url}/api/shorten_url'
        index_pattern_id = self.get_index_pattern_id()
        bool_query_rison = generate_rison(self.bool_query)
        url_dict = {"url": f"/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),"
                           f"time:(from:{self.time_from},to:{self.time_to}))&_a=(columns:!(_source),"
                           f"filters:!({bool_query_rison}),index:'{index_pattern_id}',interval:auto,"
                           f"query:(language:lucene,query:''),sort:!())"}
        headers = {'Authorization': 'Basic ' + get_base64_str(self.user + ':' + self.pwd), 'kbn-xsrf': 'reporting'}
        ret = requests.post(url=url, json=url_dict, headers=headers)
        ret_dict = ret.json()
        return f'{self.base_url}/goto/' + ret_dict['urlId']


def test_case01():
    base_url = 'http://127.0.0.1:5601'
    user = "elastic"
    pwd = "elastic"
    index_pattern_name = 'kibana_sample_data_logs'
    bool_query = {
        "query": {
            "bool": {
                "must": [
                    {
                        "term": {
                            "tags.keyword": {
                                "value": "error"
                            }
                        }
                    },
                    {
                        "term": {
                            "response.keyword": {
                                "value": "200"
                            }
                        }
                    }
                ]
            }
        }
    }
    time_from = 'now-15d'
    time_to = 'now'
    gen_url_obj = GenerateShortUrl(base_url, user, pwd, time_from, time_to, index_pattern_name, bool_query)
    index_pattern_id = gen_url_obj.get_index_pattern_id()
    short_url = gen_url_obj.generate_shorten_url()
    print(f'{index_pattern_name} id= {index_pattern_id}\n{short_url}')


if __name__ == '__main__':
    test_case01()

2.2 测试

  1. 执行输出

  2. kibana 前端
    点击链接后会自动跳转到查询界面,可以在filter 处看到代码中的query语句,如下图所示:
    在这里插入图片描述
    在这里插入图片描述

3 注意事项

  1. 直接在kibana 前端添加filter后,它会在url 中多出一部分query 内容,而且被转化为url的格式,笔者实际测试的时候发现它和rison的内容是一致的,因此可以省略该部分,测试发现确实可以省略。
    如果想保持和kibana解析一致, 那么可以考虑使用 URL 转码 的方式对其进行转码,然后在生成短链接。
  2. 在本文测试中,为了简单高效暂时去掉了查询字段加亮选项,同时保持字段为_source, 有需要的话可以在 (columns:!(_source) 中添加自己需要的字段。
  3. 报错 Request must contain a kbn-xsrf header
    执行的时候出现如下错误:
     {"statusCode":400,"error":"Bad Request","message":"Request must contain a kbn-xsrf header."}
    
    解决方法:
    在headers 中添加 , ‘kbn-xsrf’: 'reporting’参数
    headers = {'Authorization': 'Basic ' + get_base64_str(USER + ':' + PWD), 'kbn-xsrf': 'reporting'}
    

4 说明

  1. 软件环境
    Ubuntu20.04 Desktop
    ES7.10
    python 3.8
  2. 参考文档
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昕光xg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值